3d93a9df7dee72bb450af215bd7dea97f24199a5
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / osgi / BeanToOsgiServiceManager.java
1 /*
2  * Copyright (c) 2013 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 static com.google.common.base.Preconditions.checkState;
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.
34      * It is expected that before using this method OSGi service registry will
35      * be cleaned from previous registrations.
36      */
37     public OsgiRegistration registerToOsgi(AutoCloseable instance, ModuleIdentifier moduleIdentifier,
38                                            BundleContext bundleContext,
39                                            Map<ServiceInterfaceAnnotation, String /* service ref name */> serviceNamesToAnnotations) {
40         return new OsgiRegistration(instance, moduleIdentifier, bundleContext, serviceNamesToAnnotations);
41     }
42
43     private static Dictionary<String, String> createProps(String serviceName) {
44         Hashtable<String, String> result = new Hashtable<>();
45         result.put(SERVICE_NAME_OSGI_PROP, serviceName);
46         return result;
47     }
48
49
50     public static class OsgiRegistration implements AutoCloseable {
51         private static final Logger LOG = LoggerFactory.getLogger(OsgiRegistration.class);
52
53         @GuardedBy("this")
54         private AutoCloseable instance;
55         private final ModuleIdentifier moduleIdentifier;
56         @GuardedBy("this")
57         private final Set<ServiceRegistration<?>> serviceRegistrations;
58         @GuardedBy("this")
59         private final Map<ServiceInterfaceAnnotation, String /* service ref name */> serviceNamesToAnnotations;
60
61         public OsgiRegistration(AutoCloseable instance, ModuleIdentifier moduleIdentifier,
62                                 BundleContext bundleContext,
63                                 Map<ServiceInterfaceAnnotation, String /* service ref name */> serviceNamesToAnnotations) {
64             this.instance = instance;
65             this.moduleIdentifier = moduleIdentifier;
66             this.serviceNamesToAnnotations = serviceNamesToAnnotations;
67             this.serviceRegistrations = registerToSR(instance, bundleContext, serviceNamesToAnnotations);
68         }
69
70         private static Set<ServiceRegistration<?>> registerToSR(AutoCloseable instance, BundleContext bundleContext,
71                                                                 Map<ServiceInterfaceAnnotation, String /* service ref name */> serviceNamesToAnnotations) {
72             Set<ServiceRegistration<?>> serviceRegistrations = new HashSet<>();
73             for (Entry<ServiceInterfaceAnnotation, String /* service ref name */> entry : serviceNamesToAnnotations.entrySet()) {
74                 ServiceInterfaceAnnotation annotation = entry.getKey();
75                 Class<?> requiredInterface = annotation.osgiRegistrationType();
76
77                 if(!annotation.registerToOsgi()) {
78                     LOG.debug("registerToOsgi for service interface {} is false - not registering", requiredInterface);
79                     continue;
80                 }
81
82                 checkState(requiredInterface.isInstance(instance), instance.getClass().getName() +
83                         " instance should implement " + requiredInterface.getName());
84                 Dictionary<String, String> propertiesForOsgi = createProps(entry.getValue());
85                 ServiceRegistration<?> serviceRegistration = bundleContext
86                         .registerService(requiredInterface.getName(), instance, propertiesForOsgi);
87                 serviceRegistrations.add(serviceRegistration);
88             }
89             return serviceRegistrations;
90         }
91
92         @Override
93         public synchronized void close() {
94             for (ServiceRegistration<?> serviceRegistration : serviceRegistrations) {
95                 try {
96                     serviceRegistration.unregister();
97                 } catch(IllegalStateException e) {
98                     LOG.trace("Cannot unregister {}", serviceRegistration, e);
99                 }
100             }
101             serviceRegistrations.clear();
102         }
103
104         public synchronized void updateRegistrations(Map<ServiceInterfaceAnnotation, String /* service ref name */> newAnnotationMapping,
105                                                      BundleContext bundleContext, AutoCloseable newInstance) {
106             boolean notEquals = this.instance != newInstance;
107             notEquals |= newAnnotationMapping.equals(serviceNamesToAnnotations) == false;
108             if (notEquals) {
109                 // FIXME: changing from old state to new state can be improved by computing the diff
110                 LOG.debug("Detected change in service registrations for {}: old: {}, new: {}", moduleIdentifier,
111                         serviceNamesToAnnotations, newAnnotationMapping);
112                 close();
113                 this.instance = newInstance;
114                 Set<ServiceRegistration<?>> newRegs = registerToSR(instance, bundleContext, newAnnotationMapping);
115                 serviceRegistrations.clear();
116                 serviceRegistrations.addAll(newRegs);
117             }
118         }
119     }
120 }