/* * Copyright (c) 2013 Mike Heath. All rights reserved. * * 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 cloudeventbus.client; import cloudeventbus.Constants; import cloudeventbus.pki.CertificateChain; import cloudeventbus.pki.TrustStore; import io.netty.channel.EventLoopGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.security.PrivateKey; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; /** * Creates a {@link EventBus} client to connect to a Cloud Event Bus cluster. * * <p>Each method, except {@code connect()}, returns {@code this} so that the methods may be used for chained invocation. For example, * * <code> * EventBus eventBus = new Connector().addServer(...).addServer(...).connect(); * </code> * * @author Mike Heath <elcapo@gmail.com> */ public class Connector { /** * The list of candidate servers to connect to. */ final List<SocketAddress> servers = new ArrayList<>(); /** * Indicates if the client should automatically try to reconnect to the Cloud Event Bus cluster if its connection * closes unexpectedly. */ boolean autoReconnect = true; /** * The amount of time to wait before reconnecting to the Cloud Event Bus cluster. */ long reconnectWaitTime = Constants.DEFAULT_RECONNECT_WAIT_TIME; /** * The maximum messages size that can be sent over the network. */ int maxMessageSize = Constants.DEFAULT_MAX_MESSAGE_SIZE; /** * The Netty event loop group to use for connecting to the cluster. */ EventLoopGroup eventLoopGroup; /** * The trust store used for validating the server this client connects to. */ TrustStore trustStore; /** * The certificate chain used to identify this client. */ CertificateChain certificateChain; /** * The private key used to authenticate this client. */ PrivateKey privateKey; /** * The listeners that get invoked when the connection state has changed. */ final List<ConnectionStateListener> listeners = new ArrayList<>(); long id = ThreadLocalRandom.current().nextLong(); /** * Executor to use for invoking callbacks. By default the current thread, usually a Netty IO thread, is used to * invoke callbacks. */ Executor callbackExecutor = new Executor() { private final Logger logger = LoggerFactory.getLogger(getClass()); @Override public void execute(Runnable command) { try { command.run(); } catch (Exception e) { logger.error("Error invoking callback", e); } } }; /** * Adds a server candidate to connect to user the specified host and the default port, 4223. * * @param host the host to connect to. * @see #addServer(java.net.SocketAddress) */ public Connector addServer(String host) { return addServer(host, Constants.DEFAULT_PORT); } /** * Adds a server candidate to connect to user the specified host and port. * * @param host the host to connect to * @param port the port to use * @see #addServer(java.net.SocketAddress) */ public Connector addServer(String host, int port) { return addServer(new InetSocketAddress(host, port)); } /** * Adds a server candidate to connect to. This method may be invoked multiple times to add multiple server * candidates. One of the servers will be chosen at random to connect to. * * @param address the address of the server. * @return this connector. */ public Connector addServer(SocketAddress address) { servers.add(address); return this; } /** * Specifies the amount of time to wait before attempting to reconnect to the Cloud Event Bus cluster. The default * is 5 seconds. * * @param time the amount of time to wait * @param timeUnit the time unit of {@code time} * @return this connector. */ public Connector reconnectWaitTime(long time, TimeUnit timeUnit) { this.reconnectWaitTime = timeUnit.toMillis(time); return this; } /** * Indicates if the client should automatically try to reconnect to the Cloud Event Bus cluster if its connection * closes unexpectedly. * * @param autoReconnect indicates if the client should automatically try to reconnect * @return this connector. */ public Connector autoReconnect(boolean autoReconnect) { this.autoReconnect = autoReconnect; return this; } /** * Specifies the Netty {@code EventLoopGroup} to use for connecting to the Cloud Event Bus cluster. If an event * loop is not specified, one will be created and destroyed when {@link EventBus#close()} * is invoked. * * @param eventLoopGroup the Netty event loop group to use. * @return this connector. */ public Connector eventLoop(EventLoopGroup eventLoopGroup) { this.eventLoopGroup = eventLoopGroup; return this; } /** * Specifies the maximum message size that may be sent over the network. By defaults, this is relatively small to * improve the scalability of the servers. If this value is larger than the value specified by the server this * client connects to, the connection will fail. * * @param maxMessageSize the maximum message size that may be sent over the network in bytes * @return this connector. */ public Connector maxMessageSize(int maxMessageSize) { this.maxMessageSize = maxMessageSize; return this; } /** * Specifies the trust store used for validating the server this client connects to. If a trust store is not * provided, the client will simply not validate any server it connects to. * * @param trustStore the trust store used for validting the server * @return this connector. */ public Connector trustStore(TrustStore trustStore) { this.trustStore = trustStore; return this; } /** * Specifies the certificate chain used to identify this client. If the Cloud Event Bus being connected to does not * require authentication, the certificate chain is not required. * * <p>If a certificate chain is provides, a private key must be provides also, {@link #privateKey(PrivateKey)}. * * @param certificateChain the certificate chain that identifies this client. * @return this connector. */ public Connector certificateChain(CertificateChain certificateChain) { this.certificateChain = certificateChain; return this; } /** * Specifies the private key used to authenticate this client. It is only necessary to provide a private key when a * certificate chain is being provided, {@link #certificateChain(CertificateChain)}. * * @param privateKey the private key used to authenticate this client * @return this connector. */ public Connector privateKey(PrivateKey privateKey) { this.privateKey = privateKey; return this; } /** * Adds a {@link ConnectionStateListener} to the client. This allows you to be notified when a connection is * established, when the server is ready to process messages, and when the connection disconnects. If the * connection to the server closes unexpectedly, the client will automatically try to reconnect to the Cloud * Event Bus cluster. * * @param listener the listener to use * @return this connector. */ public Connector addConnectionStateListener(ConnectionStateListener listener) { listeners.add(listener); return this; } /** * The executor to use for invoking callbacks such as {@link MessageHandler}s and {@link ConnectionStateListener}s. * The default executor uses the Netty IO thread so any blocking in the callback will hold up the client from * publishing or receiving messages. * * @param executor the executor to use for invoking callbacks. * @return this connector. */ public Connector callbackExecutor(Executor executor) { this.callbackExecutor = executor; return this; } /** * Sets the unique id that gets sent to the server. * * @param id the unique id * @return this connector. */ public Connector uniqueId(long id) { this.id = id; return this; } /** * Creates a {@link EventBus} instances and initiates a connection to the Cloud Event Bus cluster. * * @return a {@code EventBus} object. */ public EventBus connect() { return new EventBusImpl(this); } }