
io.jsync.net.impl.DefaultNetClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsync.io Show documentation
Show all versions of jsync.io Show documentation
jsync.io is a non-blocking, event-driven networking framework for Java
/*
* Copyright (c) 2011-2013 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.jsync.net.impl;
import io.jsync.AsyncResult;
import io.jsync.Handler;
import io.jsync.impl.AsyncInternal;
import io.jsync.impl.Closeable;
import io.jsync.impl.DefaultContext;
import io.jsync.impl.DefaultFutureResult;
import io.jsync.logging.Logger;
import io.jsync.logging.impl.LoggerFactory;
import io.jsync.net.NetClient;
import io.jsync.net.NetSocket;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import javax.net.ssl.SSLContext;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Tim Fox
*/
public class DefaultNetClient implements NetClient {
private static final Logger log = LoggerFactory.getLogger(DefaultNetClient.class);
private final AsyncInternal async;
private final DefaultContext actualCtx;
private final TCPSSLHelper tcpHelper = new TCPSSLHelper();
private final Map socketMap = new ConcurrentHashMap<>();
private final Closeable closeHook = new Closeable() {
@Override
public void close(Handler> doneHandler) {
DefaultNetClient.this.close();
doneHandler.handle(new DefaultFutureResult<>((Void) null));
}
};
private Bootstrap bootstrap;
private int reconnectAttempts;
private long reconnectInterval = 1000;
private boolean configurable = true;
public DefaultNetClient(AsyncInternal async) {
this.async = async;
actualCtx = async.getOrCreateContext();
actualCtx.addCloseHook(closeHook);
}
private static void doFailed(Handler> connectHandler, Throwable t) {
connectHandler.handle(new DefaultFutureResult(t));
}
@Override
public NetClient connect(int port, String host, final Handler> connectHandler) {
connect(port, host, connectHandler, reconnectAttempts);
return this;
}
@Override
public NetClient connect(int port, final Handler> connectCallback) {
connect(port, "localhost", connectCallback);
return this;
}
@Override
public void close() {
for (NetSocket sock : socketMap.values()) {
sock.close();
}
actualCtx.removeCloseHook(closeHook);
}
@Override
public NetClient setReconnectAttempts(int attempts) {
checkConfigurable();
if (attempts < -1) {
throw new IllegalArgumentException("reconnect attempts must be >= -1");
}
this.reconnectAttempts = attempts;
return this;
}
@Override
public int getReconnectAttempts() {
return reconnectAttempts;
}
@Override
public NetClient setReconnectInterval(long interval) {
checkConfigurable();
if (interval < 1) {
throw new IllegalArgumentException("reconnect interval nust be >= 1");
}
this.reconnectInterval = interval;
return this;
}
@Override
public long getReconnectInterval() {
return reconnectInterval;
}
@Override
public boolean isTCPNoDelay() {
return tcpHelper.isTCPNoDelay();
}
@Override
public int getSendBufferSize() {
return tcpHelper.getSendBufferSize();
}
@Override
public int getReceiveBufferSize() {
return tcpHelper.getReceiveBufferSize();
}
@Override
public boolean isTCPKeepAlive() {
return tcpHelper.isTCPKeepAlive();
}
@Override
public boolean isReuseAddress() {
return tcpHelper.isReuseAddress();
}
@Override
public int getSoLinger() {
return tcpHelper.getSoLinger();
}
@Override
public int getTrafficClass() {
return tcpHelper.getTrafficClass();
}
@Override
public int getConnectTimeout() {
return tcpHelper.getConnectTimeout();
}
@Override
public NetClient setTCPNoDelay(boolean tcpNoDelay) {
checkConfigurable();
tcpHelper.setTCPNoDelay(tcpNoDelay);
return this;
}
@Override
public NetClient setSendBufferSize(int size) {
checkConfigurable();
tcpHelper.setSendBufferSize(size);
return this;
}
@Override
public NetClient setReceiveBufferSize(int size) {
checkConfigurable();
tcpHelper.setReceiveBufferSize(size);
return this;
}
@Override
public NetClient setTCPKeepAlive(boolean keepAlive) {
checkConfigurable();
tcpHelper.setTCPKeepAlive(keepAlive);
return this;
}
@Override
public NetClient setReuseAddress(boolean reuse) {
checkConfigurable();
tcpHelper.setReuseAddress(reuse);
return this;
}
@Override
public NetClient setSoLinger(int linger) {
checkConfigurable();
tcpHelper.setSoLinger(linger);
return this;
}
@Override
public NetClient setTrafficClass(int trafficClass) {
checkConfigurable();
tcpHelper.setTrafficClass(trafficClass);
return this;
}
@Override
public NetClient setConnectTimeout(int timeout) {
checkConfigurable();
tcpHelper.setConnectTimeout(timeout);
return this;
}
@Override
public boolean isSSL() {
return tcpHelper.isSSL();
}
@Override
public String getKeyStorePath() {
return tcpHelper.getKeyStorePath();
}
@Override
public String getKeyStorePassword() {
return tcpHelper.getKeyStorePassword();
}
@Override
public String getTrustStorePath() {
return tcpHelper.getTrustStorePath();
}
@Override
public String getTrustStorePassword() {
return tcpHelper.getTrustStorePassword();
}
@Override
public boolean isTrustAll() {
return tcpHelper.isTrustAll();
}
@Override
public NetClient setSSL(boolean ssl) {
checkConfigurable();
tcpHelper.setSSL(ssl);
return this;
}
@Override
public NetClient setSSLContext(SSLContext sslContext) {
checkConfigurable();
tcpHelper.setExternalSSLContext(sslContext);
return this;
}
@Override
public NetClient setKeyStorePath(String path) {
checkConfigurable();
tcpHelper.setKeyStorePath(path);
return this;
}
@Override
public NetClient setKeyStorePassword(String pwd) {
checkConfigurable();
tcpHelper.setKeyStorePassword(pwd);
return this;
}
@Override
public NetClient setTrustStorePath(String path) {
checkConfigurable();
tcpHelper.setTrustStorePath(path);
return this;
}
@Override
public NetClient setTrustStorePassword(String pwd) {
checkConfigurable();
tcpHelper.setTrustStorePassword(pwd);
return this;
}
@Override
public NetClient setTrustAll(boolean trustAll) {
checkConfigurable();
tcpHelper.setTrustAll(trustAll);
return this;
}
@Override
public NetClient setUsePooledBuffers(boolean pooledBuffers) {
checkConfigurable();
tcpHelper.setUsePooledBuffers(pooledBuffers);
return this;
}
@Override
public boolean isUsePooledBuffers() {
return tcpHelper.isUsePooledBuffers();
}
private void checkConfigurable() {
if (!configurable) {
throw new IllegalStateException("Can't set property after connect has been called");
}
}
private void connect(final int port, final String host, final Handler> connectHandler,
final int remainingAttempts) {
if (bootstrap == null) {
tcpHelper.checkSSL(async);
bootstrap = new Bootstrap();
bootstrap.group(actualCtx.getEventLoop());
bootstrap.channel(NioSocketChannel.class);
bootstrap.handler(new ChannelInitializer() {
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
if (tcpHelper.isSSL()) {
SslHandler sslHandler = tcpHelper.createSslHandler(async, true);
pipeline.addLast("ssl", sslHandler);
}
if (tcpHelper.isSSL()) {
// only add ChunkedWriteHandler when SSL is enabled otherwise it is not needed as FileRegion is used.
pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); // For large file / sendfile support
}
pipeline.addLast("handler", new AsyncNetHandler(async, socketMap));
}
});
configurable = false;
}
tcpHelper.applyConnectionOptions(bootstrap);
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture channelFuture) throws Exception {
final Channel ch = channelFuture.channel();
if (channelFuture.isSuccess()) {
if (tcpHelper.isSSL()) {
// TCP connected, so now we must do the SSL handshake
SslHandler sslHandler = ch.pipeline().get(SslHandler.class);
Future fut = sslHandler.handshakeFuture();
fut.addListener(new GenericFutureListener>() {
@Override
public void operationComplete(Future future) throws Exception {
if (future.isSuccess()) {
connected(ch, connectHandler);
} else {
failed(ch, future.cause(), connectHandler);
}
}
});
} else {
connected(ch, connectHandler);
}
} else {
if (remainingAttempts > 0 || remainingAttempts == -1) {
actualCtx.execute(ch.eventLoop(), new Runnable() {
public void run() {
log.debug("Failed to create connection. Will retry in " + reconnectInterval + " milliseconds");
//Set a timer to retry connection
async.setTimer(reconnectInterval, new Handler() {
public void handle(Long timerID) {
connect(port, host, connectHandler, remainingAttempts == -1 ? remainingAttempts : remainingAttempts
- 1);
}
});
}
});
} else {
failed(ch, channelFuture.cause(), connectHandler);
}
}
}
});
}
private void connected(final Channel ch, final Handler> connectHandler) {
actualCtx.execute(ch.eventLoop(), new Runnable() {
public void run() {
doConnected(ch, connectHandler);
}
});
}
private void doConnected(Channel ch, final Handler> connectHandler) {
DefaultNetSocket sock = new DefaultNetSocket(async, ch, actualCtx, tcpHelper, true);
socketMap.put(ch, sock);
connectHandler.handle(new DefaultFutureResult(sock));
}
private void failed(Channel ch, final Throwable t, final Handler> connectHandler) {
ch.close();
actualCtx.execute(ch.eventLoop(), new Runnable() {
public void run() {
doFailed(connectHandler, t);
}
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy