Repository: aries-rsa Updated Branches: refs/heads/master 8ddac37a6 -> 2792d5d64
[DOSGI-122] Implement FindHook Project: http://git-wip-us.apache.org/repos/asf/aries-rsa/repo Commit: http://git-wip-us.apache.org/repos/asf/aries-rsa/commit/2792d5d6 Tree: http://git-wip-us.apache.org/repos/asf/aries-rsa/tree/2792d5d6 Diff: http://git-wip-us.apache.org/repos/asf/aries-rsa/diff/2792d5d6 Branch: refs/heads/master Commit: 2792d5d64bdef7abfcba815ada6bcf051126730b Parents: 8ddac37 Author: Christian Schneider <ch...@die-schneider.net> Authored: Wed Nov 9 21:18:21 2016 +0100 Committer: Christian Schneider <ch...@die-schneider.net> Committed: Wed Nov 9 21:18:21 2016 +0100 ---------------------------------------------------------------------- .../aries/rsa/itests/felix/RsaTestBase.java | 9 +- .../rsa/itests/felix/tcp/TestFindHook.java | 114 +++++++++++++++++++ .../topologymanager/importer/FilterHelper.java | 35 ++++++ .../importer/ListenerHookImpl.java | 30 +---- .../topologymanager/importer/RSFindHook.java | 70 ++++++++++++ .../importer/TopologyManagerImport.java | 5 +- .../importer/FilterHelperTest.java | 9 ++ .../importer/TopologyManagerImportTest.java | 2 +- 8 files changed, 242 insertions(+), 32 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/2792d5d6/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/RsaTestBase.java ---------------------------------------------------------------------- diff --git a/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/RsaTestBase.java b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/RsaTestBase.java index 1368f41..811ae61 100644 --- a/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/RsaTestBase.java +++ b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/RsaTestBase.java @@ -81,6 +81,10 @@ public class RsaTestBase { } } + protected static Option echoTcpAPI() { + return mvn("org.apache.aries.rsa.examples.echotcp", "org.apache.aries.rsa.examples.echotcp.api"); + } + protected static Option echoTcpConsumer() { return CoreOptions.composite( mvn("org.apache.felix", "org.apache.felix.scr"), @@ -109,10 +113,13 @@ public class RsaTestBase { mvn("org.apache.aries.rsa", "org.apache.aries.rsa.spi"), mvn("org.apache.aries.rsa", "org.apache.aries.rsa.topology-manager"), mvn("org.apache.aries.rsa.discovery", "org.apache.aries.rsa.discovery.local") - // CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005") ); } + protected static Option debug() { + return CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"); + } + protected static Option rsaDiscoveryConfig() { return composite( mvn("org.apache.aries.rsa.discovery", "org.apache.aries.rsa.discovery.config") http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/2792d5d6/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/tcp/TestFindHook.java ---------------------------------------------------------------------- diff --git a/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/tcp/TestFindHook.java b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/tcp/TestFindHook.java new file mode 100644 index 0000000..f866f7b --- /dev/null +++ b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/tcp/TestFindHook.java @@ -0,0 +1,114 @@ +package org.apache.aries.rsa.itests.felix.tcp; +/** + * 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. + */ + + +import java.io.IOException; +import java.util.Collection; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeoutException; + +import javax.inject.Inject; + +import org.apache.aries.rsa.examples.echotcp.api.EchoService; +import org.apache.aries.rsa.itests.felix.RsaTestBase; +import org.apache.aries.rsa.itests.felix.ServerConfiguration; +import org.apache.aries.rsa.itests.felix.TwoContainerPaxExam; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.Configuration; +import org.ops4j.pax.exam.Option; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +@RunWith(TwoContainerPaxExam.class) +public class TestFindHook extends RsaTestBase { + + @Inject + BundleContext context; + + @ServerConfiguration + public static Option[] remoteConfig() throws IOException { + return new Option[] { + rsaCore(), + rsaDiscoveryZookeeper(), + rsaTcp(), + echoTcpService(), + configZKServer(), + configZKDiscovery(), + }; + } + + @Configuration + public static Option[] configure() throws Exception { + return new Option[] { + rsaCore(), + rsaDiscoveryZookeeper(), + rsaTcp(), + echoTcpAPI(), + configZKDiscovery() + }; + } + + public <T> T tryTo(String message, Callable<T> func) throws TimeoutException { + return tryTo(message, func, 5000); + } + + public <T> T tryTo(String message, Callable<T> func, long timeout) throws TimeoutException { + Throwable lastException = null; + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < timeout) { + try { + T result = func.call(); + if (result != null) { + return result; + } + lastException = null; + } catch (Throwable e) { + lastException = e; + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + continue; + } + } + TimeoutException ex = new TimeoutException("Timeout while trying to " + message); + if (lastException != null) { + ex.addSuppressed(lastException); + } + throw ex; + } + + @Test + public void testFind() throws Exception { + Thread.sleep(1000); // FIXME Why does it only work if we wait? + ServiceReference<EchoService> ref = tryTo("get EchoService", new Callable<ServiceReference<EchoService>>() { + + @Override + public ServiceReference<EchoService> call() throws Exception { + Collection<ServiceReference<EchoService>> refs = context.getServiceReferences(EchoService.class, null); + return (refs.size() > 0)? refs.iterator().next() : null; + } + }, 10000); + Assert.assertNotNull(ref); + } + +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/2792d5d6/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/FilterHelper.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/FilterHelper.java b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/FilterHelper.java index 77b0abb..98cb94d 100644 --- a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/FilterHelper.java +++ b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/FilterHelper.java @@ -18,6 +18,8 @@ */ package org.apache.aries.rsa.topologymanager.importer; +import java.util.HashSet; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.osgi.framework.Constants; @@ -39,4 +41,37 @@ public final class FilterHelper { } return null; } + + private static final Set<String> SYSTEM_PACKAGES; + static { + SYSTEM_PACKAGES = new HashSet<String>(); + SYSTEM_PACKAGES.add("org.osgi.service"); + SYSTEM_PACKAGES.add("org.apache.felix"); + SYSTEM_PACKAGES.add("org.ops4j.pax.logging"); + SYSTEM_PACKAGES.add("ch.ethz.iks.slp"); + SYSTEM_PACKAGES.add("org.ungoverned.osgi.service"); + SYSTEM_PACKAGES.add("org.springframework.osgi.context.event.OsgiBundleApplicationContextListener"); + SYSTEM_PACKAGES.add("java.net.ContentHandler"); + } + + public static boolean isClassExcluded(String className) { + if (className == null) { + return true; + } + + for (String p : SYSTEM_PACKAGES) { + if (className.startsWith(p)) { + return true; + } + } + return false; + } + + public static String getFullFilter(String objectClass, String filter) { + if (objectClass == null) { + return filter; + } + String nameFilter = String.format("(objectClass=%s)", objectClass); + return (filter == null) ? nameFilter : String.format("(&%s%s)", nameFilter, filter); + } } http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/2792d5d6/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/ListenerHookImpl.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/ListenerHookImpl.java b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/ListenerHookImpl.java index 6766fc1..1ca1d19 100644 --- a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/ListenerHookImpl.java +++ b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/ListenerHookImpl.java @@ -19,8 +19,6 @@ package org.apache.aries.rsa.topologymanager.importer; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; @@ -37,19 +35,6 @@ public class ListenerHookImpl implements ListenerHook { private static final Logger LOG = LoggerFactory.getLogger(ListenerHookImpl.class); - // From the old impl. - private static final Set<String> SYSTEM_PACKAGES; - static { - SYSTEM_PACKAGES = new HashSet<String>(); - SYSTEM_PACKAGES.add("org.osgi.service"); - SYSTEM_PACKAGES.add("org.apache.felix"); - SYSTEM_PACKAGES.add("org.ops4j.pax.logging"); - SYSTEM_PACKAGES.add("ch.ethz.iks.slp"); - SYSTEM_PACKAGES.add("org.ungoverned.osgi.service"); - SYSTEM_PACKAGES.add("org.springframework.osgi.context.event.OsgiBundleApplicationContextListener"); - SYSTEM_PACKAGES.add("java.net.ContentHandler"); - } - private final BundleContext bctx; private final ServiceInterestListener serviceInterestListener; private final String frameworkUUID; @@ -78,7 +63,7 @@ public class ListenerHookImpl implements ListenerHook { continue; } - if (isClassExcluded(className)) { + if (FilterHelper.isClassExcluded(className)) { LOG.debug("Skipping import request for excluded class [{}]", className); continue; } @@ -100,19 +85,6 @@ public class ListenerHookImpl implements ListenerHook { } } - private static boolean isClassExcluded(String className) { - if (className == null) { - return true; - } - - for (String p : SYSTEM_PACKAGES) { - if (className.startsWith(p)) { - return true; - } - } - return false; - } - String extendFilter(String filter) { return "(&" + filter + "(!(" + RemoteConstants.ENDPOINT_FRAMEWORK_UUID + "=" + frameworkUUID + ")))"; } http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/2792d5d6/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/RSFindHook.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/RSFindHook.java b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/RSFindHook.java new file mode 100644 index 0000000..722cee2 --- /dev/null +++ b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/RSFindHook.java @@ -0,0 +1,70 @@ +/** + * 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.aries.rsa.topologymanager.importer; + +import java.util.Collection; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.hooks.service.FindHook; +import org.osgi.service.remoteserviceadmin.RemoteConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RSFindHook implements FindHook { + private static final Logger LOG = LoggerFactory.getLogger(RSFindHook.class); + + private BundleContext bctx; + private String frameworkUUID; + private ServiceInterestListener serviceInterestListener; + + public RSFindHook(BundleContext bc, ServiceInterestListener serviceInterestListener) { + this.bctx = bc; + this.frameworkUUID = bctx.getProperty(Constants.FRAMEWORK_UUID); + this.serviceInterestListener = serviceInterestListener; + } + + @Override + public void find(BundleContext context, String name, String filter, boolean allServices, + Collection<ServiceReference<?>> references) { + if (context.equals(bctx)) { + LOG.debug("ListenerHookImpl: skipping request from myself"); + return; + } + + String fullFilter = FilterHelper.getFullFilter(name, filter); + + if (fullFilter == null) { + LOG.debug("skipping empty filter"); + return; + } + String className = name != null ? name : FilterHelper.getObjectClass(fullFilter); + if (FilterHelper.isClassExcluded(className)) { + LOG.debug("Skipping import request for excluded class [{}]", className); + return; + } + String exFilter = extendFilter(fullFilter); + serviceInterestListener.addServiceInterest(exFilter); + } + + String extendFilter(String filter) { + return "(&" + filter + "(!(" + RemoteConstants.ENDPOINT_FRAMEWORK_UUID + "=" + frameworkUUID + ")))"; + } +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/2792d5d6/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java index 3b98710..54a1c56 100644 --- a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java +++ b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java @@ -33,6 +33,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.osgi.framework.BundleContext; +import org.osgi.framework.hooks.service.FindHook; import org.osgi.framework.hooks.service.ListenerHook; import org.osgi.service.remoteserviceadmin.EndpointDescription; import org.osgi.service.remoteserviceadmin.EndpointListener; @@ -59,6 +60,7 @@ public class TopologyManagerImport implements EndpointListener, RemoteServiceAdm private final BundleContext bctx; private Set<RemoteServiceAdmin> rsaSet; private final ListenerHookImpl listenerHook; + private RSFindHook findHook; /** * If set to false only one service is imported for each import interest even it multiple services are @@ -88,18 +90,19 @@ public class TopologyManagerImport implements EndpointListener, RemoteServiceAdm private final Map<String /* filter */, List<ImportRegistration>> importedServices = new HashMap<String, List<ImportRegistration>>(); - public TopologyManagerImport(BundleContext bc) { this.rsaSet = new HashSet<RemoteServiceAdmin>(); bctx = bc; endpointListenerManager = new EndpointListenerManager(bctx, this); execService = new ThreadPoolExecutor(5, 10, 50, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); listenerHook = new ListenerHookImpl(bc, this); + findHook = new RSFindHook(bc, this); } public void start() { bctx.registerService(RemoteServiceAdminListener.class, this, null); bctx.registerService(ListenerHook.class, listenerHook, null); + bctx.registerService(FindHook.class, findHook, null); endpointListenerManager.start(); } http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/2792d5d6/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/FilterHelperTest.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/FilterHelperTest.java b/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/FilterHelperTest.java index 5644073..cf4ab00 100644 --- a/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/FilterHelperTest.java +++ b/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/FilterHelperTest.java @@ -39,6 +39,15 @@ public class FilterHelperTest { Assert.assertEquals(className, objClass); } + @Test + public void testGetFullFilter() { + String filter = "(a=b)"; + String objectClass = "my.Test"; + Assert.assertEquals(filter, FilterHelper.getFullFilter(null, filter)); + Assert.assertEquals("(objectClass=my.Test)", FilterHelper.getFullFilter(objectClass, null)); + Assert.assertEquals("(&(objectClass=my.Test)(a=b))", FilterHelper.getFullFilter(objectClass, filter)); + } + class InnerClass { } http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/2792d5d6/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImportTest.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImportTest.java b/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImportTest.java index dc17486..07fb0ae 100644 --- a/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImportTest.java +++ b/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImportTest.java @@ -58,7 +58,7 @@ public class TopologyManagerImportTest { EasyMock.expect(bc.registerService(EasyMock.anyObject(Class.class), EasyMock.anyObject(), (Dictionary)EasyMock.anyObject())).andReturn(sreg).anyTimes(); - EasyMock.expect(bc.getProperty(Constants.FRAMEWORK_UUID)).andReturn("myid"); + EasyMock.expect(bc.getProperty(Constants.FRAMEWORK_UUID)).andReturn("myid").atLeastOnce(); EndpointDescription endpoint = c.createMock(EndpointDescription.class); RemoteServiceAdmin rsa = c.createMock(RemoteServiceAdmin.class);