Modify ModuleInfoBundleTracker to track RESOLVED bundles (round 2)
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / osgi / mapping / ModuleInfoBundleTracker.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.mapping;
9
10 import static java.lang.String.format;
11 import com.google.common.base.Charsets;
12 import com.google.common.io.Resources;
13 import java.io.IOException;
14 import java.net.URL;
15 import java.util.Collection;
16 import java.util.LinkedList;
17 import java.util.List;
18 import org.opendaylight.yangtools.concepts.ObjectRegistration;
19 import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider;
20 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
21 import org.osgi.framework.Bundle;
22 import org.osgi.framework.BundleContext;
23 import org.osgi.framework.BundleEvent;
24 import org.osgi.util.tracker.BundleTracker;
25 import org.osgi.util.tracker.BundleTrackerCustomizer;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * Tracks bundles and attempts to retrieve YangModuleInfo, which is then fed into ModuleInfoRegistry
31  */
32 public final class ModuleInfoBundleTracker implements AutoCloseable,
33         BundleTrackerCustomizer<Collection<ObjectRegistration<YangModuleInfo>>> {
34
35     private static final Logger LOG = LoggerFactory.getLogger(ModuleInfoBundleTracker.class);
36
37     public static final String MODULE_INFO_PROVIDER_PATH_PREFIX = "META-INF/services/";
38
39
40     private final RefreshingSCPModuleInfoRegistry moduleInfoRegistry;
41     private final BundleTracker<Collection<ObjectRegistration<YangModuleInfo>>> bundleTracker;
42     private boolean starting;
43
44     public ModuleInfoBundleTracker(BundleContext context, RefreshingSCPModuleInfoRegistry moduleInfoRegistry) {
45         this.moduleInfoRegistry = moduleInfoRegistry;
46         bundleTracker = new BundleTracker<>(context, Bundle.RESOLVED | Bundle.STARTING |
47                 Bundle.STOPPING | Bundle.ACTIVE, this);
48     }
49
50     public void open() {
51         LOG.debug("ModuleInfoBundleTracker open starting");
52
53         starting = true;
54         bundleTracker.open();
55
56         starting = false;
57         moduleInfoRegistry.updateService();
58
59         LOG.debug("ModuleInfoBundleTracker open complete");
60     }
61
62     @Override
63     public void close() {
64         bundleTracker.close();
65     }
66
67     @Override
68     public Collection<ObjectRegistration<YangModuleInfo>> addingBundle(Bundle bundle, BundleEvent event) {
69         URL resource = bundle.getEntry(MODULE_INFO_PROVIDER_PATH_PREFIX + YangModelBindingProvider.class.getName());
70         LOG.debug("Got addingBundle({}) with YangModelBindingProvider resource {}", bundle, resource);
71         if(resource==null) {
72             return null;
73         }
74         List<ObjectRegistration<YangModuleInfo>> registrations = new LinkedList<>();
75
76         try {
77             for (String moduleInfoName : Resources.readLines(resource, Charsets.UTF_8)) {
78                 LOG.trace("Retrieve ModuleInfo({}, {})", moduleInfoName, bundle);
79                 YangModuleInfo moduleInfo = retrieveModuleInfo(moduleInfoName, bundle);
80                 registrations.add(moduleInfoRegistry.registerModuleInfo(moduleInfo));
81             }
82
83             if(!starting) {
84                 moduleInfoRegistry.updateService();
85             }
86         } catch (IOException e) {
87             LOG.error("Error while reading {} from bundle {}", resource, bundle, e);
88         } catch (RuntimeException e) {
89             LOG.error("Failed to process {} for bundle {}", resource, bundle, e);
90         }
91
92         LOG.trace("Got following registrations {}", registrations);
93         return registrations;
94     }
95
96     @Override
97     public void modifiedBundle(Bundle bundle, BundleEvent event, Collection<ObjectRegistration<YangModuleInfo>> object) {
98     }
99
100     @Override
101     public void removedBundle(Bundle bundle, BundleEvent event, Collection<ObjectRegistration<YangModuleInfo>> regs) {
102         if(regs == null) {
103             return;
104         }
105
106         for (ObjectRegistration<YangModuleInfo> reg : regs) {
107             try {
108                 reg.close();
109             } catch (Exception e) {
110                 LOG.error("Unable to unregister YangModuleInfo {}", reg.getInstance(), e);
111             }
112         }
113     }
114
115     private static YangModuleInfo retrieveModuleInfo(String moduleInfoClass, Bundle bundle) {
116         String errorMessage;
117         Class<?> clazz = loadClass(moduleInfoClass, bundle);
118
119         if (YangModelBindingProvider.class.isAssignableFrom(clazz) == false) {
120             errorMessage = logMessage("Class {} does not implement {} in bundle {}", clazz, YangModelBindingProvider.class, bundle);
121             throw new IllegalStateException(errorMessage);
122         }
123         YangModelBindingProvider instance;
124         try {
125             Object instanceObj = clazz.newInstance();
126             instance = YangModelBindingProvider.class.cast(instanceObj);
127         } catch (InstantiationException e) {
128             errorMessage = logMessage("Could not instantiate {} in bundle {}, reason {}", moduleInfoClass, bundle, e);
129             throw new IllegalStateException(errorMessage, e);
130         } catch (IllegalAccessException e) {
131             errorMessage = logMessage("Illegal access during instantiation of class {} in bundle {}, reason {}",
132                     moduleInfoClass, bundle, e);
133             throw new IllegalStateException(errorMessage, e);
134         }
135
136         try{
137             return instance.getModuleInfo();
138         } catch (NoClassDefFoundError | ExceptionInInitializerError e) {
139             throw new IllegalStateException("Error while executing getModuleInfo on " + instance, e);
140         }
141     }
142
143     private static Class<?> loadClass(String moduleInfoClass, Bundle bundle) {
144         try {
145             return bundle.loadClass(moduleInfoClass);
146         } catch (ClassNotFoundException e) {
147             String errorMessage = logMessage("Could not find class {} in bundle {}, reason {}", moduleInfoClass, bundle, e);
148             throw new IllegalStateException(errorMessage);
149         }
150     }
151
152     public static String logMessage(String slfMessage, Object... params) {
153         LOG.info(slfMessage, params);
154         String formatMessage = slfMessage.replaceAll("\\{\\}", "%s");
155         return format(formatMessage, params);
156     }
157 }