You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2014/10/18 01:00:55 UTC

svn commit: r1632688 - in /felix/sandbox/pderop/dependencymanager-prototype: org.apache.felix.dependencymanager.itest/src/org/apache/felix/dm/itest/ org.apache.felix.dependencymanager/src/org/apache/felix/dm/ org.apache.felix.dependencymanager/src/org/...

Author: pderop
Date: Fri Oct 17 23:00:55 2014
New Revision: 1632688

URL: http://svn.apache.org/r1632688
Log:
FELIX-4672: Allow callbacks to third party instance for adapters.

Added:
    felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager.itest/src/org/apache/felix/dm/itest/AdapterWithCallbackInstanceTest.java
Modified:
    felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyActivatorBase.java
    felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
    felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/AdapterServiceImpl.java
    felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FieldUtil.java

Added: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager.itest/src/org/apache/felix/dm/itest/AdapterWithCallbackInstanceTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager.itest/src/org/apache/felix/dm/itest/AdapterWithCallbackInstanceTest.java?rev=1632688&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager.itest/src/org/apache/felix/dm/itest/AdapterWithCallbackInstanceTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager.itest/src/org/apache/felix/dm/itest/AdapterWithCallbackInstanceTest.java Fri Oct 17 23:00:55 2014
@@ -0,0 +1,142 @@
+/*
+ * 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.itest;
+
+import java.util.Map;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+
+public class AdapterWithCallbackInstanceTest extends TestBase {
+    
+    public void testServiceWithAdapterAndConsumer() {
+        DependencyManager m = getDM();
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+
+        Component provider = m.createComponent()
+            .setInterface(OriginalService.class.getName(), null)
+            .setImplementation(new ServiceProvider(e));
+
+        Component consumer = m.createComponent()
+            .setImplementation(new ServiceConsumer(e))
+            .add(m.createServiceDependency()
+                .setService(AdaptedService.class)
+                .setRequired(true)
+            );
+
+        ServiceAdapterCallbackInstance callbackInstance = new ServiceAdapterCallbackInstance(e);
+        Component adapter = m.createAdapterService(OriginalService.class, null, "m_originalService", callbackInstance, "set", "changed","unset", null)
+            .setInterface(AdaptedService.class.getName(), null)
+            .setImplementation(new ServiceAdapter(e));
+        
+        // add the provider and the adapter
+        m.add(provider);
+        m.add(adapter);
+        // Checks if the callbackInstances is called, and if the adapter start method is called
+        e.waitForStep(2, 5000);
+        
+        // add a consumer that will invoke the adapter
+        // which will in turn invoke the original provider
+        m.add(consumer);
+        // now validate that both have been invoked in the right order
+        e.waitForStep(4, 5000);
+        // remove the provider again
+        m.remove(provider);
+        // ensure that the consumer is stopped
+        e.waitForStep(5, 5000);
+        // remove adapter and consumer
+        m.remove(adapter);
+        m.remove(consumer);
+    }
+
+    static interface OriginalService {
+        public void invoke();
+    }
+    
+    static interface AdaptedService {
+        public void invoke();
+    }
+    
+    static class ServiceProvider implements OriginalService {
+        private final Ensure m_ensure;
+        public ServiceProvider(Ensure e) {
+            m_ensure = e;
+        }
+        public void invoke() {
+            m_ensure.step(4);
+        }
+    }
+    
+    public static class ServiceAdapter implements AdaptedService {
+        private volatile OriginalService m_originalService;
+        private final Ensure m_ensure;
+        
+        public String toString() {
+            return "XX: ServiceAdapter";
+        }
+        
+        public ServiceAdapter(Ensure e) {
+            m_ensure = e;
+        }
+
+        public void start() { System.out.println("start"); m_ensure.step(2); }
+        public void stop() { System.out.println("stop"); }
+        public void invoke() {
+            m_originalService.invoke();
+        }
+    }
+
+    public static class ServiceAdapterCallbackInstance {
+        private final Ensure m_ensure;
+        public ServiceAdapterCallbackInstance(Ensure e) {
+            m_ensure = e;
+        }
+        
+        public void set(OriginalService m_originalService) {
+            m_ensure.step(1);
+        }
+        
+        public void changed(Map<String, String> props, OriginalService m_originalService) {            
+            m_ensure.step();
+        }
+        
+        public void unset(Map<String, String> props, OriginalService m_originalService) {            
+            m_ensure.step();
+        }
+    }
+
+    static class ServiceConsumer {
+        private volatile AdaptedService m_service;
+        private final Ensure m_ensure;
+        
+        public ServiceConsumer(Ensure e) {
+            m_ensure = e;
+        }
+        public void start() {
+            m_ensure.step(3);
+            m_service.invoke();
+        }
+        public void stop() {
+            m_ensure.step(5);
+        }
+    }
+}
+
+

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyActivatorBase.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyActivatorBase.java?rev=1632688&r1=1632687&r2=1632688&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyActivatorBase.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyActivatorBase.java Fri Oct 17 23:00:55 2014
@@ -18,6 +18,7 @@
  */
 package org.apache.felix.dm;
 
+import org.apache.felix.dm.impl.AdapterServiceImpl;
 import org.apache.felix.dm.impl.Logger;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
@@ -262,6 +263,16 @@ public abstract class DependencyActivato
     }  
     
     /**
+     * Creates a new adapter service.
+     * @return the adapter service
+     * @see DependencyManager#createAdapterService(Class, String, String, Object, String, String, String, String)
+     */
+   public Component createAdapterService(Class<?> serviceInterface, String serviceFilter, 
+        String autoConfig, Object callbackInstance, String add, String change, String remove, String swap) {
+       return m_manager.createAdapterService(serviceInterface, serviceFilter, autoConfig, callbackInstance, add, change, remove, swap);
+    }
+
+    /**
      * Creates a new resource adapter service.
      * 
      * @return the resource adapter service

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java?rev=1632688&r1=1632687&r2=1632688&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java Fri Oct 17 23:00:55 2014
@@ -258,6 +258,31 @@ public class DependencyManager {
      * <h3>Usage Example</h3>
      * 
      * <blockquote><pre>
+     * manager.createAdapterService(AdapteeService.class, "(foo=bar)")
+     *     .setInterface(AdapterService.class, new Hashtable() {{ put("extra", "property"); }})
+     *     .setImplementation(AdapterImpl.class);
+     * </pre></blockquote>
+     * 
+     * @param serviceInterface the service interface to apply the adapter to
+     * @param serviceFilter the filter condition to use with the service interface
+     * @return a service that acts as a factory for generating adapters
+     */
+    public Component createAdapterService(Class<?> serviceInterface, String serviceFilter) {
+        return new AdapterServiceImpl(this, serviceInterface, serviceFilter, null, null, null, null, null, null);
+    }
+
+    /**
+     * Creates a new adapter. The adapter will be applied to any service that
+     * matches the specified interface and filter. For each matching service
+     * 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 service 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.
+     * 
+     * <h3>Usage Example</h3>
+     * 
+     * <blockquote><pre>
      * manager.createAdapterService(AdapteeService.class, "(foo=bar)", "m_service")
      *     .setInterface(AdapterService.class, new Hashtable() {{ put("extra", "property"); }})
      *     .setImplementation(AdapterImpl.class);
@@ -269,7 +294,7 @@ public class DependencyManager {
      * @return a service that acts as a factory for generating adapters
      */
     public Component createAdapterService(Class<?> serviceInterface, String serviceFilter, String autoConfig) {
-        return new AdapterServiceImpl(this, serviceInterface, serviceFilter, autoConfig, null, null, null);
+        return new AdapterServiceImpl(this, serviceInterface, serviceFilter, autoConfig, null, null, null, null, null);
     }
 
     /**
@@ -284,17 +309,23 @@ public class DependencyManager {
      * <h3>Usage Example</h3>
      * 
      * <blockquote><pre>
-     * manager.createAdapterService(AdapteeService.class, "(foo=bar)")
+     * manager.createAdapterService(AdapteeService.class, "(foo=bar)", "add", "change", "remove")
      *     .setInterface(AdapterService.class, new Hashtable() {{ put("extra", "property"); }})
      *     .setImplementation(AdapterImpl.class);
      * </pre></blockquote>
      * 
      * @param serviceInterface the service interface to apply the adapter to
      * @param serviceFilter the filter condition to use with the service interface
+     * @param add name of the callback method to invoke on add
+     * @param change name of the callback method to invoke on change
+     * @param remove name of the callback method to invoke on remove
+     * @param swap name of the callback method to invoke on swap
      * @return a service that acts as a factory for generating adapters
      */
-    public Component createAdapterService(Class<?> serviceInterface, String serviceFilter) {
-        return new AdapterServiceImpl(this, serviceInterface, serviceFilter, null, null, null, null);
+    public Component createAdapterService(Class<?> serviceInterface, String serviceFilter, String add, String change,
+        String remove)
+    {
+        return new AdapterServiceImpl(this, serviceInterface, serviceFilter, null, null, add, change, remove, null);
     }
 
     /**
@@ -325,7 +356,7 @@ public class DependencyManager {
     public Component createAdapterService(Class<?> serviceInterface, String serviceFilter, String add, String change,
         String remove, String swap)
     {
-        return new AdapterServiceImpl(this, serviceInterface, serviceFilter, null, add, change, remove, swap);
+        return new AdapterServiceImpl(this, serviceInterface, serviceFilter, null, null, add, change, remove, swap);
     }
 
     /**
@@ -340,23 +371,25 @@ public class DependencyManager {
      * <h3>Usage Example</h3>
      * 
      * <blockquote><pre>
-     * manager.createAdapterService(AdapteeService.class, "(foo=bar)", "add", "change", "remove")
+     * manager.createAdapterService(AdapteeService.class, "(foo=bar)", "add", "change", "remove", "swap")
      *     .setInterface(AdapterService.class, new Hashtable() {{ put("extra", "property"); }})
      *     .setImplementation(AdapterImpl.class);
      * </pre></blockquote>
      * 
      * @param serviceInterface the service interface to apply the adapter to
      * @param serviceFilter the filter condition to use with the service interface
+     * @param autoConfig the name of the member to inject the service into, or null.
+     * @param callbackInstance the instance to invoke the callbacks on, or null if the callbacks have to be invoked on the adapter itself
      * @param add name of the callback method to invoke on add
      * @param change name of the callback method to invoke on change
      * @param remove name of the callback method to invoke on remove
      * @param swap name of the callback method to invoke on swap
      * @return a service that acts as a factory for generating adapters
      */
-    public Component createAdapterService(Class<?> serviceInterface, String serviceFilter, String add, String change,
-        String remove)
+    public Component createAdapterService(Class<?> serviceInterface, String serviceFilter, 
+        String autoConfig, Object callbackInstance, String add, String change, String remove, String swap)
     {
-        return new AdapterServiceImpl(this, serviceInterface, serviceFilter, null, add, change, remove);
+        return new AdapterServiceImpl(this, serviceInterface, serviceFilter, autoConfig, callbackInstance, add, change, remove, swap);
     }
 
     /**

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/AdapterServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/AdapterServiceImpl.java?rev=1632688&r1=1632687&r2=1632688&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/AdapterServiceImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/AdapterServiceImpl.java Fri Oct 17 23:00:55 2014
@@ -45,43 +45,40 @@ public class AdapterServiceImpl extends 
      * @param dm the dependency manager used to create our internal adapter service
      * @param adapteeInterface the service interface to apply the adapter to
      * @param adapteeFilter the filter condition to use with the service interface
-     * @param add
-     * @param change
-     * @param remove
+     * @param autoConfig the name of the member to inject the service into
+     * @param callbackInstance the instance to invoke the callback on, or null 
+     * @param add name of the callback method to invoke on add
+     * @param change name of the callback method to invoke on change
+     * @param remove name of the callback method to invoke on remove
+     * @param swap name of the callback method to invoke on swap
      */
-    public AdapterServiceImpl(DependencyManager dm, Class<?> adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove, String swap) {
+    public AdapterServiceImpl(DependencyManager dm, Class<?> adapteeInterface, String adapteeFilter, String autoConfig, 
+        Object callbackInstance, String add, String change, String remove, String swap)
+    {
         super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
-        m_component.setImplementation(new AdapterImpl(adapteeInterface, adapteeFilter, autoConfig, add, change, remove, swap))
+        m_component.setImplementation(new AdapterImpl(adapteeInterface, adapteeFilter, autoConfig, callbackInstance, add, change, remove, swap))
                  .add(dm.createServiceDependency()
                       .setService(adapteeInterface, adapteeFilter)
                       .setAutoConfig(false)
                       .setCallbacks("added", null, "removed", "swapped"))
                  .setCallbacks("init", null, "stop", null);
     }	
-	
-    public AdapterServiceImpl(DependencyManager dm, Class<?> adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove) {
-        super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
-        m_component.setImplementation(new AdapterImpl(adapteeInterface, adapteeFilter, autoConfig, add, change, remove, null))
-                 .add(dm.createServiceDependency()
-                      .setService(adapteeInterface, adapteeFilter)
-                      .setAutoConfig(false)
-                      .setCallbacks("added", null, "removed", "swapped"))
-                 .setCallbacks("init", null, "stop", null);
-    }
-    
+	    
     public class AdapterImpl extends AbstractDecorator {
         private final Class<?> m_adapteeInterface;
         private final String m_adapteeFilter;
+        private final Object m_dependencyCallbackInstance;
         private final String m_add;
         private final String m_change;
         private final String m_remove;
         private final String m_swap;
         private final String m_autoConfig;
         
-        public AdapterImpl(Class<?> adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove, String swap) {
+        public AdapterImpl(Class<?> adapteeInterface, String adapteeFilter, String autoConfig, Object callbackInstance, String add, String change, String remove, String swap) {
             m_adapteeInterface = adapteeInterface;
             m_adapteeFilter = adapteeFilter;
             m_autoConfig = autoConfig;
+            m_dependencyCallbackInstance = callbackInstance;
             m_add = add;
             m_change = change;
             m_swap = swap;
@@ -99,11 +96,14 @@ public class AdapterServiceImpl extends 
             	 .setService(m_adapteeInterface, "(|(" + Constants.SERVICE_ID + "=" + serviceIdToTrack 
             			 	+ ")(" + DependencyManager.ASPECT + "=" + serviceIdToTrack + "))")
                  .setRequired(true);
+            if (m_add != null || m_change != null || m_remove != null || m_swap != null) {
+                dependency.setCallbacks(m_dependencyCallbackInstance, m_add, m_change, m_remove, m_swap);
+            }
             if (m_autoConfig != null) {
                 dependency.setAutoConfig(m_autoConfig);
-            }
-            if (m_add != null || m_change != null || m_remove != null || m_swap != null) {
-                dependency.setCallbacks(m_add, m_change, m_remove, m_swap);
+            } else {
+                // enable auto configuration if there is no add callback or if there is one on a callbackInstance
+                dependency.setAutoConfig(m_add == null || (m_add != null && m_dependencyCallbackInstance != null));
             }
             dependency.setPropagate(this, "propagateAdapteeProperties");
             

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FieldUtil.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FieldUtil.java?rev=1632688&r1=1632687&r2=1632688&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FieldUtil.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FieldUtil.java Fri Oct 17 23:00:55 2014
@@ -275,10 +275,18 @@ public class FieldUtil {
     private static boolean mayInjectToMap(Class<?> clazz, Field field, boolean strictClassEquality) {
         Class<?> fieldType = field.getType();
         if (Map.class.isAssignableFrom(fieldType)) {
+            if (! (field.getGenericType() instanceof ParameterizedType)) {
+                return false;
+            }
             ParameterizedType parameterType = (ParameterizedType) field.getGenericType();
             if (parameterType == null) {
                 return false;
             }
+            
+            if (! (parameterType.getActualTypeArguments()[0] instanceof Class<?>) ||
+                ! (parameterType.getActualTypeArguments()[1] instanceof Class<?>)) {
+                return false;
+            }
             Class<?> K = (Class<?>) parameterType.getActualTypeArguments()[0];
             Class<?> V = (Class<?>) parameterType.getActualTypeArguments()[1];