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
9 package org.opendaylight.controller.northbound.bundlescanner.internal;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.Dictionary;
15 import java.util.HashSet;
16 import java.util.List;
19 import java.util.regex.Pattern;
21 import org.osgi.framework.Bundle;
22 import org.osgi.framework.Constants;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
27 * BundleInfo holds information related to the bundle obtained during the
28 * bundle scan process.
30 /*package*/ class BundleInfo {
31 private static final Logger LOGGER = LoggerFactory.getLogger(BundleInfo.class);
33 private final Bundle bundle;
34 private final Map<String, Set<String>> annotatedClasses;
35 private final Set<String> exportPkgs;
36 private final Set<String> importPkgs;
38 public BundleInfo(Bundle bundle, Map<String, Set<String>> classes) {
40 this.annotatedClasses = classes;
41 Dictionary<String, String> dict = bundle.getHeaders();
42 this.importPkgs = parsePackages(dict.get(Constants.IMPORT_PACKAGE));
43 this.exportPkgs = parsePackages(dict.get(Constants.EXPORT_PACKAGE));
47 public String toString() {
48 StringBuilder sb = new StringBuilder(super.toString());
49 sb.append("{name:").append(bundle.getSymbolicName())
50 .append(" id:").append(getId())
51 .append(" annotated-classes:").append(annotatedClasses)
52 .append(" imports:").append(importPkgs)
53 .append(" exports:").append(exportPkgs).append("}");
57 public Bundle getBundle() {
62 return bundle.getBundleId();
65 public List<Class<?>> getAnnotatedClasses(Pattern pattern, Set<String> excludes) {
66 List<String> result = new ArrayList<String>();
67 for (Map.Entry<String, Set<String>> entry : annotatedClasses.entrySet()) {
68 if (matches(pattern, entry.getValue())) {
69 result.add(entry.getKey());
72 return BundleScanner.loadClasses(result, bundle, excludes);
75 private boolean matches(Pattern pattern, Set<String> values) {
76 if (pattern == null) {
79 //LOGGER.debug("Matching: {} {}", pattern.toString(), values);
80 for (String s : values) {
81 if (pattern.matcher(s).find()) {
89 * Get classes with annotations matching a pattern
91 * @param allbundles - all bundles
92 * @param pattern - annotation pattern to match
93 * @param initBundle - the bundle which initiated this call
94 * @param excludes - set of class names to be excluded
96 * @return list of annotated classes matching the pattern
98 public List<Class<?>> getAnnotatedClasses(
99 Collection<BundleInfo> allbundles,
100 Pattern pattern, Bundle initBundle,
101 Set<String> excludes)
103 List<Class<?>> classes = getAnnotatedClasses(pattern, excludes);
104 processAnnotatedClassesInternal(this, allbundles, pattern,
105 new HashSet<BundleInfo>(), classes, initBundle, excludes);
109 private List<String> getExportedAnnotatedClasses(Pattern pattern) {
110 List<String> classes = new ArrayList<String>();
111 for (Map.Entry<String, Set<String>> entry : annotatedClasses.entrySet()) {
112 String cls = entry.getKey();
113 int idx = cls.lastIndexOf(".");
114 String pkg = (idx == -1 ? "" : cls.substring(0, idx));
115 // for a class to match, the package has to be exported and
116 // annotations should match the given pattern
117 if (exportPkgs.contains(pkg) && matches(pattern, entry.getValue())) {
121 if (LOGGER.isDebugEnabled()) {
122 LOGGER.debug("Found in bundle:{} exported classes:[{}]",
123 getBundle().getSymbolicName(), classes);
128 private static void processAnnotatedClassesInternal(
130 Collection<BundleInfo> bundlesToScan,
132 Collection<BundleInfo> visited,
133 List<Class<?>> classes,
134 Bundle initBundle, Set<String> excludes)
136 for (BundleInfo other : bundlesToScan) {
137 if (other.getId() == target.getId()) {
140 if (target.isDependantOn(other)) {
141 if (!visited.contains(other)) {
142 classes.addAll(BundleScanner.loadClasses(
143 other.getExportedAnnotatedClasses(pattern),
144 initBundle, excludes));
146 processAnnotatedClassesInternal(other, bundlesToScan,
147 pattern, visited, classes, initBundle, excludes);
153 private boolean isDependantOn(BundleInfo other) {
154 for (String pkg : importPkgs) {
155 if (other.exportPkgs.contains(pkg)) {
162 public List<BundleInfo> getDependencies(Collection<BundleInfo> bundles) {
163 List<BundleInfo> result = new ArrayList<BundleInfo>();
164 for(BundleInfo bundle : bundles) {
165 if (isDependantOn(bundle)) {
173 private static Set<String> parsePackages(String packageString) {
174 if (packageString == null) {
175 return Collections.emptySet();
177 String[] packages = packageString.split(",");
178 Set<String> result = new HashSet<String>();
179 for (int i=0; i<packages.length; i++) {
180 String[] nameAndAttrs = packages[i].split(";");
181 String packageName = nameAndAttrs[0].trim();
182 result.add(packageName);