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