diff --git a/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/client/ZookeeperEndpointListener.java b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/client/ZookeeperEndpointListener.java index beaab10d9..f137112d6 100644 --- a/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/client/ZookeeperEndpointListener.java +++ b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/client/ZookeeperEndpointListener.java @@ -21,8 +21,11 @@ import java.io.ByteArrayInputStream; import java.io.Closeable; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; @@ -113,6 +116,10 @@ private void watchRecursive(String path) { private void onChanged(String path, EndpointDescription endpoint) { EndpointDescription old = endpoints.put(path, endpoint); + if (old != null && getChangedProps(old.getProperties(), endpoint.getProperties()).isEmpty()) { + LOG.trace("ignoring endpoint that hasn't changed: {}", endpoint); + return; + } int type = old == null ? EndpointEvent.ADDED : EndpointEvent.MODIFIED; EndpointEvent event = new EndpointEvent(type, endpoint); listener.accept(event); @@ -136,4 +143,18 @@ private EndpointDescription read(String path) throws KeeperException, Interrupte } } + private static Set getChangedProps(Map p1, Map p2) { + Set changed = new LinkedHashSet<>(); + for (Map.Entry entry : p1.entrySet()) { + Object v = p2.get(entry.getKey()); + if (!Objects.deepEquals(entry.getValue(), v) || v == null && !p2.containsKey(entry.getKey())) + changed.add(entry.getKey()); + } + for (String k : p2.keySet()) { + if (!p1.containsKey(k)) + changed.add(k); + } + return changed; + } + } diff --git a/itests/tck/configs/framework1/org.apache.aries.rsa.discovery.tcp.cfg b/itests/tck/configs/framework1/org.apache.aries.rsa.discovery.tcp.cfg new file mode 100644 index 000000000..312a7908e --- /dev/null +++ b/itests/tck/configs/framework1/org.apache.aries.rsa.discovery.tcp.cfg @@ -0,0 +1,2 @@ +address=localhost:7668 +peers=localhost:7669 diff --git a/itests/tck/configs/framework1/org.apache.aries.rsa.discovery.zookeeper.cfg b/itests/tck/configs/framework1/org.apache.aries.rsa.discovery.zookeeper.cfg new file mode 100644 index 000000000..3c35b62f1 --- /dev/null +++ b/itests/tck/configs/framework1/org.apache.aries.rsa.discovery.zookeeper.cfg @@ -0,0 +1 @@ +zookeeper.timeout=300000 diff --git a/itests/tck/configs/framework1/org.apache.aries.rsa.discovery.zookeeper.server.cfg b/itests/tck/configs/framework1/org.apache.aries.rsa.discovery.zookeeper.server.cfg new file mode 100644 index 000000000..d8060cca5 --- /dev/null +++ b/itests/tck/configs/framework1/org.apache.aries.rsa.discovery.zookeeper.server.cfg @@ -0,0 +1 @@ +# if this config exists, the zookeeper server will be started diff --git a/itests/tck/configs/framework1/org.apache.aries.rsa.provider.fastbin.cfg b/itests/tck/configs/framework1/org.apache.aries.rsa.provider.fastbin.cfg new file mode 100644 index 000000000..5b6ce67ca --- /dev/null +++ b/itests/tck/configs/framework1/org.apache.aries.rsa.provider.fastbin.cfg @@ -0,0 +1 @@ +uri=tcp://0.0.0.0:2543 diff --git a/itests/tck/configs/framework1/org.ops4j.pax.logging.cfg b/itests/tck/configs/framework1/org.ops4j.pax.logging.cfg new file mode 100644 index 000000000..733f0c318 --- /dev/null +++ b/itests/tck/configs/framework1/org.ops4j.pax.logging.cfg @@ -0,0 +1,27 @@ +# Root log level +log4j2.rootLogger.level = WARN + +# Console appender (keep it, but quieter) +log4j2.rootLogger.appenderRef.console.ref = console +log4j2.appender.console.type = Console +log4j2.appender.console.name = console +log4j2.appender.console.layout.type = PatternLayout +log4j2.appender.console.layout.pattern = %d{HH:mm:ss.SSS} FW1 %-5p [%t] %c - %m%n + +# File appender +log4j2.rootLogger.appenderRef.file.ref = file +log4j2.appender.file.type = RollingFile +log4j2.appender.file.name = file +log4j2.appender.file.fileName = target/framework1.log +log4j2.appender.file.filePattern = target/framework1-%i.log +log4j2.appender.file.layout.type = PatternLayout +log4j2.appender.file.layout.pattern = %d{ISO8601} %-5p [%t] %c - %m%n +log4j2.appender.file.policies.type = Policies +log4j2.appender.file.policies.size.type = SizeBasedTriggeringPolicy +log4j2.appender.file.policies.size.size = 100MB +log4j2.appender.file.strategy.type = DefaultRolloverStrategy +log4j2.appender.file.strategy.max = 5 + +# Per-package overrides +log4j2.logger.aries.name = org.apache.aries.rsa +log4j2.logger.aries.level = WARN diff --git a/itests/tck/configs/framework2/org.apache.aries.rsa.discovery.tcp.cfg b/itests/tck/configs/framework2/org.apache.aries.rsa.discovery.tcp.cfg new file mode 100644 index 000000000..62326d9ec --- /dev/null +++ b/itests/tck/configs/framework2/org.apache.aries.rsa.discovery.tcp.cfg @@ -0,0 +1,2 @@ +address=localhost:7669 +peers=localhost:7668 diff --git a/itests/tck/configs/framework2/org.apache.aries.rsa.discovery.zookeeper.cfg b/itests/tck/configs/framework2/org.apache.aries.rsa.discovery.zookeeper.cfg new file mode 100644 index 000000000..3c35b62f1 --- /dev/null +++ b/itests/tck/configs/framework2/org.apache.aries.rsa.discovery.zookeeper.cfg @@ -0,0 +1 @@ +zookeeper.timeout=300000 diff --git a/itests/tck/configs/framework2/org.apache.aries.rsa.provider.fastbin.cfg b/itests/tck/configs/framework2/org.apache.aries.rsa.provider.fastbin.cfg new file mode 100644 index 000000000..0dbe29461 --- /dev/null +++ b/itests/tck/configs/framework2/org.apache.aries.rsa.provider.fastbin.cfg @@ -0,0 +1 @@ +uri=tcp://0.0.0.0:2544 diff --git a/itests/tck/configs/framework2/org.ops4j.pax.logging.cfg b/itests/tck/configs/framework2/org.ops4j.pax.logging.cfg new file mode 100644 index 000000000..767f09c89 --- /dev/null +++ b/itests/tck/configs/framework2/org.ops4j.pax.logging.cfg @@ -0,0 +1,27 @@ +# Root log level +log4j2.rootLogger.level = WARN + +# Console appender (keep it, but quieter) +log4j2.rootLogger.appenderRef.console.ref = console +log4j2.appender.console.type = Console +log4j2.appender.console.name = console +log4j2.appender.console.layout.type = PatternLayout +log4j2.appender.console.layout.pattern = %d{HH:mm:ss.SSS} FW2 %-5p [%t] %c - %m%n + +# File appender +log4j2.rootLogger.appenderRef.file.ref = file +log4j2.appender.file.type = RollingFile +log4j2.appender.file.name = file +log4j2.appender.file.fileName = target/framework2.log +log4j2.appender.file.filePattern = target/framework2-%i.log +log4j2.appender.file.layout.type = PatternLayout +log4j2.appender.file.layout.pattern = %d{ISO8601} %-5p [%t] %c - %m%n +log4j2.appender.file.policies.type = Policies +log4j2.appender.file.policies.size.type = SizeBasedTriggeringPolicy +log4j2.appender.file.policies.size.size = 100MB +log4j2.appender.file.strategy.type = DefaultRolloverStrategy +log4j2.appender.file.strategy.max = 5 + +# Per-package overrides +log4j2.logger.aries.name = org.apache.aries.rsa +log4j2.logger.aries.level = WARN diff --git a/itests/tck/pom.xml b/itests/tck/pom.xml index 2cdd19ae8..347965ce4 100644 --- a/itests/tck/pom.xml +++ b/itests/tck/pom.xml @@ -60,11 +60,80 @@ org.apache.aries.rsa.discovery.tcp ${project.version} + + org.apache.aries.rsa.discovery + org.apache.aries.rsa.discovery.zookeeper + ${project.version} + org.apache.aries.rsa.provider org.apache.aries.rsa.provider.tcp ${project.version} + + org.apache.aries.rsa.provider + org.apache.aries.rsa.provider.fastbin + ${project.version} + + + + + io.dropwizard.metrics + metrics-core + + + org.xerial.snappy + snappy-java + + + io.netty + netty-handler + ${netty.version} + + + io.netty + netty-buffer + ${netty.version} + + + io.netty + netty-transport + ${netty.version} + + + io.netty + netty-common + ${netty.version} + + + io.netty + netty-resolver + ${netty.version} + + + io.netty + netty-transport-native-unix-common + ${netty.version} + + + io.netty + netty-codec + ${netty.version} + + + + + org.fusesource.hawtbuf + hawtbuf + + + org.fusesource.hawtdispatch + hawtdispatch + + + org.fusesource.hawtbuf + hawtbuf-proto + @@ -154,6 +223,16 @@ + + org.apache.felix + org.apache.felix.scr + 2.2.18 + + + org.apache.felix + org.apache.felix.fileinstall + 3.7.4 + org.apache.felix org.apache.felix.configadmin @@ -164,11 +243,6 @@ org.apache.felix.eventadmin 1.6.4 - - org.apache.felix - org.apache.felix.scr - 2.2.18 - @@ -196,7 +270,8 @@ ${bnd.version} - tck.bndrun + tck-tcp-tcp.bndrun + tck-zookeeper-fastbin.bndrun false @@ -215,4 +290,3 @@ - diff --git a/itests/tck/tck.bndrun b/itests/tck/tck-tcp-tcp.bndrun similarity index 89% rename from itests/tck/tck.bndrun rename to itests/tck/tck-tcp-tcp.bndrun index 756f0dd25..029cca369 100644 --- a/itests/tck/tck.bndrun +++ b/itests/tck/tck-tcp-tcp.bndrun @@ -17,6 +17,10 @@ # under the License. #-standalone: target/index.xml + +# runs the TCK test suite with TCP discovery and TCP distribution provider + + -runtrace: true -target: org.osgi.test.cases.remoteserviceadmin @@ -26,7 +30,7 @@ osgi.resolverMode="strict",\ rsa.ct.timeout=30000,\ rsa.ct.timeout.factor=3,\ - rsa.tck.timeout=10000,\ + rsa.tck.timeout=30000,\ service.exported.configs="aries.tcp",\ org.osgi.framework.system.packages.extra="\ org.osgi.service.remoteserviceadmin",\ @@ -35,37 +39,39 @@ junit.framework",\ org.osgi.test.cases.remoteserviceadmin.serverconfig="service.exported.configs",\ org.osgi.test.cases.remoteserviceadmin.bundles="\ - ${repo;org.apache.aries.rsa.core;2.0.0.SNAPSHOT},\ - ${repo;org.apache.aries.rsa.spi;2.0.0.SNAPSHOT},\ - ${repo;org.apache.aries.rsa.topology-manager;2.0.0.SNAPSHOT},\ - ${repo;org.apache.aries.rsa.discovery.local;2.0.0.SNAPSHOT},\ - ${repo;org.apache.aries.rsa.discovery.tcp;2.0.0.SNAPSHOT},\ - ${repo;org.apache.aries.rsa.provider.tcp;2.0.0.SNAPSHOT},\ + ${repo;org.ops4j.pax.logging.pax-logging-api;2.3.3},\ + ${repo;org.ops4j.pax.logging.pax-logging-log4j2;2.3.3},\ ${repo;org.osgi.service.component;1.5.1},\ ${repo;org.osgi.util.function;1.2.0},\ ${repo;org.osgi.util.promise;1.3.0},\ + ${repo;org.apache.felix.scr;2.2.18},\ + ${repo;org.apache.felix.fileinstall;3.7.4},\ ${repo;org.apache.felix.configadmin;1.9.26},\ ${repo;org.apache.felix.eventadmin;1.6.4},\ - ${repo;org.apache.felix.scr;2.2.18},\ + ${repo;org.glassfish.hk2.osgi-resource-locator;3.0.0},\ ${repo;org.apache.servicemix.bundles.junit;4.13.2},\ - ${repo;org.ops4j.pax.logging.pax-logging-api;2.3.3},\ - ${repo;org.ops4j.pax.logging.pax-logging-log4j2;2.3.3},\ ${repo;jakarta.activation-api;2.1.4},\ ${repo;jakarta.xml.bind-api;4.0.5},\ - ${repo;com.sun.xml.bind.jaxb-impl;4.0.8},\ ${repo;com.sun.xml.bind.jaxb-core;4.0.8},\ + ${repo;com.sun.xml.bind.jaxb-impl;4.0.8},\ ${repo;com.sun.istack.commons-runtime;4.2.0},\ - ${repo;org.glassfish.hk2.osgi-resource-locator;3.0.0}",\ - org.apache.aries.rsa.discovery.tcp.address=localhost:7668,\ - org.apache.aries.rsa.discovery.tcp.peers=localhost:7669,\ + ${repo;org.apache.aries.rsa.spi;2.0.0.SNAPSHOT},\ + ${repo;org.apache.aries.rsa.discovery.local;2.0.0.SNAPSHOT},\ + ${repo;org.apache.aries.rsa.discovery.tcp;2.0.0.SNAPSHOT},\ + ${repo;org.apache.aries.rsa.provider.tcp;2.0.0.SNAPSHOT},\ + ${repo;org.apache.aries.rsa.core;2.0.0.SNAPSHOT},\ + ${repo;org.apache.aries.rsa.topology-manager;2.0.0.SNAPSHOT}",\ + felix.fileinstall.dir=${.}/configs/framework1,\ + felix.fileinstall.noInitialDelay=true,\ org.apache.aries.rsa.bridge=true,\ org.osgi.test.cases.remoteserviceadmin.framework.properties="\ - org.apache.aries.rsa.discovery.tcp.address=localhost:7669,\ - org.apache.aries.rsa.discovery.tcp.peers=localhost:7668,\ + felix.fileinstall.dir=${.}/configs/framework2,\ + felix.fileinstall.noInitialDelay=true,\ org.apache.aries.rsa.bridge=true" -runvm:\ - -Xmx512m + -Xmx512m,\ + -Dorg.ops4j.pax.logging.DefaultServiceLog.level=WARN #,"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" -runsystempackages:\ @@ -81,27 +87,28 @@ -runblacklist:\ osgi.identity;filter:='(osgi.identity=osgi.cmpn)' -runbundles:\ - org.apache.aries.rsa.core;version='[2.0.0,2.0.1)',\ - org.apache.aries.rsa.spi;version='[2.0.0,2.0.1)',\ - org.apache.aries.rsa.topology-manager;version='[2.0.0,2.0.1)',\ - org.apache.aries.rsa.discovery.local;version='[2.0.0,2.0.1)',\ - org.apache.aries.rsa.discovery.tcp;version='[2.0.0,2.0.1)',\ - org.apache.aries.rsa.provider.tcp;version='[2.0.0,2.0.1)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.3.3,2.3.4)',\ + org.ops4j.pax.logging.pax-logging-log4j2;version='[2.3.3,2.3.4)',\ org.osgi.service.component;version='[1.5.1,1.5.2)',\ org.osgi.util.function;version='[1.2.0,1.2.1)',\ org.osgi.util.promise;version='[1.3.0,1.3.1)',\ + org.apache.felix.scr;version='[2.2.18,2.2.19)',\ + org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ - org.apache.felix.scr;version='[2.2.18,2.2.19)',\ + org.glassfish.hk2.osgi-resource-locator;version='[3.0.0,3.0.1)',\ org.apache.servicemix.bundles.junit;version='[4.13.2,4.13.3)',\ assertj-core;version='[3.27.7,3.27.8)',\ net.bytebuddy.byte-buddy;version='[1.18.8,1.18.9)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.3.3,2.3.4)',\ - org.ops4j.pax.logging.pax-logging-log4j2;version='[2.3.3,2.3.4)',\ jakarta.activation-api;version='[2.1.4,2.1.5)',\ jakarta.xml.bind-api;version='[4.0.5,4.0.6)',\ - com.sun.xml.bind.jaxb-impl;version='[4.0.8,4.0.9)',\ com.sun.xml.bind.jaxb-core;version='[4.0.8,4.0.9)',\ + com.sun.xml.bind.jaxb-impl;version='[4.0.8,4.0.9)',\ com.sun.istack.commons-runtime;version='[4.2.0,4.2.1)',\ - org.glassfish.hk2.osgi-resource-locator;version='[3.0.0,3.0.1)',\ + org.apache.aries.rsa.spi;version='[2.0.0,2.0.1)',\ + org.apache.aries.rsa.discovery.local;version='[2.0.0,2.0.1)',\ + org.apache.aries.rsa.discovery.tcp;version='[2.0.0,2.0.1)',\ + org.apache.aries.rsa.provider.tcp;version='[2.0.0,2.0.1)',\ + org.apache.aries.rsa.core;version='[2.0.0,2.0.1)',\ + org.apache.aries.rsa.topology-manager;version='[2.0.0,2.0.1)',\ org.osgi.test.cases.remoteserviceadmin;version='[8.1.0,8.1.1)' diff --git a/itests/tck/tck-zookeeper-fastbin.bndrun b/itests/tck/tck-zookeeper-fastbin.bndrun new file mode 100644 index 000000000..a0d6fcb0b --- /dev/null +++ b/itests/tck/tck-zookeeper-fastbin.bndrun @@ -0,0 +1,137 @@ + +# 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. +#-standalone: target/index.xml + + +# runs the TCK test suite with ZooKeeper discovery and FastBin distribution provider + + +-runtrace: true + +-target: org.osgi.test.cases.remoteserviceadmin + +-runproperties:\ + report="true",\ + osgi.resolverMode="strict",\ + rsa.ct.timeout=30000,\ + rsa.ct.timeout.factor=3,\ + rsa.tck.timeout=30000,\ + service.exported.configs="aries.fastbin",\ + org.osgi.framework.system.packages.extra="\ + org.osgi.service.remoteserviceadmin",\ + org.osgi.test.cases.remoteserviceadmin.system.packages.extra="\ + org.osgi.service.remoteserviceadmin,\ + junit.framework",\ + org.osgi.test.cases.remoteserviceadmin.serverconfig="service.exported.configs",\ + org.osgi.test.cases.remoteserviceadmin.bundles="\ + ${repo;org.ops4j.pax.logging.pax-logging-api;2.3.3},\ + ${repo;org.ops4j.pax.logging.pax-logging-log4j2;2.3.3},\ + ${repo;org.osgi.service.component;1.5.1},\ + ${repo;org.osgi.util.function;1.2.0},\ + ${repo;org.osgi.util.promise;1.3.0},\ + ${repo;org.apache.felix.scr;2.2.18},\ + ${repo;org.apache.felix.fileinstall;3.7.4},\ + ${repo;org.apache.felix.configadmin;1.9.26},\ + ${repo;org.apache.felix.eventadmin;1.6.4},\ + ${repo;org.glassfish.hk2.osgi-resource-locator;3.0.0},\ + ${repo;org.apache.servicemix.bundles.junit;4.13.2},\ + ${repo;jakarta.activation-api;2.1.4},\ + ${repo;jakarta.xml.bind-api;4.0.5},\ + ${repo;com.sun.xml.bind.jaxb-core;4.0.8},\ + ${repo;com.sun.xml.bind.jaxb-impl;4.0.8},\ + ${repo;com.sun.istack.commons-runtime;4.2.0},\ + ${repo;org.fusesource.hawtbuf.hawtbuf;1.11.0},\ + ${repo;org.fusesource.hawtdispatch.hawtdispatch;1.22.0},\ + ${repo;io.dropwizard.metrics.core;4.2.38},\ + ${repo;io.netty.handler;4.1.121},\ + ${repo;io.netty.buffer;4.1.121},\ + ${repo;io.netty.transport;4.1.121},\ + ${repo;io.netty.common;4.1.121},\ + ${repo;io.netty.resolver;4.1.121},\ + ${repo;io.netty.transport-native-unix-common;4.1.121},\ + ${repo;io.netty.codec;4.1.121},\ + ${repo;org.apache.aries.rsa.spi;2.0.0.SNAPSHOT},\ + ${repo;org.apache.aries.rsa.discovery.local;2.0.0.SNAPSHOT},\ + ${repo;org.apache.aries.rsa.discovery.zookeeper;2.0.0.SNAPSHOT},\ + ${repo;org.apache.aries.rsa.provider.fastbin;2.0.0.SNAPSHOT},\ + ${repo;org.apache.aries.rsa.core;2.0.0.SNAPSHOT},\ + ${repo;org.apache.aries.rsa.topology-manager;2.0.0.SNAPSHOT}",\ + felix.fileinstall.dir=${.}/configs/framework1,\ + felix.fileinstall.noInitialDelay=true,\ + org.apache.aries.rsa.bridge=true,\ + zookeeper.admin.enableServer=false,\ + org.osgi.test.cases.remoteserviceadmin.framework.properties="\ + felix.fileinstall.dir=${.}/configs/framework2,\ + felix.fileinstall.noInitialDelay=true,\ + org.apache.aries.rsa.bridge=true,\ + zookeeper.admin.enableServer=false" + +-runvm:\ + -Xmx512m,\ + -Dorg.ops4j.pax.logging.DefaultServiceLog.level=WARN + #,"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" + +-runsystempackages:\ + javax.xml.stream; version=1.0,\ + javax.xml.stream.events; version=1.0,\ + javax.xml.stream.util; version=1.0 +-runfw: org.eclipse.osgi;version='[3.24.100,3.24.101)' +-runee: JavaSE-${java.specification.version} +-runrequires:\ + osgi.identity;filter:='(osgi.identity=org.osgi.test.cases.remoteserviceadmin)',\ + osgi.identity;filter:='(osgi.identity=org.apache.aries.rsa.topology-manager)',\ + osgi.identity;filter:='(osgi.identity=org.ops4j.pax.logging.pax-logging-log4j2)' +-runblacklist:\ + osgi.identity;filter:='(osgi.identity=osgi.cmpn)' +-runbundles:\ + org.ops4j.pax.logging.pax-logging-api;version='[2.3.3,2.3.4)',\ + org.ops4j.pax.logging.pax-logging-log4j2;version='[2.3.3,2.3.4)',\ + org.osgi.service.component;version='[1.5.1,1.5.2)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.3.0,1.3.1)',\ + org.apache.felix.scr;version='[2.2.18,2.2.19)',\ + org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ + org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ + org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ + org.glassfish.hk2.osgi-resource-locator;version='[3.0.0,3.0.1)',\ + org.apache.servicemix.bundles.junit;version='[4.13.2,4.13.3)',\ + assertj-core;version='[3.27.7,3.27.8)',\ + net.bytebuddy.byte-buddy;version='[1.18.8,1.18.9)',\ + jakarta.activation-api;version='[2.1.4,2.1.5)',\ + jakarta.xml.bind-api;version='[4.0.5,4.0.6)',\ + com.sun.xml.bind.jaxb-core;version='[4.0.8,4.0.9)',\ + com.sun.xml.bind.jaxb-impl;version='[4.0.8,4.0.9)',\ + com.sun.istack.commons-runtime;version='[4.2.0,4.2.1)',\ + org.fusesource.hawtbuf.hawtbuf;version='[1.11.0,1.11.1)',\ + org.fusesource.hawtdispatch.hawtdispatch;version='[1.22.0,1.22.1)',\ + io.dropwizard.metrics.core;version='[4.2.38,4.2.39)',\ + org.xerial.snappy.snappy-java;version='[1.1.10.8,1.1.10.9)',\ + io.netty.handler;version='[4.1.121,4.1.122)',\ + io.netty.buffer;version='[4.1.121,4.1.122)',\ + io.netty.transport;version='[4.1.121,4.1.122)',\ + io.netty.common;version='[4.1.121,4.1.122)',\ + io.netty.resolver;version='[4.1.121,4.1.122)',\ + io.netty.transport-native-unix-common;version='[4.1.121,4.1.122)',\ + io.netty.codec;version='[4.1.121,4.1.122)',\ + org.apache.aries.rsa.spi;version='[2.0.0,2.0.1)',\ + org.apache.aries.rsa.discovery.local;version='[2.0.0,2.0.1)',\ + org.apache.aries.rsa.discovery.zookeeper;version='[2.0.0,2.0.1)',\ + org.apache.aries.rsa.provider.fastbin;version='[2.0.0,2.0.1)',\ + org.apache.aries.rsa.core;version='[2.0.0,2.0.1)',\ + org.apache.aries.rsa.topology-manager;version='[2.0.0,2.0.1)',\ + org.osgi.test.cases.remoteserviceadmin;version='[8.1.0,8.1.1)' diff --git a/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/Activator.java b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/Activator.java index 17db549a8..d18553406 100644 --- a/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/Activator.java +++ b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/Activator.java @@ -67,7 +67,7 @@ protected void doStart() throws Exception { client = provider.getClient(); server = provider.getServer(); Dictionary props = new Hashtable<>(); - props.put(RemoteConstants.REMOTE_INTENTS_SUPPORTED, new String[]{}); + props.put(RemoteConstants.REMOTE_INTENTS_SUPPORTED, FastBinProvider.SUPPORTED_INTENTS); props.put(RemoteConstants.REMOTE_CONFIGS_SUPPORTED, provider.getSupportedTypes()); register(DistributionProvider.class, provider, props); } diff --git a/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/FastBinProvider.java b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/FastBinProvider.java index 200a8e352..9676498b0 100644 --- a/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/FastBinProvider.java +++ b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/FastBinProvider.java @@ -22,10 +22,15 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.net.URI; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.apache.aries.rsa.provider.fastbin.api.SerializationStrategy; import org.apache.aries.rsa.provider.fastbin.io.ClientInvoker; @@ -37,8 +42,10 @@ import org.apache.aries.rsa.spi.Endpoint; import org.apache.aries.rsa.spi.ImportedService; import org.apache.aries.rsa.spi.IntentUnsatisfiedException; +import org.apache.aries.rsa.util.StringPlus; import org.fusesource.hawtdispatch.Dispatch; import org.fusesource.hawtdispatch.DispatchQueue; +import org.fusesource.hawtdispatch.ShutdownException; import org.osgi.framework.BundleContext; import org.osgi.service.remoteserviceadmin.EndpointDescription; import org.osgi.service.remoteserviceadmin.RemoteConstants; @@ -50,6 +57,8 @@ public class FastBinProvider implements DistributionProvider { private static final Logger LOG = LoggerFactory.getLogger(FastBinProvider.class); + static final String[] SUPPORTED_INTENTS = { "tck.test" }; // at least one intent required by TCK + public static final String FASTBIN_CONFIG_TYPE = "aries.fastbin"; public static final String FASTBIN_ADDRESS = FASTBIN_CONFIG_TYPE + ".address"; @@ -76,7 +85,11 @@ public FastBinProvider(java.lang.String uri, java.lang.String exportedAddress, l } public void close() { - client.stop(); + try { + client.stop(); + } catch (ShutdownException se) { + LOG.trace("exception while shutting down client", se); + } final Semaphore counter = new Semaphore(0); server.stop(() -> counter.release(1)); try { @@ -101,43 +114,38 @@ public String[] getSupportedTypes() { return new String[] {FASTBIN_CONFIG_TYPE}; } + @SafeVarargs + private static Set union(Collection... collections) { + Set union = new HashSet<>(); + for (Collection c : collections) + if (c != null) + union.addAll(c); + return union; + } + @Override public Endpoint exportService(final Object serviceO, BundleContext serviceContext, Map effectiveProperties, Class[] exportedInterfaces) { - // Compute properties - /* - Map properties = new TreeMap(String.CASE_INSENSITIVE_ORDER); - for (String k : reference.getPropertyKeys()) { - properties.put(k, reference.getProperty(k)); - } - // Bail out if there is any intents specified, we don't support any - Set intents = Utils.normalize(properties.get(SERVICE_EXPORTED_INTENTS)); - Set extraIntents = Utils.normalize(properties.get(SERVICE_EXPORTED_INTENTS_EXTRA)); - if (!intents.isEmpty() || !extraIntents.isEmpty()) { - throw new UnsupportedOperationException(); - } - // Bail out if there are any configurations specified, we don't support any - Set configs = Utils.normalize(properties.get(SERVICE_EXPORTED_CONFIGS)); - if (configs.isEmpty()) { - configs.add(CONFIG); - } else if (!configs.contains(CONFIG)) { - throw new UnsupportedOperationException(); + effectiveProperties.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, getSupportedTypes()); + Set intents = union( + StringPlus.normalize(effectiveProperties.get(RemoteConstants.SERVICE_EXPORTED_INTENTS)), + StringPlus.normalize(effectiveProperties.get(RemoteConstants.SERVICE_EXPORTED_INTENTS_EXTRA))); + intents.removeAll(Arrays.asList(SUPPORTED_INTENTS)); + if (!intents.isEmpty()) { + LOG.warn("Unsupported intents found: {}. Not exporting service", intents); + return null; } - URI connectUri = new URI(this.server.getConnectAddress()); - String fabricAddress = connectUri.getScheme() + "://" + exportedAddress + ":" + connectUri.getPort(); - - properties.remove(SERVICE_EXPORTED_CONFIGS); - properties.put(SERVICE_IMPORTED_CONFIGS, new String[] { CONFIG }); - properties.put(ENDPOINT_FRAMEWORK_UUID, this.uuid); - properties.put(FABRIC_ADDRESS, fabricAddress); - - String uuid = UuidGenerator.getUUID(); - properties.put(ENDPOINT_ID, uuid); - */ + // to please the TCK - throw IAE for invalid config-type properties (we don't support any) + Map configProperties = effectiveProperties.entrySet().stream() + .filter(e -> e.getKey().startsWith(FASTBIN_CONFIG_TYPE)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + if (!configProperties.isEmpty()) { + throw new IllegalArgumentException("invalid config-type properties: " + configProperties); + } String endpointId = UuidGenerator.getUUID(); effectiveProperties.put(RemoteConstants.ENDPOINT_ID, endpointId); @@ -145,12 +153,11 @@ public Endpoint exportService(final Object serviceO, URI connectUri = URI.create(this.server.getConnectAddress()); String fastbinAddress = connectUri.getScheme() + "://" + exportedAddress + ":" + connectUri.getPort(); effectiveProperties.put(FASTBIN_ADDRESS, fastbinAddress); - effectiveProperties.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, getSupportedTypes()); + effectiveProperties.put(RemoteConstants.SERVICE_INTENTS, Arrays.asList(SUPPORTED_INTENTS)); - // Now, export the service final EndpointDescription description = new EndpointDescription(effectiveProperties); - // Export it + // export it server.registerService(description.getId(), new ServerInvoker.ServiceFactory() { public Object get() { return serviceO; diff --git a/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/tcp/TcpTransportServer.java b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/tcp/TcpTransportServer.java index a1475c5c2..6fa593a48 100644 --- a/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/tcp/TcpTransportServer.java +++ b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/tcp/TcpTransportServer.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.StandardSocketOptions; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; @@ -29,6 +30,8 @@ import java.nio.channels.SocketChannel; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import org.apache.aries.rsa.provider.fastbin.io.TransportAcceptListener; import org.apache.aries.rsa.provider.fastbin.io.TransportServer; @@ -94,6 +97,7 @@ public void start(Runnable onCompleted) throws Exception { try { channel = ServerSocketChannel.open(); channel.configureBlocking(false); + channel.setOption(StandardSocketOptions.SO_REUSEADDR, true); channel.socket().bind(bindAddress, backlog); } catch (IOException e) { throw new IOException("Failed to bind to server socket: " + bindAddress + " due to: " + e, e); @@ -161,22 +165,39 @@ protected String resolveHostName() { public void stop() { stop(null); } + public void stop(final Runnable onCompleted) { if (acceptSource.isCanceled()) { onCompleted.run(); } else { - acceptSource.setCancelHandler(new Runnable() { - public void run() { - try { - channel.close(); - } catch (IOException e) { - } - if (onCompleted != null) { - onCompleted.run(); - } - } + CountDownLatch latch = new CountDownLatch(1); + acceptSource.setCancelHandler(() -> { + closeChannel(onCompleted); + latch.countDown(); }); acceptSource.cancel(); + // due to a race condition, sometimes during shutdown the hawt dispatcher + // bundle is stopped before we get here, so the handler above will never + // get executed. We give it a chance, but make sure to ultimately close + // the channel anyway to avoid leaving the socket in use. + try { + latch.await(5, TimeUnit.SECONDS); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + if (channel.isOpen()) { // always close at the end + closeChannel(onCompleted); + } + } + } + + private void closeChannel(Runnable onCompleted) { + try { + channel.close(); + } catch (IOException ioe) { + } + if (onCompleted != null) { + onCompleted.run(); } } diff --git a/rsa/src/main/java/org/apache/aries/rsa/core/EventListenerBridge.java b/rsa/src/main/java/org/apache/aries/rsa/core/EventListenerBridge.java index 1030d0cf8..719cfb148 100644 --- a/rsa/src/main/java/org/apache/aries/rsa/core/EventListenerBridge.java +++ b/rsa/src/main/java/org/apache/aries/rsa/core/EventListenerBridge.java @@ -161,8 +161,8 @@ public void ungetService(Bundle bundle, ServiceRegistration reg, Adapte OWN_LISTENER_PROP = EventListenerBridge.class.getName(), ENDPOINT_LISTENER_CLASS_NAME = EndpointListener.class.getName(), ENDPOINT_EVENT_LISTENER_CLASS_NAME = EndpointEventListener.class.getName(), - SERVICE_LISTENER_FILTER = "(|" + getObjectClass(EndpointListener.class) - + getObjectClass(EndpointEventListener.class) + "(" + OWN_LISTENER_PROP + "=true))"; + SERVICE_LISTENER_FILTER = "(&(|" + getObjectClass(EndpointListener.class) + + getObjectClass(EndpointEventListener.class) + ")(!(" + OWN_LISTENER_PROP + "=*)))"; private final Set> oldConsumers = Collections.newSetFromMap(new ConcurrentHashMap<>()); @@ -171,7 +171,7 @@ public void ungetService(Bundle bundle, ServiceRegistration reg, Adapte private final Map producers = new ConcurrentHashMap<>(); // bundleId to producer types bitmap private final BundleContext context; - private ServiceRegistration> factoryRegistration; + private volatile ServiceRegistration> factoryRegistration; private ServiceRegistration hookRegistration; public EventListenerBridge(BundleContext context) { @@ -215,11 +215,18 @@ private String match(ServiceReference sref, EndpointDescription endpoint) { @SuppressWarnings("unchecked") public void start() throws InvalidSyntaxException { - // ServiceListener to track consumers + // add ServiceListener to track new/updated consumers context.addServiceListener(this, SERVICE_LISTENER_FILTER); - // ListenerHook to track what producers are looking for + // process previously registered consumers + ServiceReference[] existing = context.getServiceReferences((String)null, SERVICE_LISTENER_FILTER); + if (existing != null) { + for (ServiceReference sref : existing) { + serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, sref)); + } + } + // register ListenerHook to track what producers are looking for hookRegistration = context.registerService(ListenerHook.class, this, null); - // our listener, backed by a ServiceFactory, to be used by producers + // register our listener, backed by a ServiceFactory, to be used by producers factoryRegistration = (ServiceRegistration>) context.registerService( new String[] { ENDPOINT_LISTENER_CLASS_NAME, ENDPOINT_EVENT_LISTENER_CLASS_NAME }, @@ -251,15 +258,14 @@ private Hashtable getListenerProperties() { @SuppressWarnings("unchecked") public void serviceChanged(ServiceEvent event) { ServiceReference sref = event.getServiceReference(); - boolean ignore = sref.getProperty(OWN_LISTENER_PROP) != null; // ignore our own listener - List classes = Arrays.asList( - (String[])event.getServiceReference().getProperty(Constants.OBJECTCLASS)); + List classes = Arrays.asList((String[])sref.getProperty(Constants.OBJECTCLASS)); boolean el = classes.contains(ENDPOINT_LISTENER_CLASS_NAME); boolean eel = classes.contains(ENDPOINT_EVENT_LISTENER_CLASS_NAME); - if (event.getType() == ServiceEvent.UNREGISTERING || ignore) + if (event.getType() == ServiceEvent.UNREGISTERING) el = eel = false; // remove both // update our consumer lists with relevant one-interface-only consumers - boolean modified = false; + boolean modified = event.getType() == ServiceEvent.MODIFIED + && (oldConsumers.contains(sref) || newConsumers.contains(sref)); if (!el) modified |= oldConsumers.remove(sref); else if (!eel) // only EL (not EEL) @@ -269,7 +275,7 @@ else if (!eel) // only EL (not EEL) else if (!el) // only EEL (not EL) modified |= newConsumers.add((ServiceReference)sref); // update our own listener's scopes accordingly - if (modified) { + if (modified && factoryRegistration != null) { factoryRegistration.setProperties(getListenerProperties()); } }