package com.twitter.common.zookeeper;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import org.apache.zookeeper.data.ACL;
import com.twitter.common.base.Function;
import com.twitter.common.base.MorePreconditions;
import com.twitter.common.io.Codec;
import com.twitter.thrift.Endpoint;
import com.twitter.thrift.ServiceInstance;
import com.twitter.thrift.Status;
/**
* Common ServerSet related functions
*/
public class ServerSets {
private ServerSets() {
// Utility class.
}
/**
* A function that invokes {@link #toEndpoint(InetSocketAddress)}.
*/
public static final Function<InetSocketAddress, Endpoint> TO_ENDPOINT =
new Function<InetSocketAddress, Endpoint>() {
@Override public Endpoint apply(InetSocketAddress address) {
return ServerSets.toEndpoint(address);
}
};
/**
* Creates a server set that registers at a single path applying the given ACL to all nodes
* created in the path.
*
* @param zkClient ZooKeeper client to register with.
* @param acl The ACL to apply to the {@code zkPath} nodes the ServerSet creates.
* @param zkPath Path to register at. @see #create(ZooKeeperClient, java.util.Set)
* @return A server set that registers at {@code zkPath}.
*/
public static ServerSet create(ZooKeeperClient zkClient, Iterable<ACL> acl, String zkPath) {
return create(zkClient, acl, ImmutableSet.of(zkPath));
}
/**
* Creates a server set that registers at one or multiple paths applying the given ACL to all
* nodes created in the paths.
*
* @param zkClient ZooKeeper client to register with.
* @param acl The ACL to apply to the {@code zkPath} nodes the ServerSet creates.
* @param zkPaths Paths to register at, must be non-empty.
* @return A server set that registers at the given {@code zkPath}s.
*/
public static ServerSet create(ZooKeeperClient zkClient, Iterable<ACL> acl, Set<String> zkPaths) {
Preconditions.checkNotNull(zkClient);
MorePreconditions.checkNotBlank(acl);
MorePreconditions.checkNotBlank(zkPaths);
if (zkPaths.size() == 1) {
return new ServerSetImpl(zkClient, acl, Iterables.getOnlyElement(zkPaths));
} else {
ImmutableList.Builder<ServerSet> builder = ImmutableList.builder();
for (String path : zkPaths) {
builder.add(new ServerSetImpl(zkClient, acl, path));
}
return new CompoundServerSet(builder.build());
}
}
/**
* Returns a serialized Thrift service instance object, with given endpoints and codec.
*
* @param serviceInstance the Thrift service instance object to be serialized
* @param codec the codec to use to serialize a Thrift service instance object
* @return byte array that contains a serialized Thrift service instance
*/
public static byte[] serializeServiceInstance(
ServiceInstance serviceInstance, Codec<ServiceInstance> codec) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
codec.serialize(serviceInstance, output);
return output.toByteArray();
}
/**
* Serializes a service instance based on endpoints.
* @see #serializeServiceInstance(ServiceInstance, Codec)
*
* @param address the target address of the service instance
* @param additionalEndpoints additional endpoints of the service instance
* @param status service status
*/
public static byte[] serializeServiceInstance(
InetSocketAddress address,
Map<String, Endpoint> additionalEndpoints,
Status status,
Codec<ServiceInstance> codec) throws IOException {
ServiceInstance serviceInstance =
new ServiceInstance(toEndpoint(address), additionalEndpoints, status);
return serializeServiceInstance(serviceInstance, codec);
}
/**
* Creates a service instance object deserialized from byte array.
*
* @param data the byte array contains a serialized Thrift service instance
* @param codec the codec to use to deserialize the byte array
*/
public static ServiceInstance deserializeServiceInstance(
byte[] data, Codec<ServiceInstance> codec) throws IOException {
return codec.deserialize(new ByteArrayInputStream(data));
}
/**
* Creates an endpoint for the given InetSocketAddress.
*
* @param address the target address to create the endpoint for
*/
public static Endpoint toEndpoint(InetSocketAddress address) {
return new Endpoint(address.getHostName(), address.getPort());
}
}