added ResourceAdapter and ResourceDependency annotations.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@919863 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/ResourceAdapterService.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/ResourceAdapterService.java
new file mode 100644
index 0000000..cd6c689
--- /dev/null
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/ResourceAdapterService.java
@@ -0,0 +1,58 @@
+/*
+ * 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.annotation.api;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a class as a Resource Adapter Service. The adapter will be applied to any resource 
+ * that matches the specified filter condition. For each matching resource
+ * an adapter will be created based on the adapter implementation class.
+ * The adapter will be registered with the specified interface and existing properties
+ * from the original resource plus any extra properties you supply here.
+ * It will also inherit all dependencies, and if you declare the original
+ * service as a member it will be injected.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface ResourceAdapterService
+{
+    /**
+     * The filter condition to use with the resource.
+     */
+    String filter();
+
+    /**
+     * The interface to use when registering adapters
+     */
+    Class<?> service() default Object.class;
+
+    /**
+     * Additional properties to use with the adapter service registration
+     */
+    Param[] properties() default {};
+
+    /**
+     * <code>true</code> if properties from the resource should be propagated to the service.
+     */
+    boolean propagate() default false;
+}
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/ResourceDependency.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/ResourceDependency.java
new file mode 100644
index 0000000..c4d2823
--- /dev/null
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/ResourceDependency.java
@@ -0,0 +1,64 @@
+/*
+ * 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.annotation.api;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.METHOD, ElementType.FIELD})
+public @interface ResourceDependency
+{
+    /**
+     * Returns the callback method to be invoked when the service is available. This attribute is only meaningful when 
+     * the annotation is applied on a class field.
+     */
+    String added() default "";
+
+    /**
+     * Returns the callback method to be invoked when the service properties have changed.
+     */
+    String changed() default "";
+
+    /**
+     * Returns the callback method to invoke when the service is lost.
+     */
+    String removed() default "";
+
+    /**
+     * Returns whether the Service dependency is required or not.
+     * @return true if the dependency is required, false if not.
+     */
+    boolean required() default true;
+    
+    /**
+     * Returns the Service dependency OSGi filter.
+     * @return The Service dependency filter.
+     */
+    String filter() default "";
+
+    /**
+     * TODO add comments for this method.
+     * @param propagate
+     * @return
+     */
+    boolean propagate() default false;
+}
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
index db8754d..bf47e81 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
@@ -38,6 +38,8 @@
 import org.apache.felix.dm.annotation.api.Destroy;
 import org.apache.felix.dm.annotation.api.Init;
 import org.apache.felix.dm.annotation.api.Properties;
+import org.apache.felix.dm.annotation.api.ResourceAdapterService;
+import org.apache.felix.dm.annotation.api.ResourceDependency;
 import org.apache.felix.dm.annotation.api.Service;
 import org.apache.felix.dm.annotation.api.ServiceDependency;
 import org.apache.felix.dm.annotation.api.Start;
@@ -72,6 +74,8 @@
         + TemporalServiceDependency.class.getName().replace('.', '/') + ";";
     private final static String A_BUNDLE_DEPENDENCY = "L"
         + BundleDependency.class.getName().replace('.', '/') + ";";
+    private final static String A_RESOURCE_DEPENDENCY = "L"
+        + ResourceDependency.class.getName().replace('.', '/') + ";";
     private final static String A_PROPERTIES = "L"
         + Properties.class.getName().replace('.', '/') + ";";
     private final static String A_ASPECT_SERVICE = "L"
@@ -80,6 +84,8 @@
         + AdapterService.class.getName().replace('.', '/') + ";";
     private final static String A_BUNDLE_ADAPTER_SERVICE = "L"
         + BundleAdapterService.class.getName().replace('.', '/') + ";";
+    private final static String A_RESOURCE_ADAPTER_SERVICE = "L"
+        + ResourceAdapterService.class.getName().replace('.', '/') + ";";
 
     private Reporter m_reporter;
     private String m_className;
@@ -97,8 +103,8 @@
     private String m_destroyMethod;
     private String m_compositionMethod;
 
-    // Pattern used to parse the class parameter from the bind methods ("bind(Type)" or "bind(Map, Type)")
-    private final static Pattern m_bindClassPattern = Pattern.compile("\\((Ljava/util/Map;)?L([^;]+);\\)V");
+    // Pattern used to parse the class parameter from the bind methods ("bind(Type)" or "bind(Map, Type)" or "bind(BundleContext, Type)"
+    private final static Pattern m_bindClassPattern = Pattern.compile("\\((L[^;]+;)?L([^;]+);\\)V");
 
     // Pattern used to parse classes from class descriptors;
     private final static Pattern m_classPattern = Pattern.compile("L([^;]+);");
@@ -116,10 +122,12 @@
         AspectService,
         AdapterService,
         BundleAdapterService,
+        ResourceAdapterService,
         ServiceDependency, 
         TemporalServiceDependency, 
         ConfigurationDependency,
         BundleDependency,
+        ResourceDependency
     };
 
     // List of component descriptor parameters
@@ -375,6 +383,10 @@
         {
             parseBundleAdapterService(annotation);
         }
+        else if (annotation.getName().equals(A_RESOURCE_ADAPTER_SERVICE))
+        {
+            parseResourceAdapterService(annotation);
+        }
         else if (annotation.getName().equals(A_INIT))
         {
             checkMethod(m_voidMethodPattern);
@@ -420,6 +432,10 @@
         {
             parseBundleDependencyAnnotation(annotation);
         }
+        else if (annotation.getName().equals(A_RESOURCE_DEPENDENCY)) 
+        {
+            parseRersourceDependencyAnnotation(annotation);
+        }
     }
 
     /**
@@ -432,7 +448,7 @@
         m_infos.add(info);
 
         // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addInitStartStopDestroyCompositionParams(info);
+        addCommonServiceParams(info);
         
         // impl attribute
         info.addParam(Params.impl, m_className);
@@ -450,7 +466,7 @@
         info.addParam(annotation, Params.factoryMethod, null);
     }
 
-    private void addInitStartStopDestroyCompositionParams(Info info)
+    private void addCommonServiceParams(Info info)
     {
         if (m_initMethod != null) {
             info.addParam(Params.init, m_initMethod);
@@ -608,7 +624,7 @@
         m_infos.add(info);        
 
         // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addInitStartStopDestroyCompositionParams(info);
+        addCommonServiceParams(info);
         
         // factory attribute
         info.addClassParam(annotation, Params.factory, null);
@@ -665,7 +681,7 @@
         m_infos.add(info);
         
         // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addInitStartStopDestroyCompositionParams(info);
+        addCommonServiceParams(info);
         
         // Generate Adapter Implementation
         info.addParam(Params.impl, m_className);
@@ -718,7 +734,7 @@
         m_infos.add(info);
         
         // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addInitStartStopDestroyCompositionParams(info);
+        addCommonServiceParams(info);
         
         // Generate Adapter Implementation
         info.addParam(Params.impl, m_className);
@@ -764,6 +780,59 @@
         info.addParam(annotation, Params.propagate, Boolean.FALSE);
     }
 
+    /**
+     * Parses a BundleAdapterService annotation.
+     * @param annotation
+     */
+    private void parseResourceAdapterService(Annotation annotation)
+    {
+        Info info = new Info(EntryTypes.ResourceAdapterService);
+        m_infos.add(info);
+        
+        // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
+        addCommonServiceParams(info);
+        
+        // Generate Adapter Implementation
+        info.addParam(Params.impl, m_className);
+      
+        // Parse resource filter
+        String filter = annotation.get(Params.filter.toString());
+        if (filter != null)
+        {
+            Verifier.verifyFilter(filter, 0);
+            info.addParam(Params.filter, filter);
+        }
+                
+        // Parse Adapter properties.
+        parseParameters(annotation, Params.properties, info);
+
+        // Parse the optional adapter service (use directly implemented interface by default).
+        Object service = annotation.get(Params.service.toString());
+        if (service == null) {
+            if (m_interfaces == null)
+            {
+                throw new IllegalStateException("Invalid ResourceAdapterService annotation: " +
+                    "the service attribute has not been set and the class " + m_className + 
+                    " does not implement any interfaces");
+            }
+            if (m_interfaces.length != 1) 
+            {
+                throw new IllegalStateException("Invalid ResourceAdapterService annotation: " +
+                    "the service attribute has not been set and the class " + m_className +
+                    " implements more than one interface");
+            }
+            
+            info.addParam(Params.service, m_interfaces[0]);
+        } else 
+        {
+            checkClassImplements(annotation, Params.service);
+            info.addClassParam(annotation, Params.service, null);
+        }
+        
+        // Parse propagate attribute
+        info.addParam(annotation, Params.propagate, Boolean.FALSE);
+    }
+
     private void parseBundleDependencyAnnotation(Annotation annotation)
     {
         Info info = new Info(EntryTypes.BundleDependency);
@@ -784,6 +853,25 @@
         info.addParam(annotation, Params.propagate, null);
     }
     
+    private void parseRersourceDependencyAnnotation(Annotation annotation)
+    {
+        Info info = new Info(EntryTypes.ResourceDependency);
+        m_infos.add(info);
+
+        String filter = annotation.get(Params.filter.toString());
+        if (filter != null)
+        {
+            Verifier.verifyFilter(filter, 0);
+            info.addParam(Params.filter, filter);
+        }
+
+        info.addParam(annotation, Params.added, m_method);
+        info.addParam(annotation, Params.changed, null); // TODO check if "changed" callback exists
+        info.addParam(annotation, Params.removed, null); // TODO check if "removed" callback exists
+        info.addParam(annotation, Params.required, null);
+        info.addParam(annotation, Params.propagate, null);        
+    }
+
     /**
      * Checks if an annotation attribute references an implemented interface. 
      * @param annotation the parsed annotation
@@ -920,7 +1008,8 @@
         }
 
         // We must have at least a Service or an AspectService annotation.
-        checkServiceDeclared(EntryTypes.Service, EntryTypes.AspectService, EntryTypes.AdapterService, EntryTypes.BundleAdapterService);
+        checkServiceDeclared(EntryTypes.Service, EntryTypes.AspectService, EntryTypes.AdapterService, EntryTypes.BundleAdapterService,
+            EntryTypes.ResourceAdapterService);
 
         StringBuilder sb = new StringBuilder();
         sb.append("Parsed annotation for class ");