Remove yang-test
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / osgi / BeanToOsgiServiceManager.java
1 /*
2  * Copyright (c) 2013, 2017 Cisco Systems, Inc. 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.controller.config.manager.impl.osgi;
9
10 import com.google.common.base.Preconditions;
11 import java.util.Dictionary;
12 import java.util.HashSet;
13 import java.util.Hashtable;
14 import java.util.Map;
15 import java.util.Map.Entry;
16 import java.util.Set;
17 import javax.annotation.concurrent.GuardedBy;
18 import org.opendaylight.controller.config.api.ModuleIdentifier;
19 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
20 import org.osgi.framework.BundleContext;
21 import org.osgi.framework.ServiceRegistration;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 /**
26  * Registers instantiated beans as OSGi services and unregisters these services
27  * if beans are destroyed.
28  */
29 public class BeanToOsgiServiceManager {
30     private static final String SERVICE_NAME_OSGI_PROP = "name";
31
32     /**
33      * To be called for every created, reconfigured and recreated config bean. It is
34      * expected that before using this method OSGi service registry will be cleaned
35      * from previous registrations.
36      *
37      * @param instance instance
38      * @param moduleIdentifier module identifier
39      * @param bundleContext bundle context
40      * @param serviceNamesToAnnotations service names annotations
41      * @return OSGI registration
42      */
43     public OsgiRegistration registerToOsgi(final AutoCloseable instance, final ModuleIdentifier moduleIdentifier,
44             final BundleContext bundleContext,
45             final Map<ServiceInterfaceAnnotation, String> serviceNamesToAnnotations) {
46         return new OsgiRegistration(instance, moduleIdentifier, bundleContext, serviceNamesToAnnotations);
47     }
48
49     public static class OsgiRegistration implements AutoCloseable {
50         private static final Logger LOG = LoggerFactory.getLogger(OsgiRegistration.class);
51
52         @GuardedBy("this")
53         private AutoCloseable instance;
54         private final ModuleIdentifier moduleIdentifier;
55         @GuardedBy("this")
56         private final Set<ServiceRegistration<?>> serviceRegistrations;
57         @GuardedBy("this")
58         private final Map<ServiceInterfaceAnnotation, String> serviceNamesToAnnotations;
59
60         public OsgiRegistration(final AutoCloseable instance, final ModuleIdentifier moduleIdentifier,
61                 final BundleContext bundleContext,
62                 final Map<ServiceInterfaceAnnotation, String /* service ref name */> serviceNamesToAnnotations) {
63             this.instance = instance;
64             this.moduleIdentifier = moduleIdentifier;
65             this.serviceNamesToAnnotations = serviceNamesToAnnotations;
66             this.serviceRegistrations = registerToSR(instance, bundleContext, serviceNamesToAnnotations);
67         }
68
69         private static Set<ServiceRegistration<?>> registerToSR(final AutoCloseable instance,
70                 final BundleContext bundleContext,
71                 final Map<ServiceInterfaceAnnotation, String /* service ref name */> serviceNamesToAnnotations) {
72             Set<ServiceRegistration<?>> serviceRegistrations = new HashSet<>();
73             for (Entry<ServiceInterfaceAnnotation, String /* service ref name */> entry : serviceNamesToAnnotations
74                     .entrySet()) {
75                 ServiceInterfaceAnnotation annotation = entry.getKey();
76                 Class<?> requiredInterface = annotation.osgiRegistrationType();
77
78                 if (!annotation.registerToOsgi()) {
79                     LOG.debug("registerToOsgi for service interface {} is false - not registering", requiredInterface);
80                     continue;
81                 }
82
83                 Preconditions.checkState(requiredInterface.isInstance(instance),
84                         instance.getClass().getName() + " instance should implement " + requiredInterface.getName());
85                 Dictionary<String, String> propertiesForOsgi = createProps(entry.getValue());
86                 ServiceRegistration<?> serviceRegistration = bundleContext.registerService(requiredInterface.getName(),
87                         instance, propertiesForOsgi);
88                 serviceRegistrations.add(serviceRegistration);
89             }
90             return serviceRegistrations;
91         }
92
93         @Override
94         public synchronized void close() {
95             for (ServiceRegistration<?> serviceRegistration : serviceRegistrations) {
96                 try {
97                     serviceRegistration.unregister();
98                 } catch (final IllegalStateException e) {
99                     LOG.trace("Cannot unregister {}", serviceRegistration, e);
100                 }
101             }
102             serviceRegistrations.clear();
103         }
104
105         public synchronized void updateRegistrations(
106                 final Map<ServiceInterfaceAnnotation, String /* service ref name */> newAnnotationMapping,
107                 final BundleContext bundleContext, final AutoCloseable newInstance) {
108             boolean notEquals = !this.instance.equals(newInstance);
109             notEquals |= !newAnnotationMapping.equals(serviceNamesToAnnotations);
110             if (notEquals) {
111                 // FIXME: changing from old state to new state can be improved by computing the
112                 // diff
113                 LOG.debug("Detected change in service registrations for {}: old: {}, new: {}", moduleIdentifier,
114                         serviceNamesToAnnotations, newAnnotationMapping);
115                 close();
116                 this.instance = newInstance;
117                 Set<ServiceRegistration<?>> newRegs = registerToSR(instance, bundleContext, newAnnotationMapping);
118                 serviceRegistrations.clear();
119                 serviceRegistrations.addAll(newRegs);
120             }
121         }
122
123         private static Dictionary<String, String> createProps(final String serviceName) {
124             Hashtable<String, String> result = new Hashtable<>();
125             result.put(SERVICE_NAME_OSGI_PROP, serviceName);
126             return result;
127         }
128     }
129 }