felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From clem...@apache.org
Subject svn commit: r1523996 - in /felix/trunk/ipojo/runtime: core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apa...
Date Tue, 17 Sep 2013 12:07:10 GMT
Author: clement
Date: Tue Sep 17 12:07:09 2013
New Revision: 1523996

URL: http://svn.apache.org/r1523996
Log:
Fix FELIX-4231 Provide service binding interceptors

Added:
    felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/EnhancingBindingInterceptor.java
    felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/ProxyBindingInterceptor.java
    felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Enhanced.java
    felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestBindingInterceptors.java
      - copied, changed from r1523544, felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestTransformingServices.java
    felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceBindingInterceptor.java
      - copied, changed from r1523570, felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceTrackingInterceptor.java
Modified:
    felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooConsumer.java
    felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
    felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ServiceReferenceManager.java
    felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceRankingInterceptor.java
    felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceTrackingInterceptor.java
    felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
    felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java
    felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java

Modified: felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooConsumer.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooConsumer.java?rev=1523996&r1=1523995&r2=1523996&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooConsumer.java (original)
+++ felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooConsumer.java Tue Sep 17 12:07:09 2013
@@ -21,8 +21,10 @@ package org.apache.felix.ipojo.runtime.c
 
 import org.apache.felix.ipojo.annotations.*;
 import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.Enhanced;
 import org.apache.felix.ipojo.runtime.core.test.services.FooService;
 
+import java.util.Dictionary;
 import java.util.Map;
 import java.util.Properties;
 
@@ -33,21 +35,24 @@ import java.util.Properties;
 @Provides
 public class FooConsumer implements CheckService {
 
-    @Requires(id= "foo", policy = "dynamic-priority")
+    @Requires(id= "foo", policy = "dynamic-priority", proxy = false)
     private FooService foo;
 
     private Map<String, Object> props;
 
     @Override
     public boolean check() {
-        return foo != null;
+        return foo.foo();
     }
 
     @Override
-    public Properties getProps() {
+    public Dictionary getProps() {
         Properties properties =  new Properties();
         properties.put("props", props);
         properties.put("grade", foo.getGrade());
+        if (foo instanceof Enhanced) {
+            properties.put("enhanced", ((Enhanced) foo).enhance());
+        }
         return properties;
     }
 

Added: felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/EnhancingBindingInterceptor.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/EnhancingBindingInterceptor.java?rev=1523996&view=auto
==============================================================================
--- felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/EnhancingBindingInterceptor.java (added)
+++ felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/EnhancingBindingInterceptor.java Tue Sep 17 12:07:09 2013
@@ -0,0 +1,77 @@
+/*
+ * 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.ipojo.runtime.core.test.interceptors;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.dependency.interceptors.DefaultDependencyInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceBindingInterceptor;
+import org.apache.felix.ipojo.runtime.core.test.services.Enhanced;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.ServiceReference;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.HashMap;
+
+/**
+ * A binding interceptor enhancing the service object.
+ */
+@Component(immediate = true)
+@Provides
+public class EnhancingBindingInterceptor extends DefaultDependencyInterceptor implements ServiceBindingInterceptor {
+
+    @ServiceProperty
+    private String target;
+
+    private HashMap<ServiceReference, Object> deps = new HashMap<ServiceReference, Object>();
+
+    @Override
+    public <S> S getService(DependencyModel dependency, ServiceReference<S> reference, S service) {
+        S proxy =  (S) Proxy.newProxyInstance(this.getClass().getClassLoader(),
+                new Class[]{dependency.getSpecification(), Enhanced.class}, new Interceptor(service));
+        deps.put(reference, proxy);
+        return proxy;
+    }
+
+    @Override
+    public <S> void ungetService(DependencyModel dependency, ServiceReference<S> reference) {
+        deps.remove(reference);
+    }
+
+    private class Interceptor implements InvocationHandler {
+
+        private final Object service;
+
+        public Interceptor(Object service) {
+            this.service = service;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            if (method.getName().equals("enhance")) {
+                return "yo!";
+            }
+            return method.invoke(service, args);
+        }
+    }
+}

Added: felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/ProxyBindingInterceptor.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/ProxyBindingInterceptor.java?rev=1523996&view=auto
==============================================================================
--- felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/ProxyBindingInterceptor.java (added)
+++ felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/ProxyBindingInterceptor.java Tue Sep 17 12:07:09 2013
@@ -0,0 +1,100 @@
+/*
+ * 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.ipojo.runtime.core.test.interceptors;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.dependency.interceptors.DefaultDependencyInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceBindingInterceptor;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.ServiceReference;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.*;
+
+/**
+ * A binding interceptor generating a proxy to monitor the invocations.
+ */
+@Component
+@Provides
+public class ProxyBindingInterceptor extends DefaultDependencyInterceptor implements ServiceBindingInterceptor, CheckService {
+
+    @ServiceProperty
+    private String target;
+
+    private HashMap<ServiceReference, Object> deps = new HashMap<ServiceReference, Object>();
+    private Dictionary data = new Hashtable();
+
+
+    private void increment(String key) {
+        if (data.get(key) == null) {
+            data.put(key, 1);
+        } else {
+            data.put(key, (Integer) data.get(key) + 1);
+        }
+    }
+
+    @Override
+    public <S> S getService(DependencyModel dependency, ServiceReference<S> reference, S service) {
+        S proxy =  (S) Proxy.newProxyInstance(this.getClass().getClassLoader(),
+                new Class[]{dependency.getSpecification()}, new Interceptor(service));
+        deps.put(reference, proxy);
+        increment("bound");
+        return proxy;
+    }
+
+    @Override
+    public <S> void ungetService(DependencyModel dependency, ServiceReference<S> reference) {
+        deps.remove(reference);
+        increment("unbound");
+    }
+
+    @Override
+    public boolean check() {
+        return true;
+    }
+
+    @Override
+    public Dictionary getProps() {
+        return data;
+    }
+
+    private class Interceptor implements InvocationHandler {
+
+        private final Object service;
+
+        public Interceptor(Object service) {
+            this.service = service;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            increment(method.getName());
+
+            if (method.getName().equals("toString")) {
+                return this.toString();
+            }
+            return method.invoke(service, args);
+        }
+    }
+}

Modified: felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java?rev=1523996&r1=1523995&r2=1523996&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java (original)
+++ felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java Tue Sep 17 12:07:09 2013
@@ -19,7 +19,7 @@
 
 package org.apache.felix.ipojo.runtime.core.test.services;
 
-import java.util.Properties;
+import java.util.Dictionary;
 
 public interface CheckService {
     
@@ -27,6 +27,6 @@ public interface CheckService {
 	
 	public boolean check();
 	
-	public Properties getProps();
+	public Dictionary getProps();
 
 }

Added: felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Enhanced.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Enhanced.java?rev=1523996&view=auto
==============================================================================
--- felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Enhanced.java (added)
+++ felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Enhanced.java Tue Sep 17 12:07:09 2013
@@ -0,0 +1,27 @@
+/*
+ * 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.ipojo.runtime.core.test.services;
+
+/**
+ * An interface added on the fly to the service object.
+ */
+public interface Enhanced {
+
+    public String enhance();
+}

Copied: felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestBindingInterceptors.java (from r1523544, felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestTransformingServices.java)
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestBindingInterceptors.java?p2=felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestBindingInterceptors.java&p1=felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestTransformingServices.java&r1=1523544&r2=1523996&rev=1523996&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestTransformingServices.java (original)
+++ felix/trunk/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestBindingInterceptors.java Tue Sep 17 12:07:09 2013
@@ -23,16 +23,16 @@ import org.apache.felix.ipojo.ComponentI
 import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
 import org.junit.Before;
 import org.junit.Test;
+import org.osgi.framework.ServiceReference;
 
-import java.util.Map;
 import java.util.Properties;
 
 import static org.fest.assertions.Assertions.assertThat;
 
 /**
- * Checks Tracking interceptor transforming services
+ * Checks binding interceptors.
  */
-public class TestTransformingServices extends Common {
+public class TestBindingInterceptors extends Common {
 
     private ComponentInstance provider;
 
@@ -43,135 +43,135 @@ public class TestTransformingServices ex
     }
 
     @Test
-    public void testTransformationOfFoo() {
+    public void testProxyBindingInterceptorBeforeInstanceCreation() {
         // Create the interceptor
         Properties configuration = new Properties();
         configuration.put("target", "(dependency.id=foo)");
         ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
-                ".AddLocationTrackingInterceptor", configuration);
+                ".ProxyBindingInterceptor", configuration);
 
         // Create the FooConsumer
-        ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.components.FooConsumer");
+        ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+                ".components" +
+                ".FooConsumer");
+
+        ServiceReference ref = osgiHelper.waitForService(CheckService.class.getName(),
+                "(instance.name=" + instance.getInstanceName() + ")",
+                1000, true);
+        CheckService check = (CheckService) osgiHelper.getServiceObject(ref);
 
-        osgiHelper.waitForService(CheckService.class.getName(), null, 1000, true);
-        CheckService check = osgiHelper.getServiceObject(CheckService.class);
         assertThat(check.check());
-        @SuppressWarnings("unchecked") Map<String, ?> props = (Map<String, ?>) check.getProps().get("props");
-        assertThat(props.get("location")).isEqualTo("kitchen");
-        assertThat(props.get("hidden")).isNull();
+
+        // Extract monitored data
+        CheckService checkService = osgiHelper.getServiceObject(CheckService.class,
+                "(factory.name=org.apache.felix.ipojo.runtime.core.test.interceptors.ProxyBindingInterceptor)");
+
+        assertThat(checkService).isNotNull();
+        assertThat(checkService.getProps().get("bound")).isEqualTo(1);
+        assertThat(checkService.getProps().get("foo")).isEqualTo(1);
+
+        provider.dispose();
+
+        assertThat(checkService.getProps().get("bound")).isEqualTo(1);
+        assertThat(checkService.getProps().get("unbound")).isEqualTo(1);
     }
 
     /**
      * Same as previous but the interceptor arrives after the instance.
      */
     @Test
-    public void testDelayedTransformationOfFoo() {
+    public void testProxyBindingInterceptorAfterInstanceCreation() {
         // Create the FooConsumer
-        ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.components" +
+        ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+                ".components" +
                 ".FooConsumer");
 
-        osgiHelper.waitForService(CheckService.class.getName(), null, 1000, true);
-        CheckService check = osgiHelper.getServiceObject(CheckService.class);
+        ServiceReference ref = osgiHelper.waitForService(CheckService.class.getName(),
+                "(instance.name=" + instance.getInstanceName() + ")",
+                1000, true);
+        CheckService check = (CheckService) osgiHelper.getServiceObject(ref);
+
         assertThat(check.check());
-        @SuppressWarnings("unchecked") Map<String, ?> props = (Map<String, ?>) check.getProps().get("props");
-        assertThat(props.get("location")).isNull();
-        assertThat(props.get("hidden")).isNotNull();
 
         // Create the interceptor
         Properties configuration = new Properties();
         configuration.put("target", "(dependency.id=foo)");
         ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
-                ".AddLocationTrackingInterceptor", configuration);
-
-        assertThat(check.check());
-        props = (Map<String, ?>) check.getProps().get("props");
-        assertThat(props.get("location")).isEqualTo("kitchen");
-        assertThat(props.get("hidden")).isNull();
-    }
-
-    /**
-     * The interceptor makes the instance valid.
-     */
-    @Test
-    public void testTransformationMakingFilterMatch() {
-        // Create the FooConsumer
-        Properties configuration = new Properties();
-        Properties filters = new Properties();
-        filters.put("foo", "(location=kitchen)");
-        configuration.put("requires.filters", filters);
-        ComponentInstance consumer = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
-                ".components.FooConsumer", configuration);
+                ".ProxyBindingInterceptor", configuration);
 
-        // Invalid instance
-        assertThat(consumer.getInstanceDescription().getState()).isEqualTo(ComponentInstance.INVALID);
+        // Extract monitored data
+        CheckService checkService = osgiHelper.getServiceObject(CheckService.class,
+                "(factory.name=org.apache.felix.ipojo.runtime.core.test.interceptors.ProxyBindingInterceptor)");
+
+        // Nothing was intercepted.
+        assertThat(checkService).isNotNull();
+        assertThat(checkService.getProps().get("bound")).isNull();
+        assertThat(checkService.getProps().get("foo")).isNull();
+
+        // Force rebinding.
+        provider.stop();
+        provider.start();
+
+        check.check();
+
+        // Things should have been intercepted
+        assertThat(checkService).isNotNull();
+        assertThat(checkService.getProps().get("bound")).isEqualTo(1);
+        assertThat(checkService.getProps().get("foo")).isEqualTo(1);
 
-        // Create the interceptor
-        Properties config = new Properties();
-        config.put("target", "(dependency.id=foo)");
-        ComponentInstance interceptor = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
-                ".interceptors.AddLocationTrackingInterceptor", config);
-
-        assertThat(consumer.getInstanceDescription().getState()).isEqualTo(ComponentInstance.VALID);
-
-        CheckService check = osgiHelper.getServiceObject(CheckService.class);
+        provider.dispose();
 
-        assertThat(check.check());
-        Map<String, ?> props = (Map<String, ?>) check.getProps().get("props");
-        assertThat(props.get("location")).isEqualTo("kitchen");
-        assertThat(props.get("hidden")).isNull();
-
-        // Removing the interceptor should revert to the base set.
-        interceptor.dispose();
-        System.out.println(consumer.getInstanceDescription().getDescription());
-        assertThat(consumer.getInstanceDescription().getState()).isEqualTo(ComponentInstance.INVALID);
+        // Two unget calls, as we intercepted the first one (provider.stop()).
+        assertThat(checkService.getProps().get("unbound")).isEqualTo(2);
     }
 
     /**
-     * Checks the behavior when services arrives and leaves.
+     * Checks that two interceptors are called sequentially.
      */
     @Test
-    public void testTransformationOfDynamicFoo() {
+    public void testWithTwoInterceptors() {
+        // First, only one interceptor.
+
         // Create the interceptor
         Properties configuration = new Properties();
         configuration.put("target", "(dependency.id=foo)");
         ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
-                ".AddLocationTrackingInterceptor", configuration);
+                ".ProxyBindingInterceptor", configuration);
 
-        // Create the FooConsumer
-        ComponentInstance consumer = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
-                ".components.FooConsumer");
 
-        osgiHelper.waitForService(CheckService.class.getName(), null, 1000, true);
-        CheckService check = osgiHelper.getServiceObject(CheckService.class);
-        assertThat(check.check());
-        @SuppressWarnings("unchecked") Map<String, ?> props = (Map<String, ?>) check.getProps().get("props");
-        assertThat(props.get("location")).isEqualTo("kitchen");
-        assertThat(props.get("hidden")).isNull();
+        // Create the FooConsumer
+        ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+                ".components" +
+                ".FooConsumer");
 
-        // Create another provider
-        ComponentInstance provider2 = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
-                ".components.FooProvider");
+        ServiceReference ref = osgiHelper.waitForService(CheckService.class.getName(),
+                "(instance.name=" + instance.getInstanceName() + ")",
+                1000, true);
+        CheckService check = (CheckService) osgiHelper.getServiceObject(ref);
 
-        check = osgiHelper.getServiceObject(CheckService.class);
         assertThat(check.check());
-        props = (Map<String, ?>) check.getProps().get("props");
-        assertThat(props.get("location")).isEqualTo("kitchen");
-        assertThat(props.get("hidden")).isNull();
 
-        // Provider 1 leaves
-        provider.dispose();
+        // Create the second interceptor, but it's too late to modify the first binding.
+        configuration = new Properties();
+        configuration.put("target", "(dependency.id=foo)");
+        ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+                ".EnhancingBindingInterceptor", configuration);
 
-        // The second provider is also transformed.
-        check = osgiHelper.getServiceObject(CheckService.class);
-        assertThat(check.check());
-        props = (Map<String, ?>) check.getProps().get("props");
-        assertThat(props.get("location")).isEqualTo("kitchen");
-        assertThat(props.get("hidden")).isNull();
+        assertThat(check.getProps().get("enhanced")).isNull();
 
-        provider2.dispose();
+        // Extract monitored data
+        CheckService checkService = osgiHelper.getServiceObject(CheckService.class,
+                "(factory.name=org.apache.felix.ipojo.runtime.core.test.interceptors.ProxyBindingInterceptor)");
 
-        System.out.println(consumer.getInstanceDescription().getDescription());
+        assertThat(checkService).isNotNull();
+        assertThat(checkService.getProps().get("bound")).isEqualTo(1);
+        assertThat(checkService.getProps().get("foo")).isEqualTo(1);
 
-        assertThat(consumer.getState()).isEqualTo(ComponentInstance.INVALID);
+        // Force re-binding.
+        provider.stop();
+        provider.start();
+
+        assertThat(check.getProps().get("enhanced")).isNotNull();
     }
+
 }

Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ServiceReferenceManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ServiceReferenceManager.java?rev=1523996&r1=1523995&r2=1523996&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ServiceReferenceManager.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ServiceReferenceManager.java Tue Sep 17 12:07:09 2013
@@ -20,6 +20,7 @@
 package org.apache.felix.ipojo.dependency.impl;
 
 import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceBindingInterceptor;
 import org.apache.felix.ipojo.dependency.interceptors.ServiceRankingInterceptor;
 import org.apache.felix.ipojo.dependency.interceptors.ServiceTrackingInterceptor;
 import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference;
@@ -71,10 +72,20 @@ public class ServiceReferenceManager imp
      */
     private ServiceRankingInterceptor m_rankingInterceptor;
     /**
-     * Service interceptor tracker.
+     * Service Ranking Interceptor trackers.
      */
     private Tracker m_rankingInterceptorTracker;
+
+    /**
+     * Service Tracking Interceptor trackers.
+     */
     private Tracker m_trackingInterceptorTracker;
+
+    /**
+     * Service Binding Interceptor trackers.
+     */
+    private Tracker m_bindingInterceptorTracker;
+
     /**
      * The set of tracking interceptors.
      * TODO this set should be sorted according to the OSGi ranking policy.
@@ -84,6 +95,13 @@ public class ServiceReferenceManager imp
             LinkedList<ServiceTrackingInterceptor>();
 
     /**
+     * The set of binding interceptors.
+     * TODO this set should be sorted according to the OSGi ranking policy.
+     */
+    private LinkedList<ServiceBindingInterceptor> m_bindingInterceptors = new
+            LinkedList<ServiceBindingInterceptor>();
+
+    /**
      * Creates the service reference manager.
      *
      * @param dep        the dependency
@@ -191,6 +209,42 @@ public class ServiceReferenceManager imp
                     }
                 });
         m_rankingInterceptorTracker.open();
+
+        m_bindingInterceptorTracker = new Tracker(m_dependency.getBundleContext(),
+                ServiceBindingInterceptor.class.getName(),
+                new TrackerCustomizer() {
+
+                    public boolean addingService(ServiceReference reference) {
+                        return DependencyProperties.match(reference, m_dependency);
+                    }
+
+                    public void addedService(ServiceReference reference) {
+                        ServiceBindingInterceptor interceptor = (ServiceBindingInterceptor) m_bindingInterceptorTracker
+                                .getService(reference);
+                        if (interceptor != null) {
+                            addBindingInterceptor(interceptor);
+                        } else {
+                            m_dependency.getComponentInstance().getFactory().getLogger().log(Log.ERROR,
+                                    "Cannot retrieve the interceptor object from service reference " + reference
+                                            .getProperty(Constants.SERVICE_ID) + " - " + reference.getProperty
+                                            (Factory.INSTANCE_NAME_PROPERTY));
+                        }
+                    }
+
+                    public void modifiedService(ServiceReference reference, Object service) {
+                        // Not supported.
+                    }
+
+                    public void removedService(ServiceReference reference, Object service) {
+                        if (service != null && service instanceof ServiceBindingInterceptor &&
+                                m_bindingInterceptors.contains(service)
+                                ) {
+                            removeBindingInterceptor((ServiceBindingInterceptor) service);
+                        }
+                    }
+                }
+        );
+        m_bindingInterceptorTracker.open();
     }
 
     private void addTrackingInterceptor(ServiceTrackingInterceptor interceptor) {
@@ -220,6 +274,53 @@ public class ServiceReferenceManager imp
         m_dependency.onChange(changeset);
     }
 
+    private void addBindingInterceptor(ServiceBindingInterceptor interceptor) {
+        // A new interceptor arrives, open it.
+        // Binding interceptor cannot modify existing bindings.
+        try {
+            m_dependency.acquireWriteLockIfNotHeld();
+            m_bindingInterceptors.add(interceptor);
+            interceptor.open(m_dependency);
+        } finally {
+            m_dependency.releaseWriteLockIfHeld();
+        }
+    }
+
+    private void removeBindingInterceptor(ServiceBindingInterceptor interceptor) {
+        try {
+            m_dependency.acquireWriteLockIfNotHeld();
+            m_bindingInterceptors.remove(interceptor);
+            interceptor.close(m_dependency);
+        } finally {
+            m_dependency.releaseWriteLockIfHeld();
+        }
+    }
+
+    public Object weavingServiceBinding(DependencyModel.ServiceBindingHolder sbh) {
+        Object svc = sbh.service;
+        try {
+            m_dependency.acquireReadLockIfNotHeld();
+            for (ServiceBindingInterceptor interceptor : m_bindingInterceptors) {
+                // Interceptor are not allowed to return null.
+                svc = interceptor.getService(m_dependency, sbh.reference, svc);
+            }
+        } finally {
+            m_dependency.releaseReadLockIfHeld();
+        }
+        return svc;
+    }
+
+    public void unweavingServiceBinding(DependencyModel.ServiceBindingHolder sbh) {
+        try {
+            m_dependency.acquireReadLockIfNotHeld();
+            for (ServiceBindingInterceptor interceptor : m_bindingInterceptors) {
+                interceptor.ungetService(m_dependency, sbh.reference);
+            }
+        } finally {
+            m_dependency.releaseReadLockIfHeld();
+        }
+    }
+
     private ChangeSet computeChangesInMatchingServices() {
         if (m_dependency.getTracker() == null || m_dependency.getTracker().getServiceReferences() == null) {
             // Tracker closed, no problem

Copied: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceBindingInterceptor.java (from r1523570, felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceTrackingInterceptor.java)
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceBindingInterceptor.java?p2=felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceBindingInterceptor.java&p1=felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceTrackingInterceptor.java&r1=1523570&r2=1523996&rev=1523996&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceTrackingInterceptor.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceBindingInterceptor.java Tue Sep 17 12:07:09 2013
@@ -24,38 +24,47 @@ import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 
 /**
- * A service to influence the visibility of services within a service dependency.
- * This service is called to determine which services from the tracker (base set) is going to the matching set.
+ * A service to modify / monitor the service bindings.
+ * This service is notified every time the dependency is weaving a new service bindings on un-weaves an existing one.
  *
- * Several tracking interceptors can be plugged to the same service dependency. In this case,
- * a chain is created where all interceptor can influence the next one. If the dependency has a filter,
- * a tracking interceptor using this filter is the last interceptor of the chain.
+ * Several binding interceptors can be plugged to the same service dependency. In this case,
+ * a chain is created where all interceptor are called in a sequence.
  *
- * Obviously an interceptor can be plugged to several interceptors.
+ * A binding interceptor cannot modify the existing bindings.
+ *
+ * Obviously an interceptor can be plugged to several dependencies.
+ *
+ * @since 1.10.2
  */
-public interface ServiceTrackingInterceptor extends DependencyInterceptor {
+public interface ServiceBindingInterceptor extends DependencyInterceptor {
 
     /**
-     * Does the interceptor accepts the reference of not ?
-     * This methods has two goals. It can filter out undesirable services by returning {@literal null}. In addition,
-     * it can <em>transform</em> the service reference to add / remove service properties. In this case,
-     * it must return the <strong>same</strong> instance of {@link TransformedServiceReference},
-     * but with the new set of properties.
+     * Notification method when a dependency is weaving a new service binding.
+     * The interceptor can modify the service object. It must <strong>never</strong> return a {@code null} object,
+     * but the receive service object if it does not want to do anything with the service object.
      *
-     * So to filter out the service, return {@literal null}. To accept the service,
-     * return the reference as it is. To transform the service update the service reference and return it.
+     * When the interceptor <em>modifies</em> the service object, the returned object <strong>must</strong> be
+     * compatible with the dependency specification.
      *
-     * When several interceptors are collaborating on the same dependency, a chain is created. The received reference
-     * is the reference modified by the preceding interceptor. Notice that once an interceptor returns {@literal
-     * null} the chain is interrupted and the service rejected.
+     * The received service object may already have been <em>wrapped</em> by binding interceptors called before the
+     * current one.
+     *
+     * @param dependency the dependency
+     * @param reference the service reference bound
+     * @param service the service object
+     * @param <S> the service specification
+     * @return the service object to be injected within the component. Must never be {@code null}.
+     */
+    public <S> S getService(DependencyModel dependency, ServiceReference<S> reference, S service);
+
+    /**
+     * Notification method when a dependency is un-weaving a service binding.
+     * The interceptor must released all objects related to this service binding.
      *
      * @param dependency the dependency
-     * @param context the context of the dependency
-     * @param ref the reference
-     * @param <S> the type of service
-     * @return {@literal null} to filter out the service, the, optionally updated, reference to accept it.
+     * @param reference the unbound service reference
+     * @param <S> the service specification
      */
-    public <S> TransformedServiceReference<S> accept(DependencyModel dependency, BundleContext context,
-                                                     TransformedServiceReference<S> ref);
+    public <S> void ungetService(DependencyModel dependency, ServiceReference<S> reference);
 
 }

Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceRankingInterceptor.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceRankingInterceptor.java?rev=1523996&r1=1523995&r2=1523996&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceRankingInterceptor.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceRankingInterceptor.java Tue Sep 17 12:07:09 2013
@@ -31,6 +31,8 @@ import java.util.List;
  *
  * This interceptors is called to compute the selected set of services from the matching set,
  * i.e. the set of services that matching the filter (actually accepted by the tracking interceptors).
+ *
+ * @since 1.10.1
  */
 public interface ServiceRankingInterceptor extends DependencyInterceptor {
 

Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceTrackingInterceptor.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceTrackingInterceptor.java?rev=1523996&r1=1523995&r2=1523996&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceTrackingInterceptor.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceTrackingInterceptor.java Tue Sep 17 12:07:09 2013
@@ -31,7 +31,10 @@ import org.osgi.framework.ServiceReferen
  * a chain is created where all interceptor can influence the next one. If the dependency has a filter,
  * a tracking interceptor using this filter is the last interceptor of the chain.
  *
- * Obviously an interceptor can be plugged to several interceptors.
+ * Obviously an interceptor can be plugged to several dependencies. Conversely, several tracking interceptor can be
+ * plugged to one dependency.
+ *
+ * @since 1.10.1
  */
 public interface ServiceTrackingInterceptor extends DependencyInterceptor {
 

Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java?rev=1523996&r1=1523995&r2=1523996&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java Tue Sep 17 12:07:09 2013
@@ -697,7 +697,7 @@ public class Dependency extends Dependen
                     } else {
                         //  Use a reflective construction to avoid class cast exception. This method allows setting the component type.
                         Object[] objs = (Object[]) Array.newInstance(getSpecification(), refs.length);
-                        for (int i = 0; refs != null && i < refs.length; i++) {
+                        for (int i = 0; i < refs.length; i++) {
                             ServiceReference ref = refs[i];
                             objs[i] = getService(ref);
                         }

Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java?rev=1523996&r1=1523995&r2=1523996&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java Tue Sep 17 12:07:09 2013
@@ -18,9 +18,6 @@
  */
 package org.apache.felix.ipojo.handlers.dependency;
 
-import java.util.Iterator;
-import java.util.List;
-
 import org.apache.felix.ipojo.Factory;
 import org.apache.felix.ipojo.architecture.HandlerDescription;
 import org.apache.felix.ipojo.metadata.Attribute;
@@ -29,6 +26,8 @@ import org.apache.felix.ipojo.util.Depen
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 
+import java.util.List;
+
 /**
  * Dependency Handler Description.
  * 
@@ -40,26 +39,6 @@ public class DependencyHandlerDescriptio
      * Dependencies managed by the dependency handler.
      */
     private DependencyDescription[] m_dependencies = new DependencyDescription[0];
-    
-    // TODO Define the DependencyStateListener Interface (in ipojo utils)
-    
-    // TODO Add the list of listener.
-    
-    // TODO Add register listener method.
-    
-    // TODO Add unregister listener method.
-    
-    // TODO Implement the validate method.
-    
-    // TODO Implement the invalidate method.
-    
-    // TODO Implement the onServiceArrival method.
-    
-    // TODO Implement the onServiceDeparture method.
-    
-    // TODO Implement the onServiceBound method.
-    
-    // TODO Implement the onServiceUnbound method.
 
     /**
      * Creates the Dependency Handler description.
@@ -71,7 +50,6 @@ public class DependencyHandlerDescriptio
         m_dependencies = new DependencyDescription[deps.length];
         for (int i = 0; i < m_dependencies.length; i++) {
             m_dependencies[i] = new DependencyDescription(deps[i]);
-            //TODO Register callback there on the dependency model.
         }
     }
 

Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java?rev=1523996&r1=1523995&r2=1523996&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java Tue Sep 17 12:07:09 2013
@@ -128,7 +128,7 @@ public abstract class DependencyModel {
      * This map stores service object, and so is able to handle
      * iPOJO custom policies.
      */
-    private Map<ServiceReference, Object> m_serviceObjects = new HashMap<ServiceReference, Object>();
+    private Map<ServiceReference, ServiceBindingHolder> m_serviceObjects = new HashMap<ServiceReference, ServiceBindingHolder>();
     /**
      * The current list of bound services.
      */
@@ -269,15 +269,16 @@ public abstract class DependencyModel {
      * The method is called while holding the exclusive lock.
      */
     private void ungetAllServices() {
-        for (Map.Entry<ServiceReference, Object> entry : m_serviceObjects.entrySet()) {
+        for (Map.Entry<ServiceReference, ServiceBindingHolder> entry : m_serviceObjects.entrySet()) {
             ServiceReference ref = entry.getKey();
-            Object svc = entry.getValue();
+            ServiceBindingHolder sbh = entry.getValue();
             if (m_tracker != null) {
                 m_tracker.ungetService(ref);
             }
-            if (svc instanceof IPOJOServiceFactory) {
-                ((IPOJOServiceFactory) svc).ungetService(m_instance, svc);
+            if (sbh.factory != null) {
+                sbh.factory.ungetService(m_instance, sbh.service);
             }
+            m_serviceReferenceManager.unweavingServiceBinding(sbh);
         }
         m_serviceObjects.clear();
     }
@@ -790,12 +791,12 @@ public abstract class DependencyModel {
             for (ServiceReference ref : arrivals) {
                 onServiceArrival(ref);
                 // Notify service binding to listeners
-                notifyListeners(DependencyEventType.BINDING, ref, m_serviceObjects.get(ref));
+                notifyListeners(DependencyEventType.BINDING, ref, m_serviceObjects.get(ref).service);
             }
             for (ServiceReference ref : departures) {
                 onServiceDeparture(ref);
                 // Notify service unbinding to listeners
-                notifyListeners(DependencyEventType.UNBINDING, ref, m_serviceObjects.get(ref));
+                notifyListeners(DependencyEventType.UNBINDING, ref, m_serviceObjects.get(ref).service);
             }
         } finally {
             releaseReadLockIfHeld();
@@ -912,6 +913,12 @@ public abstract class DependencyModel {
             return null;
         }
 
+        // If we already have the service object, just return it.
+        if (m_serviceObjects.containsKey(ref)) {
+            return m_serviceObjects.get(ref).service;
+        }
+
+        ServiceBindingHolder holder = null;
         Object svc = m_tracker.getService(ref);
         IPOJOServiceFactory factory = null;
 
@@ -919,20 +926,23 @@ public abstract class DependencyModel {
             factory = (IPOJOServiceFactory) svc;
             svc = factory.getService(m_instance);
         }
+        holder = new ServiceBindingHolder(ref, factory, svc);
+
+        svc = m_serviceReferenceManager.weavingServiceBinding(holder);
 
         if (store) {
             try {
                 acquireWriteLockIfNotHeld();
-                if (factory != null) {
-                    m_serviceObjects.put(ref, factory);
+                // The service object may have been modified by the interceptor, update the holder
+                if (svc != holder.service) {
+                    m_serviceObjects.put(ref, new ServiceBindingHolder(ref, factory, svc));
                 } else {
-                    m_serviceObjects.put(ref, svc);
+                    m_serviceObjects.put(ref, holder);
                 }
             } finally {
                 releaseWriteLockIfHeld();
             }
         }
-
         return svc;
     }
 
@@ -943,18 +953,21 @@ public abstract class DependencyModel {
      */
     public void ungetService(ServiceReference ref) {
         m_tracker.ungetService(ref);
-        Object obj;
+        ServiceBindingHolder sbh;
         try {
             acquireWriteLockIfNotHeld();
-            obj = m_serviceObjects.remove(ref);
+            sbh = m_serviceObjects.remove(ref);
         } finally {
             releaseWriteLockIfHeld();
         }
 
         // Call the callback outside the lock.
-        if (obj != null && obj instanceof IPOJOServiceFactory) {
-            ((IPOJOServiceFactory) obj).ungetService(m_instance, obj);
+        if (sbh != null && sbh.factory != null) {
+            sbh.factory.ungetService(m_instance, sbh.service);
         }
+
+        m_serviceReferenceManager.unweavingServiceBinding(sbh);
+
     }
 
     public ContextSourceManager getContextSourceManager() {
@@ -988,11 +1001,11 @@ public abstract class DependencyModel {
                         m_state = BROKEN;
 
                         // We are going to call callbacks, releasing the lock.
-                        Object svc = m_serviceObjects.get(ref);
+                        ServiceBindingHolder sbh = m_serviceObjects.get(ref);
                         releaseWriteLockIfHeld();
 
                         // Notify listeners
-                        notifyListeners(DependencyEventType.UNBINDING, ref, svc);
+                        notifyListeners(DependencyEventType.UNBINDING, ref, sbh.service);
                         notifyListeners(DependencyEventType.DEPARTURE, ref, null);
 
                         invalidate();  // This will invalidate the instance.
@@ -1072,7 +1085,7 @@ public abstract class DependencyModel {
             }
 
             // Before leaving the protected region, copy used services.
-            Map<ServiceReference, Object> services = new HashMap<ServiceReference, Object>(m_serviceObjects);
+            Map<ServiceReference, ServiceBindingHolder> services = new HashMap<ServiceReference, ServiceBindingHolder>(m_serviceObjects);
 
             // Leaving the locked region to invoke callbacks
             releaseWriteLockIfHeld();
@@ -1080,14 +1093,24 @@ public abstract class DependencyModel {
             for (ServiceReference ref : departures) {
                 onServiceDeparture(ref);
                 // Notify service unbinding to listeners
-                Object svc = services.get(ref);
-                notifyListeners(DependencyEventType.UNBINDING, ref, svc);
+                final ServiceBindingHolder sbh = services.get(ref);
+                if (sbh != null) {
+                    notifyListeners(DependencyEventType.UNBINDING, ref, sbh.service);
+                } else {
+                    notifyListeners(DependencyEventType.UNBINDING, ref, null);
+                }
+                // Unget the service reference.
+                ungetService(ref);
             }
             for (ServiceReference ref : arrivals) {
                 onServiceArrival(ref);
                 // Notify service binding to listeners
-                Object svc = services.get(ref);
-                notifyListeners(DependencyEventType.BINDING, ref, svc);
+                final ServiceBindingHolder sbh = services.get(ref);
+                if (sbh != null) {
+                    notifyListeners(DependencyEventType.BINDING, ref, sbh.service);
+                } else {
+                    notifyListeners(DependencyEventType.BINDING, ref, null);
+                }
             }
             // Do we have a modified service ?
             if (set.modified != null && m_boundServices.contains(set.modified)) {
@@ -1229,4 +1252,26 @@ public abstract class DependencyModel {
             m_listeners.clear();
         }
     }
+
+    /**
+     * Service binding structure.
+     */
+    public class ServiceBindingHolder {
+
+        public final Object service;
+        public final IPOJOServiceFactory factory;
+        public final ServiceReference reference;
+
+        private ServiceBindingHolder(ServiceReference reference, IPOJOServiceFactory factory, Object service) {
+            this.service = service;
+            this.factory = factory;
+            this.reference = reference;
+        }
+
+        private ServiceBindingHolder(ServiceReference reference, Object service) {
+            this.service = service;
+            this.factory = null;
+            this.reference = reference;
+        }
+    }
 }



Mime
View raw message