5727c13ba1e888825d94b96bcc1c330bdf39fa1e
[controller.git] / opendaylight / blueprint / src / main / java / org / opendaylight / controller / blueprint / BlueprintBundleTracker.java
1 /*
2  * Copyright (c) 2016 Brocade Communications 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.blueprint;
9
10 import java.util.Collections;
11 import java.util.Dictionary;
12 import java.util.Enumeration;
13 import java.util.Hashtable;
14 import java.util.List;
15 import org.apache.aries.blueprint.NamespaceHandler;
16 import org.apache.aries.blueprint.services.BlueprintExtenderService;
17 import org.apache.aries.util.AriesFrameworkUtil;
18 import org.opendaylight.controller.blueprint.ext.OpendaylightNamespaceHandler;
19 import org.osgi.framework.Bundle;
20 import org.osgi.framework.BundleActivator;
21 import org.osgi.framework.BundleContext;
22 import org.osgi.framework.BundleEvent;
23 import org.osgi.framework.ServiceReference;
24 import org.osgi.framework.ServiceRegistration;
25 import org.osgi.service.blueprint.container.EventConstants;
26 import org.osgi.service.event.Event;
27 import org.osgi.service.event.EventHandler;
28 import org.osgi.util.tracker.BundleTracker;
29 import org.osgi.util.tracker.BundleTrackerCustomizer;
30 import org.osgi.util.tracker.ServiceTracker;
31 import org.osgi.util.tracker.ServiceTrackerCustomizer;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * This class is created in bundle activation and scans ACTIVE bundles for blueprint XML files located under
37  * the well-known org/opendaylight/blueprint/ path and deploys the XML files via the Aries
38  * BlueprintExtenderService. This path differs from the standard OSGI-INF/blueprint path to allow for
39  * controlled deployment of blueprint containers in an orderly manner.
40  *
41  * @author Thomas Pantelis
42  */
43 public class BlueprintBundleTracker implements BundleActivator, BundleTrackerCustomizer<Bundle>, EventHandler {
44     private static final Logger LOG = LoggerFactory.getLogger(BlueprintBundleTracker.class);
45     private static final String BLUEPRINT_FILE_PATH = "org/opendaylight/blueprint/";
46     private static final String BLUEPRINT_FLE_PATTERN = "*.xml";
47
48     private ServiceTracker<BlueprintExtenderService, BlueprintExtenderService> serviceTracker;
49     private BundleTracker<Bundle> bundleTracker;
50     private volatile BlueprintExtenderService blueprintExtenderService;
51     private volatile ServiceRegistration<?> blueprintContainerRestartReg;
52     private ServiceRegistration<?> eventHandlerReg;
53     private ServiceRegistration<?> namespaceReg;
54
55     /**
56      * Implemented from BundleActivator.
57      */
58     @Override
59     public void start(BundleContext context) {
60         LOG.info("Starting {}", getClass().getSimpleName());
61
62         registerBlueprintEventHandler(context);
63
64         registerNamespaceHandler(context);
65
66         bundleTracker = new BundleTracker<>(context, Bundle.ACTIVE, this);
67
68         serviceTracker = new ServiceTracker<>(context, BlueprintExtenderService.class.getName(),
69                 new ServiceTrackerCustomizer<BlueprintExtenderService, BlueprintExtenderService>() {
70                     @Override
71                     public BlueprintExtenderService addingService(
72                             ServiceReference<BlueprintExtenderService> reference) {
73                         blueprintExtenderService = reference.getBundle().getBundleContext().getService(reference);
74                         bundleTracker.open();
75
76                         LOG.debug("Got BlueprintExtenderService");
77
78                         blueprintContainerRestartReg = context.registerService(
79                                 BlueprintContainerRestartService.class.getName(),
80                                 new BlueprintContainerRestartServiceImpl(blueprintExtenderService), new Hashtable<>());
81
82                         return blueprintExtenderService;
83                     }
84
85                     @Override
86                     public void modifiedService(ServiceReference<BlueprintExtenderService> reference,
87                             BlueprintExtenderService service) {
88                     }
89
90                     @Override
91                     public void removedService(ServiceReference<BlueprintExtenderService> reference,
92                             BlueprintExtenderService service) {
93                     }
94                 });
95         serviceTracker.open();
96     }
97
98     private void registerNamespaceHandler(BundleContext context) {
99         Dictionary<String, Object> props = new Hashtable<>();
100         props.put("osgi.service.blueprint.namespace", OpendaylightNamespaceHandler.NAMESPACE_1_0_0);
101         namespaceReg = context.registerService(NamespaceHandler.class.getName(),
102                 new OpendaylightNamespaceHandler(), props);
103     }
104
105     private void registerBlueprintEventHandler(BundleContext context) {
106         Dictionary<String, Object> props = new Hashtable<>();
107         props.put(org.osgi.service.event.EventConstants.EVENT_TOPIC, EventConstants.TOPIC_CREATED);
108         eventHandlerReg = context.registerService(EventHandler.class.getName(), this, props);
109     }
110
111     /**
112      * Implemented from BundleActivator.
113      */
114     @Override
115     public void stop(BundleContext context) {
116         bundleTracker.close();
117         serviceTracker.close();
118
119         AriesFrameworkUtil.safeUnregisterService(eventHandlerReg);
120         AriesFrameworkUtil.safeUnregisterService(namespaceReg);
121         AriesFrameworkUtil.safeUnregisterService(blueprintContainerRestartReg);
122     }
123
124     /**
125      * Implemented from BundleActivator.
126      */
127     @Override
128     public Bundle addingBundle(Bundle bundle, BundleEvent event) {
129         modifiedBundle(bundle, event, bundle);
130         return bundle;
131     }
132
133     /**
134      * Implemented from BundleActivator.
135      */
136     @Override
137     public void modifiedBundle(Bundle bundle, BundleEvent event, Bundle object) {
138         if(bundle.getState() == Bundle.ACTIVE) {
139             List<Object> paths = findBlueprintPaths(bundle);
140
141             if(!paths.isEmpty()) {
142                 LOG.info("Creating blueprint container for bundle {} with paths {}", bundle, paths);
143
144                 blueprintExtenderService.createContainer(bundle, paths);
145             }
146         }
147     }
148
149     /**
150      * Implemented from BundleActivator.
151      */
152     @Override
153     public void removedBundle(Bundle bundle, BundleEvent event, Bundle object) {
154         // BlueprintExtenderService will handle this.
155     }
156
157     /**
158      * Implemented from EventHandler to listen for blueprint events.
159      *
160      * @param event
161      */
162     @Override
163     public void handleEvent(Event event) {
164         if(EventConstants.TOPIC_CREATED.equals(event.getTopic())) {
165             LOG.info("Blueprint container for bundle {} was successfully created",
166                     event.getProperty(EventConstants.BUNDLE));
167         }
168     }
169
170     @SuppressWarnings({ "rawtypes", "unchecked" })
171     static List<Object> findBlueprintPaths(Bundle bundle) {
172         Enumeration<?> e = bundle.findEntries(BLUEPRINT_FILE_PATH, BLUEPRINT_FLE_PATTERN, false);
173         if(e == null) {
174             return Collections.emptyList();
175         } else {
176             return Collections.list((Enumeration)e);
177         }
178     }
179 }