Handle conflicting types in BundleScanner
[controller.git] / opendaylight / northbound / bundlescanner / implementation / src / main / java / org / opendaylight / controller / northbound / bundlescanner / internal / BundleScanner.java
index 3e517e9a1f717e3b9a8c889c5b34b2f3bf3d7351..0c640820598b1c4f12f7f786df1ee3f23ee774a2 100644 (file)
@@ -22,6 +22,8 @@ import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
 
+import javax.xml.bind.annotation.XmlRootElement;
+
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
@@ -66,6 +68,7 @@ import org.slf4j.LoggerFactory;
 
     public List<Class<?>> getAnnotatedClasses(BundleContext context,
             String[] annotations,
+            Set<String> excludes,
             boolean includeDependentBundleClasses)
     {
         BundleInfo info = bundleAnnotations.get(context.getBundle().getBundleId());
@@ -73,9 +76,15 @@ import org.slf4j.LoggerFactory;
         Pattern pattern = mergePatterns(annotations, false);
         List<Class<?>> result = null;
         if (includeDependentBundleClasses) {
-            result = info.getAnnotatedClasses(bundleAnnotations.values(), pattern);
+            result = info.getAnnotatedClasses(bundleAnnotations.values(),
+                    pattern, context.getBundle(), excludes);
+            // reverse the list to give precedence to the types loaded from the
+            // initiating bundle
+            Collections.reverse(result);
+            // validate for conflicts only when searching dependencies
+            validate(result);
         } else {
-            result = info.getAnnotatedClasses(pattern);
+            result = info.getAnnotatedClasses(pattern, excludes);
         }
         LOGGER.debug("Annotated classes detected: {} matching: {}", result, pattern);
         return result;
@@ -237,17 +246,24 @@ import org.slf4j.LoggerFactory;
         // find bundle dependencies
     }
 
-    public static List<Class<?>> loadClasses(Bundle bundle,
-            Collection<String> annotatedClasses)
+    public static List<Class<?>> loadClasses(
+            Collection<String> annotatedClasses,
+            Bundle initBundle, Set<String> excludes)
     {
         List<Class<?>> result = new ArrayList<Class<?>>();
+        StringBuilder errors = new StringBuilder();
         for (String name : annotatedClasses) {
             try {
-                result.add(bundle.loadClass(name));
-            } catch (Exception e) {
-                LOGGER.error("Unable to load class: {}", name, e);
+                if (excludes != null && excludes.contains(name)) continue;
+                result.add(initBundle.loadClass(name));
+            } catch (ClassNotFoundException e) {
+                errors.append(name).append(", ");
             }
         }
+        if (LOGGER.isDebugEnabled() && errors.length() > 0) {
+            LOGGER.debug("Bundle: {} could not load classes: {}",
+                    initBundle.getSymbolicName(), errors.toString());
+        }
         return result;
     }
 
@@ -274,4 +290,31 @@ import org.slf4j.LoggerFactory;
         return Pattern.compile(regex.toString());
     }
 
+    private void validate(List<Class<?>> classes) {
+        if (classes == null || classes.size() == 0) return;
+        Map<String,String> names = new HashMap<String,String>();
+        StringBuilder conflictsMsg = new StringBuilder();
+        for (Class c : classes) {
+            XmlRootElement root = (XmlRootElement) c.getAnnotation(XmlRootElement.class);
+            if (root == null) continue;
+            String rootName = root.name();
+            if ("##default".equals(rootName)) {
+                String clsName = c.getSimpleName();
+                rootName = Character.toLowerCase(clsName.charAt(0)) + clsName.substring(1);
+            }
+            String other = names.get(rootName);
+            if (other != null && !other.equals(c.getName())) {
+                conflictsMsg.append(System.lineSeparator())
+                    .append("[").append(rootName).append(":")
+                    .append(c.getName()).append(",").append(other)
+                    .append("]");
+            } else {
+                names.put(rootName, c.getName());
+            }
+        }
+        if (conflictsMsg.length() > 0) {
+            LOGGER.info("JAXB type conflicts detected : {}", conflictsMsg.toString());
+        }
+    }
+
 }