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.adapter.osgi;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.collect.Maps;
13 import java.util.Dictionary;
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;
29 * A ServiceTracker which adapts a DOMService to a BindingService.
31 * @param <D> DOMService type
32 * @param <B> BindingService type
33 * @author Robert Varga
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> {
39 ComponentInstance<? extends B> component;
41 ComponentHolder(final B binding, final ComponentInstance<? extends B> component) {
42 this.binding = requireNonNull(binding);
43 this.component = requireNonNull(component);
47 private static final Logger LOG = LoggerFactory.getLogger(AdaptingTracker.class);
49 private final Function<D, B> bindingFactory;
50 private final @NonNull Class<B> bindingClass;
51 private final ComponentFactory<? extends B> componentFactory;
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);
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());
69 public ComponentHolder<B> addingService(final ServiceReference<D> reference) {
70 if (reference == null) {
71 LOG.debug("Null reference for {}, ignoring it", bindingClass.getName());
74 if (reference.getProperty(ServiceProperties.IGNORE_PROP) != null) {
75 LOG.debug("Ignoring reference {} due to {}", reference, ServiceProperties.IGNORE_PROP);
79 final D dom = context.getService(reference);
81 LOG.debug("Could not get {} service from {}, ignoring it", bindingClass.getName(), reference);
85 final B binding = bindingFactory.apply(dom);
86 return new ComponentHolder<>(binding, componentFactory.newInstance(referenceProperties(reference, binding)));
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));
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);
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);
114 props.put(key, value);
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);
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);
133 props.put(AbstractAdaptedService.DELEGATE, service);
134 return FrameworkUtil.asDictionary(props);