Decouple config and netconf subsystems.
[controller.git] / opendaylight / config / config-manager-facade-xml / src / main / java / org / opendaylight / controller / config / facade / xml / osgi / YangStoreActivator.java
1     /*
2  * Copyright (c) 2015 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
9 package org.opendaylight.controller.config.facade.xml.osgi;
10
11 import java.lang.management.ManagementFactory;
12 import java.util.Hashtable;
13 import java.util.concurrent.atomic.AtomicBoolean;
14 import javax.management.MBeanServer;
15 import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacadeFactory;
16 import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
17 import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
18 import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
19 import org.osgi.framework.BundleActivator;
20 import org.osgi.framework.BundleContext;
21 import org.osgi.framework.ServiceReference;
22 import org.osgi.framework.ServiceRegistration;
23 import org.osgi.util.tracker.ServiceTracker;
24 import org.osgi.util.tracker.ServiceTrackerCustomizer;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 /**
29  * Start yang store service and the XML config manager facade
30  */
31 public class YangStoreActivator implements BundleActivator {
32
33     private static final Logger LOG = LoggerFactory.getLogger(YangStoreActivator.class);
34
35     private final MBeanServer configMBeanServer = ManagementFactory.getPlatformMBeanServer();
36
37     private ServiceRegistration<YangStoreService> yangStoreServiceServiceRegistration;
38     private ConfigRegistryLookupThread configRegistryLookup = null;
39     private BundleContext context;
40     private ServiceRegistration<ConfigSubsystemFacadeFactory> osgiRegistrayion;
41
42     @Override
43     public void start(final BundleContext context) throws Exception {
44         LOG.debug("ConfigPersister starting");
45         this.context = context;
46
47         ServiceTrackerCustomizer<SchemaContextProvider, YangStoreService> schemaServiceTrackerCustomizer = new ServiceTrackerCustomizer<SchemaContextProvider, YangStoreService>() {
48
49             private final AtomicBoolean alreadyStarted = new AtomicBoolean(false);
50
51             @Override
52             public YangStoreService addingService(ServiceReference<SchemaContextProvider> reference) {
53                 LOG.debug("Got addingService(SchemaContextProvider) event");
54
55                 // Yang store service should not be registered multiple times
56                 if(!alreadyStarted.compareAndSet(false, true)) {
57                     LOG.warn("Starting yang store service multiple times. Received new service {}", reference);
58                     throw new RuntimeException("Starting yang store service multiple times");
59                 }
60                 SchemaContextProvider schemaContextProvider = reference.getBundle().getBundleContext().getService(reference);
61                 final YangStoreService yangStoreService = new YangStoreService(schemaContextProvider);
62                 yangStoreServiceServiceRegistration = context.registerService(YangStoreService.class, yangStoreService, new Hashtable<String, Object>());
63                 configRegistryLookup = new ConfigRegistryLookupThread(yangStoreService);
64                 configRegistryLookup.start();
65                 return yangStoreService;
66             }
67
68             @Override
69             public void modifiedService(ServiceReference<SchemaContextProvider> reference, YangStoreService service) {
70                 LOG.debug("Got modifiedService(SchemaContextProvider) event");
71                 final BindingRuntimeContext runtimeContext = (BindingRuntimeContext) reference.getProperty(BindingRuntimeContext.class.getName());
72                 LOG.debug("BindingRuntimeContext retrieved as {}", runtimeContext);
73                 service.refresh(runtimeContext);
74             }
75
76             @Override
77             public void removedService(ServiceReference<SchemaContextProvider> reference, YangStoreService service) {
78                 LOG.debug("Got removedService(SchemaContextProvider) event");
79                 alreadyStarted.set(false);
80                 configRegistryLookup.interrupt();
81                 yangStoreServiceServiceRegistration.unregister();
82                 yangStoreServiceServiceRegistration = null;
83             }
84         };
85
86         ServiceTracker<SchemaContextProvider, YangStoreService> schemaContextProviderServiceTracker =
87                 new ServiceTracker<>(context, SchemaContextProvider.class, schemaServiceTrackerCustomizer);
88         schemaContextProviderServiceTracker.open();
89     }
90
91     @Override
92     public void stop(BundleContext context) throws Exception {
93         if(configRegistryLookup != null) {
94             configRegistryLookup.interrupt();
95         }
96         if(osgiRegistrayion != null) {
97             osgiRegistrayion.unregister();
98         }
99         if (yangStoreServiceServiceRegistration != null) {
100             yangStoreServiceServiceRegistration.unregister();
101             yangStoreServiceServiceRegistration = null;
102         }
103     }
104
105     /**
106      * Find ConfigRegistry from config manager in JMX
107      */
108     private class ConfigRegistryLookupThread extends Thread {
109         public static final int ATTEMPT_TIMEOUT_MS = 1000;
110         private static final int SILENT_ATTEMPTS = 30;
111
112         private final YangStoreService yangStoreService;
113
114         private ConfigRegistryLookupThread(YangStoreService yangStoreService) {
115             super("config-registry-lookup");
116             this.yangStoreService = yangStoreService;
117         }
118
119         @Override
120         public void run() {
121
122             ConfigRegistryJMXClient configRegistryJMXClient;
123             ConfigRegistryJMXClient configRegistryJMXClientNoNotifications;
124             int i = 0;
125             // Config registry might not be present yet, but will be eventually
126             while(true) {
127
128                 try {
129                     configRegistryJMXClient = new ConfigRegistryJMXClient(configMBeanServer);
130                     configRegistryJMXClientNoNotifications = ConfigRegistryJMXClient.createWithoutNotifications(configMBeanServer);
131                     break;
132                 } catch (IllegalStateException e) {
133                     ++i;
134                     if (i > SILENT_ATTEMPTS) {
135                         LOG.info("JMX client not created after {} attempts, still trying", i, e);
136                     } else {
137                         LOG.debug("JMX client could not be created, reattempting, try {}", i, e);
138                     }
139                     try {
140                         Thread.sleep(ATTEMPT_TIMEOUT_MS);
141                     } catch (InterruptedException e1) {
142                         Thread.currentThread().interrupt();
143                         throw new IllegalStateException("Interrupted while reattempting connection", e1);
144                     }
145                 }
146             }
147
148             final ConfigRegistryJMXClient jmxClient = configRegistryJMXClient;
149             final ConfigRegistryJMXClient jmxClientNoNotifications = configRegistryJMXClientNoNotifications;
150             if (i > SILENT_ATTEMPTS) {
151                 LOG.info("Created JMX client after {} attempts", i);
152             } else {
153                 LOG.debug("Created JMX client after {} attempts", i);
154             }
155
156             final ConfigSubsystemFacadeFactory configSubsystemFacade =
157                     new ConfigSubsystemFacadeFactory(jmxClient, jmxClientNoNotifications, yangStoreService);
158             osgiRegistrayion = context.registerService(ConfigSubsystemFacadeFactory.class, configSubsystemFacade, new Hashtable<String, Object>());
159         }
160     }
161 }
162