felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pde...@apache.org
Subject svn commit: r1761367 - in /felix/trunk/dependencymanager: org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/ org.apache.felix.dependencymanager.runtime.itest/src/org/apache/felix/dm/runtime/itest/components/ or...
Date Sun, 18 Sep 2016 22:04:20 GMT
Author: pderop
Date: Sun Sep 18 22:04:20 2016
New Revision: 1761367

URL: http://svn.apache.org/viewvc?rev=1761367&view=rev
Log:
FELIX-4384: committed improvement for the support of annotation inheritance.

Added:
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime.itest/src/org/apache/felix/dm/runtime/itest/components/InheritedAnnotations.java
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime.itest/src/org/apache/felix/dm/runtime/itest/tests/InheritedAnnotationsTest.java
Modified:
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationPlugin.java
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/DescriptorGenerator.java

Modified: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java?rev=1761367&r1=1761366&r2=1761367&view=diff
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
(original)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
Sun Sep 18 22:04:20 2016
@@ -24,7 +24,9 @@ import java.util.Arrays;
 import java.util.Dictionary;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Optional;
 import java.util.Set;
+import java.util.function.Supplier;
 
 import org.apache.felix.dm.annotation.api.AdapterService;
 import org.apache.felix.dm.annotation.api.AspectService;
@@ -91,14 +93,13 @@ public class AnnotationCollector extends
     private final static String A_UNREGISTERED = Unregistered.class.getName();
 
     private Logger m_logger;
-    private String m_className;
     private String[] m_interfaces;
     private boolean m_isField;
     private String m_field;
     private String m_method;
     private String m_descriptor;
-    private Set<String> m_dependencyNames = new HashSet<String>();
-    private List<EntryWriter> m_writers = new ArrayList<EntryWriter>();
+    private final Set<String> m_dependencyNames = new HashSet<String>();
+    private final List<EntryWriter> m_writers = new ArrayList<EntryWriter>();
     private MetaType m_metaType;
     private String m_startMethod;
     private String m_stopMethod;
@@ -107,14 +108,34 @@ public class AnnotationCollector extends
     private String m_compositionMethod;
     private String m_starter;
     private String m_stopper;
-    private Set<String> m_importService = new HashSet<String>();
-    private Set<String> m_exportService = new HashSet<String>();
+    private final Set<String> m_importService = new HashSet<String>();
+    private final Set<String> m_exportService = new HashSet<String>();
     private String m_bundleContextField;
     private String m_dependencyManagerField;
     private String m_componentField;
     private String m_registeredMethod;
     private String m_unregisteredMethod;
+	private TypeRef	m_superClass;
+	private boolean m_baseClass = true;
+	
+	/**
+	 * Name of the class annotated with @Component (or other kind of components, like aspect,
adapters).
+	 */
+    private String m_componentClassName;
     
+    /*
+     * Name of class currently being parsed (the component class name at first, then the
inherited classes).
+     * See DescriptorGenerator class, which first calls parseClassFileWithCollector method
with the component class, then it calls 
+     * again the parseClassFileWithCollector method with all inherited component super classes.

+     */
+    private String m_currentClassName;
+	
+    /**
+	 * Contains all bind methods annotated with a dependency.
+	 * Each entry has the format: "methodName/method signature".
+	 */
+	private final Set<String> m_bindMethods = new HashSet<>(); 
+
     /**
      * When more than one @Property annotation are declared on a component type (outside
of the @Component annotation), then a @Repeatable 
      * annotation is used as the container for the @Property annotations. When such annotation
is found, it is stored in this attribute, which 
@@ -143,6 +164,14 @@ public class AnnotationCollector extends
         m_logger = reporter;
         m_metaType = metaType;
     }
+    
+    /**
+     * Indicates that we are parsing a superclass of a given component class.
+     */
+    public void baseClass(boolean baseClass) {
+        m_logger.debug("baseClass:%b", baseClass);
+    	m_baseClass = baseClass;
+    }
 
     /**
      * Parses the name of the class.
@@ -152,8 +181,12 @@ public class AnnotationCollector extends
     @Override
     public void classBegin(int access, TypeRef name)
     {
-        m_className = name.getFQN();
-        m_logger.debug("class name: %s", m_className);
+    	if (m_baseClass) 
+    	{
+    		m_componentClassName = name.getFQN();
+            m_logger.debug("Parsing class: %s", m_componentClassName);
+    	}
+        m_currentClassName = name.getFQN();
     }
 
     /**
@@ -162,17 +195,20 @@ public class AnnotationCollector extends
     @Override
     public void implementsInterfaces(TypeRef[] interfaces)
     {
-        List<String> result = new ArrayList<String>();
-        for (int i = 0; i < interfaces.length; i++)
-        {
-            if (!interfaces[i].getBinary().equals("scala/ScalaObject"))
-            {
-                result.add(interfaces[i].getFQN());
-            }
-        }
+    	if (m_baseClass)
+    	{
+    		List<String> result = new ArrayList<String>();
+    		for (int i = 0; i < interfaces.length; i++)
+    		{
+    			if (!interfaces[i].getBinary().equals("scala/ScalaObject"))
+    			{
+    				result.add(interfaces[i].getFQN());
+    			}
+    		}
          
-        m_interfaces = result.toArray(new String[result.size()]);
-        m_logger.debug("implements: %s", Arrays.toString(m_interfaces));
+    		m_interfaces = result.toArray(new String[result.size()]);
+    		m_logger.debug("implements: %s", Arrays.toString(m_interfaces));
+    	}
     }
 
     /**
@@ -199,6 +235,15 @@ public class AnnotationCollector extends
         m_descriptor = field.getDescriptor().toString();
     }
 
+	@Override
+	public void extendsClass(TypeRef name) {
+		m_superClass = name;
+	}
+	
+	public TypeRef getSuperClass() {
+		return m_superClass; 
+	}
+
     /** 
      * An annotation has been parsed. Always invoked AFTER the "method"/"field"/"classBegin"
callbacks. 
      */
@@ -206,91 +251,110 @@ public class AnnotationCollector extends
     public void annotation(Annotation annotation)
     {
         m_logger.debug("Parsing annotation: %s", annotation.getName());
-
-        if (annotation.getName().getFQN().equals(A_COMPONENT))
+        
+        // if we are parsing a superclass of a given component, then ignore any component
annotations.        
+        String name = annotation.getName().getFQN();
+        if (! m_baseClass) { 
+            String simpleName = name.indexOf(".") != -1 ? name.substring(name.lastIndexOf(".")+1)
: name;
+            Optional<EntryType> type = m_componentTypes.stream().filter(writer ->
writer.name().equals(simpleName)).findFirst();
+            if (type.isPresent()) {
+                m_logger.debug("Ignoring annotation %s from super class %s of component class
%s", name, m_currentClassName, m_componentClassName);
+                return;
+            }
+        }
+        
+        if (name.equals(A_COMPONENT))
         {
             parseComponentAnnotation(annotation);
         }
-        else if (annotation.getName().getFQN().equals(A_ASPECT_SERVICE))
+        else if (name.equals(A_ASPECT_SERVICE))
         {
             parseAspectService(annotation);
         }
-        else if (annotation.getName().getFQN().equals(A_ADAPTER_SERVICE))
+        else if (name.equals(A_ADAPTER_SERVICE))
         {
             parseAdapterService(annotation);
         }
-        else if (annotation.getName().getFQN().equals(A_BUNDLE_ADAPTER_SERVICE))
+        else if (name.equals(A_BUNDLE_ADAPTER_SERVICE))
         {
             parseBundleAdapterService(annotation);
         }
-        else if (annotation.getName().getFQN().equals(A_RESOURCE_ADAPTER_SERVICE))
+        else if (name.equals(A_RESOURCE_ADAPTER_SERVICE))
         {
             parseResourceAdapterService(annotation);
         }
-        else if (annotation.getName().getFQN().equals(A_FACTORYCONFIG_ADAPTER_SERVICE))
+        else if (name.equals(A_FACTORYCONFIG_ADAPTER_SERVICE))
         {
             parseFactoryConfigurationAdapterService(annotation);
         }
-        else if (annotation.getName().getFQN().equals(A_INIT))
+        else if (name.equals(A_INIT))
         {
+            checkAlreadyDeclaredSingleAnnot(() -> m_initMethod, "@Init");
             m_initMethod = m_method;
         } 
-        else if (annotation.getName().getFQN().equals(A_START))
+        else if (name.equals(A_START))
         {
+            checkAlreadyDeclaredSingleAnnot(() -> m_startMethod, "@Start");
             m_startMethod = m_method;
         } 
-        else if (annotation.getName().getFQN().equals(A_REGISTERED))
+        else if (name.equals(A_REGISTERED))
         {
+            checkAlreadyDeclaredSingleAnnot(() -> m_registeredMethod, "@Registered");
             m_registeredMethod = m_method;
         }
-        else if (annotation.getName().getFQN().equals(A_STOP))
+        else if (name.equals(A_STOP))
         {
+            checkAlreadyDeclaredSingleAnnot(() -> m_stopMethod, "@Stop");
             m_stopMethod = m_method;
         }
-        else if (annotation.getName().getFQN().equals(A_UNREGISTERED))
+        else if (name.equals(A_UNREGISTERED))
         {
+            checkAlreadyDeclaredSingleAnnot(() -> m_unregisteredMethod, "@Unregistered");
             m_unregisteredMethod = m_method;
         }
-        else if (annotation.getName().getFQN().equals(A_DESTROY))
+        else if (name.equals(A_DESTROY))
         {
+            checkAlreadyDeclaredSingleAnnot(() -> m_destroyMethod, "@Destroy");
             m_destroyMethod = m_method;
         }
-        else if (annotation.getName().getFQN().equals(A_COMPOSITION))
+        else if (name.equals(A_COMPOSITION))
         {
+            checkAlreadyDeclaredSingleAnnot(() -> m_compositionMethod, "@Composition");
             Patterns.parseMethod(m_method, m_descriptor, Patterns.COMPOSITION);
             m_compositionMethod = m_method;
-        } else if (annotation.getName().getFQN().equals(A_LIFCLE_CTRL)) 
+        } 
+        else if (name.equals(A_LIFCLE_CTRL)) 
         {
             parseLifecycleAnnotation(annotation);
         }
-        else if (annotation.getName().getFQN().equals(A_SERVICE_DEP))
+        else if (name.equals(A_SERVICE_DEP))
         {
             parseServiceDependencyAnnotation(annotation);
         }
-        else if (annotation.getName().getFQN().equals(A_CONFIGURATION_DEPENDENCY))
+        else if (name.equals(A_CONFIGURATION_DEPENDENCY))
         {
             parseConfigurationDependencyAnnotation(annotation);
         }
-        else if (annotation.getName().getFQN().equals(A_BUNDLE_DEPENDENCY))
+        else if (name.equals(A_BUNDLE_DEPENDENCY))
         {
             parseBundleDependencyAnnotation(annotation);
         }
-        else if (annotation.getName().getFQN().equals(A_RESOURCE_DEPENDENCY))
+        else if (name.equals(A_RESOURCE_DEPENDENCY))
         {
             parseRersourceDependencyAnnotation(annotation);
         } 
-        else if (annotation.getName().getFQN().equals(A_INJECT))
+        else if (name.equals(A_INJECT))
         {
             parseInject(annotation);
         } 
-        else if (annotation.getName().getFQN().equals(A_REPEATABLE_PROPERTY))
+        else if (name.equals(A_REPEATABLE_PROPERTY))
         {
             parseRepeatableProperties(annotation);
         } 
         else if (annotation.getName().getFQN().equals(A_PROPERTY))
         {
         	m_singleProperty = annotation;
-        } 
+        }       
     }
 
     /**
@@ -299,21 +363,37 @@ public class AnnotationCollector extends
      */
     public boolean finish()
     {
-        if (m_writers.size() == 0)
-        {
-            m_logger.info("No components found for class " + m_className);
-            return false;
-        }
+        m_logger.info("finish %s", m_componentClassName);           
 
-        // We must have at least a valid component annotation type (component, aspect, or
adapters)
-        
-        EntryWriter componentWriter = m_writers.stream()
+        // check if we have a component (or adapter) annotation.                
+        Optional<EntryWriter> componentWriter = m_writers.stream()
             .filter(writer -> m_componentTypes.indexOf(writer.getEntryType()) != -1)
-            .findFirst()
-            .orElseThrow(() -> new IllegalStateException(": the class " + m_className
+ " must be annotated with either one of the following types: " + m_componentTypes));    
              
+            .findFirst();
         
-        // Add any repeated @Property annotations to the component (or to the aspect, or
adapter).
-                
+        if (! componentWriter.isPresent() || m_writers.size() == 0) {
+            m_logger.info("No components found for class " + m_componentClassName);
+            return false;
+        }
+        
+        finishComponentAnnotation(componentWriter.get());
+                        
+        // log all meta data for component annotations, dependencies, etc ...
+        StringBuilder sb = new StringBuilder();
+        sb.append("Parsed annotation for class ");
+        sb.append(m_componentClassName);
+        for (int i = m_writers.size() - 1; i >= 0; i--)
+        {
+            sb.append("\n\t").append(m_writers.get(i).toString());
+        }
+        m_logger.info(sb.toString());
+        return true;
+    }
+    
+    private void finishComponentAnnotation(EntryWriter componentWriter) {
+        // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
+        addCommonServiceParams(componentWriter);
+
+        // Add any repeated @Property annotations to the component (or to the aspect, or
adapter).                
         if (m_repeatableProperty != null)
         {
             Object[] properties = m_repeatableProperty.get("value");
@@ -329,30 +409,26 @@ public class AnnotationCollector extends
         if (m_singleProperty != null) {
             parseProperty(m_singleProperty, componentWriter);
         }
-        
-        StringBuilder sb = new StringBuilder();
-        sb.append("Parsed annotation for class ");
-        sb.append(m_className);
-        for (int i = m_writers.size() - 1; i >= 0; i--)
-        {
-            sb.append("\n\t").append(m_writers.get(i).toString());
-        }
-        m_logger.info(sb.toString());
-        return true;
     }
 
     /**
      * Writes the generated component descriptor in the given print writer.
-     * The first line must be the service (@Service or AspectService).
+     * The first line must be the component descriptor (@Component or AspectService, etc
..).
      * @param pw the writer where the component descriptor will be written.
      */
     public void writeTo(PrintWriter pw)
     {
-        // The last element our our m_writers list contains either the Service, or the AspectService
descriptor.
-        for (int i = m_writers.size() - 1; i >= 0; i--)
-        {
-            pw.println(m_writers.get(i).toString());
-        }
+        // write first the component descriptor (@Component, @AspectService, ...)
+        EntryWriter componentWriter = m_writers.stream()
+            .filter(writer -> m_componentTypes.indexOf(writer.getEntryType()) != -1)
+            .findFirst()
+            .orElseThrow(() -> new IllegalStateException("Component type not found while
scanning class " + m_componentClassName));
+        pw.println(componentWriter);
+            
+        // and write other component descriptors (dependencies, and other annotations)
+        m_writers.stream()
+            .filter(writer -> m_componentTypes.indexOf(writer.getEntryType()) == -1)
+            .forEach(dependency -> pw.println(dependency.toString()));        
     }
         
     /**
@@ -384,16 +460,25 @@ public class AnnotationCollector extends
         m_repeatableProperty = repeatedProperties;
     }
     
+    /**
+     * Checks double declaration of an annotation, which normally must be declared only one
time. 
+     * @param field the field supplier (if not null, means the annotation is already declared)
+     * @param annot the annotation name.
+     * @throws IllegalStateException if annotation is already declared.
+     */
+    private void checkAlreadyDeclaredSingleAnnot(Supplier<Object> field, String annot)
{
+        if (field.get() != null) {
+            throw new IllegalStateException("detected multiple " + annot + " annotation from
class " + m_currentClassName + " (on from child classes)");
+        }
+    }
+    
     private void parseComponentAnnotation(Annotation annotation)
     {
         EntryWriter writer = new EntryWriter(EntryType.Component);
         m_writers.add(writer);
 
-        // Register previously parsed annotations common to services (Init/Start/...)
-        addCommonServiceParams(writer);
-
         // impl attribute
-        writer.put(EntryParam.impl, m_className);
+        writer.put(EntryParam.impl, m_componentClassName);
 
         // properties attribute
         parseProperties(annotation, writer);
@@ -484,7 +569,7 @@ public class AnnotationCollector extends
             if (m_starter == null)
             {
                 throw new IllegalArgumentException("Can't use a @LifecycleController annotation
for stopping a service without declaring a " +
-                                                   "@LifecycleController that starts the
component in class " + m_className);
+                                                   "@LifecycleController that starts the
component in class " + m_currentClassName);
             }
         }   
 
@@ -505,6 +590,17 @@ public class AnnotationCollector extends
     }
 
     /**
+     * Check if a dependency is already declared in another same bindMethod (or class field)
on another child class.
+     */
+    private void checkDependencyAlreadyDeclaredInChild(Annotation annotation, String methodOrField,
boolean method) {
+        if (! m_baseClass && m_bindMethods.contains(methodOrField + "/" + m_descriptor))
{
+            throw new IllegalStateException("Annotation " + annotation.getName().getShortName()
+                + " declared on " + m_currentClassName + "." + methodOrField + (method ?
" method" : " field") + " is already declared in child classe(s)");
+        }
+        m_bindMethods.add(methodOrField + "/" + m_descriptor);
+    }
+    
+    /**
      * Parses a ServiceDependency Annotation.
      * @param annotation the ServiceDependency Annotation.
      */
@@ -519,10 +615,13 @@ public class AnnotationCollector extends
         {
             if (m_isField)
             {
+                checkDependencyAlreadyDeclaredInChild(annotation, m_field, false);
                 service = Patterns.parseClass(m_descriptor, Patterns.CLASS, 1);
             }
             else
             {
+                // if we are parsing some inherited classes, detect if the bind method is
already declared in child classes
+                checkDependencyAlreadyDeclaredInChild(annotation, m_method, true);      
         
             	// parse "bind(Component, ServiceReference, Service)" signature
             	service = Patterns.parseClass(m_descriptor, Patterns.BIND_CLASS1, 3, false);
           		
             	
@@ -597,7 +696,7 @@ public class AnnotationCollector extends
         Long t = (Long) annotation.get(EntryParam.timeout.toString());
         if (t != null && t.longValue() < -1)
         {
-            throw new IllegalArgumentException("Invalid timeout value " + t + " in ServiceDependency
annotation from class " + m_className);
+            throw new IllegalArgumentException("Invalid timeout value " + t + " in ServiceDependency
annotation from class " + m_currentClassName);
         }
         
         // required attribute (not valid if parsing a temporal service dependency)
@@ -648,6 +747,8 @@ public class AnnotationCollector extends
      */
     private void parseConfigurationDependencyAnnotation(Annotation annotation)
     {
+        checkDependencyAlreadyDeclaredInChild(annotation, m_method, true);
+
         EntryWriter writer = new EntryWriter(EntryType.ConfigurationDependency);
         m_writers.add(writer);
 
@@ -699,7 +800,7 @@ public class AnnotationCollector extends
             }
             else 
             {
-                pid = m_className;
+                pid = m_componentClassName;
             }
         }
 
@@ -730,9 +831,6 @@ public class AnnotationCollector extends
         EntryWriter writer = new EntryWriter(EntryType.AspectService);
         m_writers.add(writer);
 
-        // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addCommonServiceParams(writer);
-
         // Parse service filter
         String filter = annotation.get(EntryParam.filter.toString());
         if (filter != null)
@@ -746,7 +844,7 @@ public class AnnotationCollector extends
         writer.put(EntryParam.ranking, ranking.toString());
 
         // Generate Aspect Implementation
-        writer.put(EntryParam.impl, m_className);
+        writer.put(EntryParam.impl, m_componentClassName);
 
         // Parse Aspect properties.
         parseProperties(annotation, writer);
@@ -761,13 +859,13 @@ public class AnnotationCollector extends
             if (m_interfaces == null)
             {
                 throw new IllegalStateException("Invalid AspectService annotation: " +
-                    "the service attribute has not been set and the class " + m_className
+                    "the service attribute has not been set and the class " + m_componentClassName
                     + " does not implement any interfaces");
             }
             if (m_interfaces.length != 1)
             {
                 throw new IllegalStateException("Invalid AspectService annotation: " +
-                    "the service attribute has not been set and the class " + m_className
+                    "the service attribute has not been set and the class " + m_componentClassName
                     + " implements more than one interface");
             }
 
@@ -793,7 +891,7 @@ public class AnnotationCollector extends
         // "field" and "added/changed/removed/swap" attributes can't be mixed
         if (field != null && (added != null || changed != null || removed != null
|| swap != null))
         {
-            throw new IllegalStateException("Annotation " + annotation + "can't applied on
" + m_className
+            throw new IllegalStateException("Annotation " + annotation + "can't applied on
" + m_componentClassName
                     + " can't mix \"field\" attribute with \"added/changed/removed\" attributes");
         }
                 
@@ -816,11 +914,8 @@ public class AnnotationCollector extends
         EntryWriter writer = new EntryWriter(EntryType.AdapterService);
         m_writers.add(writer);
 
-        // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addCommonServiceParams(writer);
-
         // Generate Adapter Implementation
-        writer.put(EntryParam.impl, m_className);
+        writer.put(EntryParam.impl, m_componentClassName);
 
         // Parse adaptee filter
         String adapteeFilter = annotation.get(EntryParam.adapteeFilter.toString());
@@ -862,11 +957,8 @@ public class AnnotationCollector extends
         EntryWriter writer = new EntryWriter(EntryType.BundleAdapterService);
         m_writers.add(writer);
 
-        // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addCommonServiceParams(writer);
-
         // Generate Adapter Implementation
-        writer.put(EntryParam.impl, m_className);
+        writer.put(EntryParam.impl, m_componentClassName);
 
         // Parse bundle filter
         String filter = annotation.get(EntryParam.filter.toString());
@@ -905,11 +997,8 @@ public class AnnotationCollector extends
         EntryWriter writer = new EntryWriter(EntryType.ResourceAdapterService);
         m_writers.add(writer);
 
-        // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addCommonServiceParams(writer);
-
         // Generate Adapter Implementation
-        writer.put(EntryParam.impl, m_className);
+        writer.put(EntryParam.impl, m_componentClassName);
 
         // Parse resource filter
         String filter = annotation.get(EntryParam.filter.toString());
@@ -944,11 +1033,8 @@ public class AnnotationCollector extends
         EntryWriter writer = new EntryWriter(EntryType.FactoryConfigurationAdapterService);
         m_writers.add(writer);
 
-        // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addCommonServiceParams(writer);
-
         // Generate Adapter Implementation
-        writer.put(EntryParam.impl, m_className);
+        writer.put(EntryParam.impl, m_componentClassName);
 
         // factory pid attribute (can be specified using the factoryPid attribute, or using
the factoryPidClass attribute)
         String factoryPidClass = parseClassAttrValue(annotation.get(EntryParam.factoryPidClass.toString()));
@@ -964,7 +1050,7 @@ public class AnnotationCollector extends
         
         factoryPid = get(annotation, EntryParam.factoryPid.toString(), factoryPidClass);
         if (factoryPid == null) {
-            factoryPid = configType != null ? configType : m_className;
+            factoryPid = configType != null ? configType : m_componentClassName;
         }
         
         writer.put(EntryParam.factoryPid, factoryPid);
@@ -993,6 +1079,8 @@ public class AnnotationCollector extends
 
     private void parseBundleDependencyAnnotation(Annotation annotation)
     {
+        checkDependencyAlreadyDeclaredInChild(annotation, m_method, true);
+
         EntryWriter writer = new EntryWriter(EntryType.BundleDependency);
         m_writers.add(writer);
 
@@ -1014,6 +1102,8 @@ public class AnnotationCollector extends
 
     private void parseRersourceDependencyAnnotation(Annotation annotation)
     {
+        checkDependencyAlreadyDeclaredInChild(annotation, ! m_isField ? m_method : m_field,
! m_isField);
+
         EntryWriter writer = new EntryWriter(EntryType.ResourceDependency);
         m_writers.add(writer);
 
@@ -1050,7 +1140,7 @@ public class AnnotationCollector extends
         {
             if(! m_dependencyNames.add(name))
             {
-                throw new IllegalArgumentException("Duplicate dependency name " + name +
" in Dependency " + annotation + " from class " + m_className);
+                throw new IllegalArgumentException("Duplicate dependency name " + name +
" in Dependency " + annotation + " from class " + m_currentClassName);
             }
             writer.put(EntryParam.name, name);
         }
@@ -1063,13 +1153,13 @@ public class AnnotationCollector extends
         {
             if (m_starter != null) {
                 throw new IllegalStateException("Lifecycle annotation already defined on
field " + 
-                                                m_starter + " in class " + m_className);
+                                                m_starter + " in class (or super class of)
" + m_componentClassName);
             }
             m_starter = m_field;
         } else {
             if (m_stopper != null) {
                 throw new IllegalStateException("Lifecycle annotation already defined on
field " + 
-                                                m_stopper + " in class " + m_className);
+                                                m_stopper + " in class (or super class of)
" + m_componentClassName);
             }
             m_stopper = m_field;
         }
@@ -1114,7 +1204,7 @@ public class AnnotationCollector extends
                 {
                     throw new IllegalArgumentException("invalid option labels/values specified
for property "
                         + id +
-                        " in PropertyMetadata annotation from class " + m_className);
+                        " in PropertyMetadata annotation from class " + m_currentClassName);
                 }
 
                 if (optionValues != null)
@@ -1131,7 +1221,7 @@ public class AnnotationCollector extends
             m_metaType.add(ocd);
             MetaType.Designate designate = new MetaType.Designate(pid, factory);
             m_metaType.add(designate);
-            m_logger.info("Parsed MetaType Properties from class " + m_className);
+            m_logger.info("Parsed MetaType Properties from class " + m_componentClassName);
         }
     }
 
@@ -1198,7 +1288,7 @@ public class AnnotationCollector extends
             {
                 // Theorically impossible
                 throw new IllegalArgumentException("Invalid Property type " + type
-                    + " from annotation " + property + " in class " + m_className);
+                    + " from annotation " + property + " in class " + m_componentClassName);
             }
 
             Object[] values;
@@ -1248,7 +1338,7 @@ public class AnnotationCollector extends
             else
             {
                 throw new IllegalArgumentException(
-                    "Missing Property value from annotation " + property + " in class " +
m_className);
+                    "Missing Property value from annotation " + property + " in class " +
m_componentClassName);
             }
 
             if (properties.length() > 0) {
@@ -1257,7 +1347,7 @@ public class AnnotationCollector extends
         }
         catch (JSONException e)
         {
-            throw new IllegalArgumentException("Unexpected exception while parsing Property
from class " + m_className, e);
+            throw new IllegalArgumentException("Unexpected exception while parsing Property
from class " + m_componentClassName, e);
         }
     }
 
@@ -1279,7 +1369,7 @@ public class AnnotationCollector extends
                 try {
                     Long.valueOf(value.toString());
                 } catch (NumberFormatException e) {
-                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_className
+                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_componentClassName
                         + " does not contain a valid Long value (" + value.toString() + ")");
                 }
             }
@@ -1288,7 +1378,7 @@ public class AnnotationCollector extends
                 try {
                     Double.valueOf(value.toString());
                 } catch (NumberFormatException e) {
-                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_className
+                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_componentClassName
                         + " does not contain a valid Double value (" + value.toString() +
")");
                 }
             }
@@ -1297,7 +1387,7 @@ public class AnnotationCollector extends
                 try {
                     Float.valueOf(value.toString());
                 } catch (NumberFormatException e) {
-                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_className
+                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_componentClassName
                         + " does not contain a valid Float value (" + value.toString() +
")");
                 }
             }
@@ -1306,7 +1396,7 @@ public class AnnotationCollector extends
                 try {
                     Integer.valueOf(value.toString());
                 } catch (NumberFormatException e) {
-                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_className
+                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_componentClassName
                         + " does not contain a valid Integer value (" + value.toString()
+ ")");
                 }
             }
@@ -1315,7 +1405,7 @@ public class AnnotationCollector extends
                 try {
                     Byte.valueOf(value.toString());
                 } catch (NumberFormatException e) {
-                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_className
+                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_componentClassName
                         + " does not contain a valid Byte value (" + value.toString() + ")");
                 }
             }
@@ -1333,7 +1423,7 @@ public class AnnotationCollector extends
                     if (values[i].toString().length() != 1)
                     {
                         throw new IllegalArgumentException("Property \"" + name + "\" in
class "
-                            + m_className + " does not contain a valid Character value ("
+ values[i] + ")");
+                            + m_componentClassName + " does not contain a valid Character
value (" + values[i] + ")");
                     }
                     try
                     {
@@ -1342,7 +1432,7 @@ public class AnnotationCollector extends
                     catch (NumberFormatException e2)
                     {
                         throw new IllegalArgumentException("Property \"" + name + "\" in
class "
-                            + m_className + " does not contain a valid Character value ("
+ values[i].toString()
+                            + m_componentClassName + " does not contain a valid Character
value (" + values[i].toString()
                             + ")");
                     }
                 }
@@ -1350,7 +1440,7 @@ public class AnnotationCollector extends
         } else if (type.equals(Boolean.class)) {
             for (Object value : values) {
                 if (! value.toString().equalsIgnoreCase("false") && ! value.toString().equalsIgnoreCase("true"))
{
-                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_className
+                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_componentClassName
                         + " does not contain a valid Boolean value (" + value.toString()
+ ")");
                 }
             }
@@ -1359,7 +1449,7 @@ public class AnnotationCollector extends
                 try {
                     Short.valueOf(value.toString());
                 } catch (NumberFormatException e) {
-                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_className
+                    throw new IllegalArgumentException("Property \"" + name + "\" in class
" + m_componentClassName
                         + " does not contain a valid Short value (" + value.toString() +
")");
                 }
             }
@@ -1408,20 +1498,29 @@ public class AnnotationCollector extends
     {      
         if (Patterns.BUNDLE_CONTEXT.matcher(m_descriptor).matches())
         {
+            if (m_bundleContextField != null) {
+                throw new IllegalStateException("detected multiple @Inject annotation from
class " + m_currentClassName + " (on from child classes)");
+            }
             m_bundleContextField = m_field;
         }
         else if (Patterns.DEPENDENCY_MANAGER.matcher(m_descriptor).matches())
         {
+            if (m_dependencyManagerField != null) {
+                throw new IllegalStateException("detected multiple @Inject annotation from
class " + m_currentClassName + " (on from child classes)");
+            }
             m_dependencyManagerField = m_field;
         }
         else if (Patterns.COMPONENT.matcher(m_descriptor).matches())
         {
+            if (m_componentField != null) {
+                throw new IllegalStateException("detected multiple @Inject annotation from
class " + m_currentClassName + " (on from child classes)");
+            }
             m_componentField = m_field;
         }
         else
         {
             throw new IllegalArgumentException("@Inject annotation can't be applied on the
field \"" + m_field
-                                               + "\" in class " + m_className);
+                                               + "\" in class " + m_currentClassName);
         }
     }
     
@@ -1434,14 +1533,14 @@ public class AnnotationCollector extends
         if (m_registeredMethod != null)
         {
             throw new IllegalStateException("@Registered annotation can't be used on a Component
" +
-                                            " which does not provide a service (class=" +
m_className + ")");
+                                            " which does not provide a service (class=" +
m_currentClassName + ")");
 
         }
         
         if (m_unregisteredMethod != null)
         {
             throw new IllegalStateException("@Unregistered annotation can't be used on a
Component " +
-                                            " which does not provide a service (class=" +
m_className + ")");
+                                            " which does not provide a service (class=" +
m_currentClassName + ")");
 
         }
     }

Modified: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationPlugin.java?rev=1761367&r1=1761366&r2=1761367&view=diff
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationPlugin.java
(original)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationPlugin.java
Sun Sep 18 22:04:20 2016
@@ -18,8 +18,6 @@
  */
 package org.apache.felix.dm.annotation.plugin.bnd;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
 import java.util.Map;
 import java.util.Set;
 
@@ -115,7 +113,7 @@ public class AnnotationPlugin implements
         }
 
         catch (Throwable t) {
-            m_logger.error(parse(t));
+            m_logger.error("error: " + t.toString(), t);
         }
 
         finally {
@@ -165,16 +163,4 @@ public class AnnotationPlugin implements
             analyzer.setProperty(REQUIRE_CAPABILITY, sb.toString());
         }
     }
-
-    /**
-     * Parse an exception into a string.
-     * @param e The exception to parse
-     * @return the parsed exception
-     */
-    private static String parse(Throwable e) {
-        StringWriter buffer = new StringWriter();
-        PrintWriter pw = new PrintWriter(buffer);
-        e.printStackTrace(pw);
-        return (buffer.toString());
-    }
 }

Modified: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/DescriptorGenerator.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/DescriptorGenerator.java?rev=1761367&r1=1761366&r2=1761367&view=diff
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/DescriptorGenerator.java
(original)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/DescriptorGenerator.java
Sun Sep 18 22:04:20 2016
@@ -33,6 +33,7 @@ import aQute.bnd.osgi.Clazz;
 import aQute.bnd.osgi.EmbeddedResource;
 import aQute.bnd.osgi.Resource;
 import aQute.bnd.osgi.Clazz.QUERY;
+import aQute.bnd.osgi.Descriptors.TypeRef;
 
 /**
  * This helper parses all classes which contain DM annotations, and generates the corresponding
component descriptors.
@@ -103,9 +104,28 @@ public class DescriptorGenerator
             
         for (Clazz c : expanded)
         {
-            // Let's parse all annotations from that class !
             AnnotationCollector reader = new AnnotationCollector(m_logger, metaType);
+            reader.baseClass(true);
+            m_logger.debug("scanning class %s", c.getClassName());
             c.parseClassFileWithCollector(reader);
+
+            // parse inherited annotations.
+            while (reader.getSuperClass() != null) {
+            	Clazz superClazz = m_analyzer.findClass(reader.getSuperClass());
+            	if (superClazz == null) {
+            		m_logger.error("Can't find super class %s from %s", reader.getSuperClass(),
c.getClassName());
+            		break;
+            	}
+            	if (isObject(reader.getSuperClass()) || isScalaObject(reader.getSuperClass()))
{
+            		/* don't scan java.lang.Object or scala object ! */
+            		break;
+            	}
+
+            	m_logger.debug("scanning super class %s for class %s", reader.getSuperClass(),
c.getClassName());
+            	reader.baseClass(false);
+            	superClazz.parseClassFileWithCollector(reader);				
+            }
+
             if (reader.finish())
             {
                 // And store the generated component descriptors in our resource list.
@@ -127,7 +147,7 @@ public class DescriptorGenerator
         return annotationsFound;
     }
 
-    /**
+	/**
      * Returns the path of the descriptor.
      * @return the path of the generated descriptors.
      */
@@ -179,6 +199,20 @@ public class DescriptorGenerator
     {
         return m_exportService;
     }    
+    
+    /**
+     * Tests if a given type is java.lang.Object
+     */
+    private boolean isObject(TypeRef typeRef) {
+    	return (typeRef.isJava());
+	}
+    
+    /**
+     * Tests if a given type is scala object.
+     */
+    private boolean isScalaObject(TypeRef typeRef) {
+    	return (typeRef.getBinary().equals("scala/ScalaObject"));
+    }
 
     /**
      * Creates a bnd resource that contains the generated dm descriptor.

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime.itest/src/org/apache/felix/dm/runtime/itest/components/InheritedAnnotations.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime.itest/src/org/apache/felix/dm/runtime/itest/components/InheritedAnnotations.java?rev=1761367&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime.itest/src/org/apache/felix/dm/runtime/itest/components/InheritedAnnotations.java
(added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime.itest/src/org/apache/felix/dm/runtime/itest/components/InheritedAnnotations.java
Sun Sep 18 22:04:20 2016
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.runtime.itest.components;
+
+import org.apache.felix.dm.annotation.api.Component;
+import org.apache.felix.dm.annotation.api.Init;
+import org.apache.felix.dm.annotation.api.ServiceDependency;
+import org.apache.felix.dm.annotation.api.Start;
+import org.apache.felix.dm.itest.util.Ensure;
+import org.junit.Assert;
+
+public class InheritedAnnotations
+{
+    public final static String ENSURE = "InheritedAnnotations";
+    
+    @Component(provides=Service1.class)
+    public static class Service1 {       
+        @ServiceDependency(filter="(name=" + ENSURE + ")")
+        Ensure m_ensure;
+
+    }
+    
+    @Component(provides=Service2.class)
+    public static class Service2 {
+        @ServiceDependency(filter="(name=" + ENSURE + ")")
+        Ensure m_ensure;
+    }
+    
+    public static class Base {
+        @ServiceDependency(filter="(name=" + ENSURE + ")")
+        protected Ensure m_ensure;
+        
+        protected Service1 m_s1;
+        
+        @ServiceDependency
+        void bind(Service1 s1) {
+            m_s1 = s1;
+        }
+
+        @Init
+        void init() {
+            Assert.assertNotNull(m_ensure);
+            Assert.assertNotNull(m_s1);
+            m_ensure.step(1);
+        }
+    }
+    
+    @Component
+    public static class Child extends Base {
+        private Service2 m_s2;
+
+        @ServiceDependency
+        void bind(Service2 s2) { 
+            m_s2 = s2;
+        }
+
+        @Start
+        void start() {    
+            Assert.assertNotNull(m_ensure);
+            Assert.assertNotNull(m_s1);
+            Assert.assertNotNull(m_s2);
+            m_ensure.step(2);
+        }        
+    }
+
+}

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime.itest/src/org/apache/felix/dm/runtime/itest/tests/InheritedAnnotationsTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime.itest/src/org/apache/felix/dm/runtime/itest/tests/InheritedAnnotationsTest.java?rev=1761367&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime.itest/src/org/apache/felix/dm/runtime/itest/tests/InheritedAnnotationsTest.java
(added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime.itest/src/org/apache/felix/dm/runtime/itest/tests/InheritedAnnotationsTest.java
Sun Sep 18 22:04:20 2016
@@ -0,0 +1,41 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+package org.apache.felix.dm.runtime.itest.tests;
+
+import org.apache.felix.dm.itest.util.Ensure;
+import org.apache.felix.dm.itest.util.TestBase;
+import org.apache.felix.dm.runtime.itest.components.InheritedAnnotations;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Use case: Verify if a component may inherit from annotations defined in inherited classes.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class InheritedAnnotationsTest extends TestBase {
+    
+    public void testInheritedAnnotation() throws Throwable {
+        Ensure e = new Ensure();
+        ServiceRegistration sr = register(e, InheritedAnnotations.ENSURE);
+        e.ensure();
+        e.waitForStep(2, 5000);
+        sr.unregister();
+    }
+    
+}




Mime
View raw message