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