2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.config.yang.store.impl;
10 import java.io.IOException;
11 import java.io.InputStream;
13 import java.util.Collection;
14 import java.util.Enumeration;
17 import org.opendaylight.controller.config.yang.store.api.YangStoreException;
18 import org.opendaylight.controller.config.yang.store.api.YangStoreService;
19 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
20 import org.osgi.framework.Bundle;
21 import org.osgi.framework.BundleContext;
22 import org.osgi.framework.BundleEvent;
23 import org.osgi.util.tracker.BundleTracker;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
27 import com.google.common.annotations.VisibleForTesting;
28 import com.google.common.base.Function;
29 import com.google.common.base.Optional;
30 import com.google.common.base.Preconditions;
31 import com.google.common.collect.Collections2;
32 import com.google.common.collect.HashMultimap;
33 import com.google.common.collect.Multimap;
34 import com.google.common.collect.Sets;
36 public class ExtenderYangTracker extends BundleTracker<Object> implements
39 private static final Logger logger = LoggerFactory
40 .getLogger(ExtenderYangTracker.class);
42 private final Multimap<Bundle, URL> bundlesToYangURLs = HashMultimap
44 private final YangStoreCache cache = new YangStoreCache();
45 private final MbeParser mbeParser;
47 public ExtenderYangTracker(BundleContext context) {
48 this(context, new MbeParser());
53 ExtenderYangTracker(BundleContext context, MbeParser mbeParser) {
54 super(context, Bundle.ACTIVE, null);
55 this.mbeParser = mbeParser;
56 logger.trace("Registered as extender with context {}", context);
60 public Object addingBundle(Bundle bundle, BundleEvent event) {
62 // Ignore system bundle
64 // system bundle has config-api on classpath &&
65 // config-api contains yang files =>
66 // system bundle contains yang files from that bundle
67 if (bundle.getBundleId() == 0)
70 Enumeration<URL> yangURLs = bundle.findEntries("META-INF/yang",
77 while (yangURLs.hasMoreElements()) {
78 URL yang = yangURLs.nextElement();
79 logger.debug("Bundle {} found yang file {}", bundle, yang);
80 bundlesToYangURLs.put(bundle, yang);
88 public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
90 Collection<URL> urls = bundlesToYangURLs.removeAll(bundle);
92 "Removed following yang URLs {} because of removed bundle {}",
98 public synchronized YangStoreSnapshot getYangStoreSnapshot()
99 throws YangStoreException {
100 Optional<YangStoreSnapshot> yangStoreOpt = cache
101 .getCachedYangStore(bundlesToYangURLs);
102 if (yangStoreOpt.isPresent()) {
103 logger.debug("Returning cached yang store {}", yangStoreOpt.get());
104 return yangStoreOpt.get();
108 YangStoreSnapshot yangStoreSnapshot = mbeParser
109 .parseYangFiles(fromUrlsToInputStreams());
111 "{} module entries parsed successfully from {} yang files",
112 yangStoreSnapshot.countModuleMXBeanEntries(),
113 bundlesToYangURLs.values().size());
114 cache.cacheYangStore(bundlesToYangURLs, yangStoreSnapshot);
116 return yangStoreSnapshot;
117 } catch (RuntimeException e) {
119 "Unable to parse yang files, yang files that were picked up so far: {}",
120 bundlesToYangURLs, e);
121 throw new YangStoreException("Unable to parse yang files", e);
125 private Collection<InputStream> fromUrlsToInputStreams() {
126 return Collections2.transform(bundlesToYangURLs.values(),
127 new Function<URL, InputStream>() {
130 public InputStream apply(URL url) {
132 return url.openStream();
133 } catch (IOException e) {
134 logger.warn("Unable to open stream from {}", url);
135 throw new IllegalStateException(
136 "Unable to open stream from " + url, e);
142 private static final class YangStoreCache {
145 YangStoreSnapshot cachedYangStoreSnapshot;
147 Optional<YangStoreSnapshot> getCachedYangStore(
148 Multimap<Bundle, URL> bundlesToYangURLs) {
149 Set<URL> urls = setFromMultimapValues(bundlesToYangURLs);
150 if (cachedUrls != null && cachedUrls.equals(urls)) {
151 Preconditions.checkState(cachedYangStoreSnapshot != null);
152 return Optional.of(cachedYangStoreSnapshot);
154 return Optional.absent();
157 private static Set<URL> setFromMultimapValues(
158 Multimap<Bundle, URL> bundlesToYangURLs) {
159 Set<URL> urls = Sets.newHashSet(bundlesToYangURLs.values());
160 Preconditions.checkState(bundlesToYangURLs.size() == urls.size());
164 void cacheYangStore(Multimap<Bundle, URL> urls,
165 YangStoreSnapshot yangStoreSnapshot) {
166 this.cachedUrls = setFromMultimapValues(urls);
167 this.cachedYangStoreSnapshot = yangStoreSnapshot;