Do not use ListenerRegistration
[mdsal.git] / binding / mdsal-binding-dom-adapter / src / main / java / org / opendaylight / mdsal / binding / dom / adapter / osgi / AdaptingTracker.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.dom.adapter.osgi;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.collect.Maps;
13 import java.util.Dictionary;
14 import java.util.Map;
15 import java.util.function.Function;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.opendaylight.mdsal.binding.api.BindingService;
18 import org.opendaylight.mdsal.dom.api.DOMService;
19 import org.osgi.framework.BundleContext;
20 import org.osgi.framework.FrameworkUtil;
21 import org.osgi.framework.ServiceReference;
22 import org.osgi.service.component.ComponentFactory;
23 import org.osgi.service.component.ComponentInstance;
24 import org.osgi.util.tracker.ServiceTracker;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 /**
29  * A ServiceTracker which adapts a DOMService to a BindingService.
30  *
31  * @param <D> DOMService type
32  * @param <B> BindingService type
33  * @author Robert Varga
34  */
35 final class AdaptingTracker<D extends DOMService<?, ?>, B extends BindingService>
36         extends ServiceTracker<D, AdaptingTracker.ComponentHolder<B>> {
37     static final class ComponentHolder<B extends BindingService> {
38         final B binding;
39         ComponentInstance<? extends B> component;
40
41         ComponentHolder(final B binding, final ComponentInstance<? extends B> component) {
42             this.binding = requireNonNull(binding);
43             this.component = requireNonNull(component);
44         }
45     }
46
47     private static final Logger LOG = LoggerFactory.getLogger(AdaptingTracker.class);
48
49     private final Function<D, B> bindingFactory;
50     private final @NonNull Class<B> bindingClass;
51     private final ComponentFactory<? extends B> componentFactory;
52
53     AdaptingTracker(final BundleContext ctx, final Class<D> domClass, final Class<B> bindingClass,
54             final Function<D, B> bindingFactory, final ComponentFactory<? extends B> componentFactory) {
55         super(ctx, domClass, null);
56         this.bindingClass = requireNonNull(bindingClass);
57         this.bindingFactory = requireNonNull(bindingFactory);
58         this.componentFactory = requireNonNull(componentFactory);
59     }
60
61     @Override
62     public void open(final boolean trackAllServices) {
63         LOG.debug("Starting tracker for {}", bindingClass.getName());
64         super.open(trackAllServices);
65         LOG.debug("Tracker for {} started", bindingClass.getName());
66     }
67
68     @Override
69     public ComponentHolder<B> addingService(final ServiceReference<D> reference) {
70         if (reference == null) {
71             LOG.debug("Null reference for {}, ignoring it", bindingClass.getName());
72             return null;
73         }
74         if (reference.getProperty(ServiceProperties.IGNORE_PROP) != null) {
75             LOG.debug("Ignoring reference {} due to {}", reference, ServiceProperties.IGNORE_PROP);
76             return null;
77         }
78
79         final D dom = context.getService(reference);
80         if (dom == null) {
81             LOG.debug("Could not get {} service from {}, ignoring it", bindingClass.getName(), reference);
82             return null;
83         }
84
85         final B binding = bindingFactory.apply(dom);
86         return new ComponentHolder<>(binding, componentFactory.newInstance(referenceProperties(reference, binding)));
87     }
88
89     @Override
90     public void modifiedService(final ServiceReference<D> reference, final ComponentHolder<B> service) {
91         if (service != null && reference != null) {
92             service.component.dispose();
93             service.component = componentFactory.newInstance(referenceProperties(reference, service.binding));
94         }
95     }
96
97     @Override
98     public void removedService(final ServiceReference<D> reference, final ComponentHolder<B> service) {
99         if (service != null) {
100             context.ungetService(reference);
101             service.component.dispose();
102             LOG.debug("Unregistered service {}", service);
103         }
104     }
105
106     static Dictionary<String, Object> referenceProperties(final ServiceReference<?> ref, final BindingService service) {
107         final String[] keys = ref.getPropertyKeys();
108         final Map<String, Object> props = Maps.newHashMapWithExpectedSize(keys.length + 1);
109         for (String key : keys) {
110             // Ignore properties with our prefix: we are not exporting those
111             if (!key.startsWith(ServiceProperties.PREFIX)) {
112                 final Object value = ref.getProperty(key);
113                 if (value != null) {
114                     props.put(key, value);
115                 }
116             }
117         }
118
119         // Second phase: apply any our properties
120         for (String key : keys) {
121             if (key.startsWith(ServiceProperties.OVERRIDE_PREFIX)) {
122                 final Object value = ref.getProperty(key);
123                 if (value != null) {
124                     final String newKey = key.substring(ServiceProperties.OVERRIDE_PREFIX.length());
125                     if (!newKey.isEmpty()) {
126                         LOG.debug("Overriding property {}", newKey);
127                         props.put(newKey, value);
128                     }
129                 }
130             }
131         }
132
133         props.put(AbstractAdaptedService.DELEGATE, service);
134         return FrameworkUtil.asDictionary(props);
135     }
136 }