amichair commented on code in PR #93: URL: https://github.com/apache/aries-rsa/pull/93#discussion_r3145408482
########## discovery/tcp/src/main/java/org/apache/aries/rsa/discovery/tcp/TcpDiscovery.java: ########## @@ -0,0 +1,204 @@ +/* + * 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.discovery.tcp; + +import org.apache.aries.rsa.annotations.RSADiscoveryProvider; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.remoteserviceadmin.EndpointEventListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.osgi.framework.Constants.FRAMEWORK_UUID; +import static org.osgi.service.component.annotations.ReferenceCardinality.MULTIPLE; +import static org.osgi.service.component.annotations.ReferencePolicy.DYNAMIC; +import static org.osgi.service.remoteserviceadmin.EndpointEventListener.ENDPOINT_LISTENER_SCOPE; +import static org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_FRAMEWORK_UUID; + +/** + * The main TCP Discovery provider component. + * <p> + * It initializes the provider using config admin configuration, + * initializes the interest manager and connection manager, + * registers an EndpointEventListener to track locally exported + * endpoints, and listens for registrations of other + * EndpointEventListeners which are managed by the InterestManager. + */ +@RSADiscoveryProvider(protocols = "aries.tcp") +@Component(immediate = true, configurationPid = "org.apache.aries.rsa.discovery.tcp") +public class TcpDiscovery { + private static final Logger LOG = LoggerFactory.getLogger(TcpDiscovery.class); + private static final String OWN_LISTENER_PROP = "aries.discovery.tcp"; + public static final int DEFAULT_PORT = 7667; + + @interface Config { + String address() default "localhost:" + DEFAULT_PORT; + String bindAddress() default "0.0.0.0"; + String[] peers() default {}; + long reconnectDelay() default 5000; + boolean gossip() default true; + } + + private InterestManager interestManager; + private TcpConnectionManager connectionManager; + private ServiceRegistration<?> listenerRegistration; + + public TcpDiscovery() { + // initialize in constructor before we start getting reference bind events + interestManager = new InterestManager(); + } + + public static URI toURI(String address) { + try { + URI uri = new URI("tcp://" + address); + if (uri.getPort() == -1) { + uri = new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), + DEFAULT_PORT, uri.getPath(), uri.getQuery(), uri.getFragment()); + } + return uri; + } catch (URISyntaxException urise) { + LOG.error("failed to parse address " + address, urise); + throw new RuntimeException(urise); + } + } + + // merge config from ConfigAdmin, framework properties and system properties + @SuppressWarnings("unchecked") + private <T extends Annotation> T mergeConfig(BundleContext context, String prefix, T config) { + Class<T> cls = (Class<T>)config.annotationType(); + return (T)Proxy.newProxyInstance(cls.getClassLoader(), new Class[] { cls }, + (proxy, method, args) -> { + Object value = method.invoke(config, args); + Object defaultValue = method.getDefaultValue(); + if (method.getDeclaringClass() != Object.class && Objects.deepEquals(value, defaultValue)) { + String prop = prefix + method.getName(); + value = context.getProperty(prop); + if (value == null) { + value = System.getProperty(prop); + } + if (value == null) { + value = defaultValue; + } else if (method.getReturnType() == Boolean.TYPE) { + value = Boolean.valueOf(value.toString()); + } else if (method.getReturnType() == Integer.TYPE) { + value = Integer.valueOf(value.toString()); + } else if (method.getReturnType() == Long.TYPE) { + value = Long.valueOf(value.toString()); + } else if (method.getReturnType() == String[].class) { + value = ((String)value).split("\\s*,\\s*"); + } + } else if (method.getDeclaringClass() == Object.class && method.getName().equals("toString")) { + // add a nice toString that shows all merged config names and values (including arrays) + value = Arrays.stream(cls.getMethods()) + .filter(m -> !m.getDeclaringClass().equals(Annotation.class)) // not Object.class! + .collect(Collectors.<Method, String, Object>toMap(Method::getName, m -> { + try { + Object v = m.invoke(proxy); + return (v == null || v instanceof Object[]) ? Arrays.toString((Object[])v) : v.toString(); + } catch (Exception ignore) { + return "<ERROR>"; + } + })).toString(); + } + return value; + }); + } + + private void initConnectionManager(Config config, String uuid) throws IOException { + String address = config.address(); + String bindAddress = config.bindAddress(); + String[] peers = config.peers(); + if (address == null || address.isEmpty() || address.equals("0.0.0.0")) { Review Comment: to what end? it's a single use of a well-known wildcard address in Java and elsewhere. Wouldn't having to lookup the constant just make understanding the code a wee bit harder? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
