Return-Path: X-Original-To: apmail-felix-commits-archive@www.apache.org Delivered-To: apmail-felix-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 53702109FA for ; Tue, 17 Sep 2013 12:07:41 +0000 (UTC) Received: (qmail 20227 invoked by uid 500); 17 Sep 2013 12:07:38 -0000 Delivered-To: apmail-felix-commits-archive@felix.apache.org Received: (qmail 20186 invoked by uid 500); 17 Sep 2013 12:07:36 -0000 Mailing-List: contact commits-help@felix.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@felix.apache.org Delivered-To: mailing list commits@felix.apache.org Received: (qmail 20176 invoked by uid 99); 17 Sep 2013 12:07:35 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 17 Sep 2013 12:07:35 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 17 Sep 2013 12:07:31 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id AC32123888E7; Tue, 17 Sep 2013 12:07:10 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit 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 -0000 To: commits@felix.apache.org From: clement@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20130917120710.AC32123888E7@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 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 deps = new HashMap(); + + @Override + public S getService(DependencyModel dependency, ServiceReference 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 void ungetService(DependencyModel dependency, ServiceReference 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 deps = new HashMap(); + 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 getService(DependencyModel dependency, ServiceReference 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 void ungetService(DependencyModel dependency, ServiceReference 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 props = (Map) 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 props = (Map) 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) 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 props = (Map) 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 props = (Map) 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) 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) 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(); /** + * The set of binding interceptors. + * TODO this set should be sorted according to the OSGi ranking policy. + */ + private LinkedList m_bindingInterceptors = new + LinkedList(); + + /** * 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 transform the service reference to add / remove service properties. In this case, - * it must return the same 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 never 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 modifies the service object, the returned object must 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 wrapped by binding interceptors called before the + * current one. + * + * @param dependency the dependency + * @param reference the service reference bound + * @param service the service object + * @param the service specification + * @return the service object to be injected within the component. Must never be {@code null}. + */ + public S getService(DependencyModel dependency, ServiceReference 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 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 the service specification */ - public TransformedServiceReference accept(DependencyModel dependency, BundleContext context, - TransformedServiceReference ref); + public void ungetService(DependencyModel dependency, ServiceReference 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 m_serviceObjects = new HashMap(); + private Map m_serviceObjects = new HashMap(); /** * 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 entry : m_serviceObjects.entrySet()) { + for (Map.Entry 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 services = new HashMap(m_serviceObjects); + Map services = new HashMap(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; + } + } }