com.nesscomputing.service.discovery.client.DiscoveryClientModule Maven / Gradle / Ivy
/**
* Copyright (C) 2012 Ness Computing, Inc.
*
* Licensed 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 com.nesscomputing.service.discovery.client;
import java.net.InetSocketAddress;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.Singleton;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
import com.nesscomputing.config.Config;
import com.nesscomputing.config.ConfigProvider;
import com.nesscomputing.httpclient.guice.HttpClientModule;
import com.nesscomputing.logging.Log;
import com.nesscomputing.service.discovery.client.internal.DiscoveryClientImpl;
import com.nesscomputing.service.discovery.client.internal.ReadOnlyDiscoveryClientImpl;
/**
* Module for the client side of service discovery.
*/
public class DiscoveryClientModule extends AbstractModule
{
public static final String ZOOKEEPER_CONNECT_NAME = "_zookeeper_connect";
public static final Named ZOOKEEPER_CONNECT_NAMED = Names.named(ZOOKEEPER_CONNECT_NAME);
private static final Log LOG = Log.findLog();
private final boolean readOnly;
/**
* Installs a read/write discovery client.
*/
public DiscoveryClientModule()
{
this(false);
}
/**
* Installs a read/write discovery client.
*
* @param readonly - True if the client should be read only (allow service lookup but no announcements.
*/
public DiscoveryClientModule(final boolean readOnly)
{
this.readOnly = readOnly;
}
@Override
public void configure()
{
bind(DiscoveryClientConfig.class).toProvider(ConfigProvider.of(DiscoveryClientConfig.class)).in(Scopes.SINGLETON);
bind(ServiceURIConverter.class).in(Scopes.SINGLETON);
if (readOnly) {
bind(ReadOnlyDiscoveryClient.class).to(ReadOnlyDiscoveryClientImpl.class).in(Scopes.SINGLETON);
}
else {
bind(DiscoveryClient.class).to(DiscoveryClientImpl.class).in(Scopes.SINGLETON);
bind(ReadOnlyDiscoveryClient.class).to(DiscoveryClient.class).in(Scopes.SINGLETON);
bind(ServiceAnnouncer.class).asEagerSingleton();
}
HttpClientModule.bindNewObserver(binder()).to(DiscoveryServiceInterceptor.class);
}
/**
* Register a new Announcement with service discovery. This will only work with the read/write Discovery client and
* it requires binding the ServiceAnnouncer as an eager singleton.
* @return the binding builder you should register with
*/
public static LinkedBindingBuilder bindNewAnnouncement(final Binder binder)
{
return Multibinder.newSetBinder(binder, ServiceInformation.class).addBinding();
}
@Provides
@Singleton
@Named(ZOOKEEPER_CONNECT_NAME)
String getConnectString(@Named(ZOOKEEPER_CONNECT_NAME) final Map zookeeperServers,
final DiscoveryClientConfig clientConfig)
{
final StringBuilder sb = new StringBuilder();
for (final InetSocketAddress address : zookeeperServers.values()) {
if (sb.length() > 0) {
sb.append(",");
}
sb.append(address.getAddress().getHostAddress()).append(":").append(address.getPort());
}
if (sb.length() == 0) {
if (clientConfig.isEnabled()) {
throw new IllegalStateException("Service discovery is enabled but no servers found!");
}
else {
LOG.info("No servers found!");
}
}
return sb.toString();
}
@Provides
@Singleton
@Named(ZOOKEEPER_CONNECT_NAME)
Map getZookeeperServers(final Config config, final DiscoveryClientConfig clientConfig)
{
Map results = Maps.newHashMap();
if (!clientConfig.isEnabled()) {
LOG.warn("Service Discovery is administratively disabled.");
}
else {
final Configuration zookeeperConfig = config.getConfiguration("ness.zookeeper");
// This can be explicitly given to support the "Three servers, one host" configuration.
final String [] servers = zookeeperConfig.getStringArray("clientConnect");
if (ArrayUtils.isNotEmpty(servers)) {
LOG.debug("Found explicit 'ness.zookeeper.clientConnect' string (%s)", StringUtils.join(servers, ","));
int serverId = 1;
for (String server: servers) {
final String parts[] = StringUtils.split(server, ":");
InetSocketAddress serverAddress = new InetSocketAddress(parts[0], Integer.parseInt(parts[1]));
results.put(serverId++, serverAddress);
}
}
else {
LOG.debug("Building connectString from server configuration.");
final int clientPort = zookeeperConfig.getInt("clientPort");
LOG.debug("ness.zookeeper.clientPort is %d", clientPort);
for (final Iterator> it = zookeeperConfig.getKeys("server"); it.hasNext(); ) {
final String key = it.next().toString();
final String [] keyElements = StringUtils.split(key, ".");
final String value = zookeeperConfig.getString(key);
final Integer serverId = Integer.parseInt(keyElements[keyElements.length-1]);
final String parts[] = StringUtils.split(value, ":");
InetSocketAddress serverAddress = new InetSocketAddress(parts[0], clientPort);
results.put(serverId, serverAddress);
LOG.debug("Server # %d : %s", serverId, serverAddress);
}
// If there are less than two servers, this is running in standalone mode. In that case,
// use the clientAddress, because that is what the server will be using.
if (results.size() < 2) {
LOG.info("Found less than two servers, falling back to clientPortAddress/clientPort!");
final String clientAddress = zookeeperConfig.getString("clientPortAddress");
Preconditions.checkState(clientAddress != null, "Client address must not be null!");
final InetSocketAddress serverAddress = new InetSocketAddress(clientAddress, clientPort);
LOG.debug("Server: %s", serverAddress);
results = ImmutableMap.of(1, serverAddress);
}
}
if (LOG.isDebugEnabled()) {
for (Map.Entry entry: results.entrySet()) {
LOG.debug("Server # %d : %s", entry.getKey(), entry.getValue());
}
}
}
return results;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy