
io.jsync.net.impl.DefaultNetSocket 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.VoidHandler;
import io.jsync.buffer.Buffer;
import io.jsync.eventbus.Message;
import io.jsync.file.impl.PathAdjuster;
import io.jsync.impl.AsyncInternal;
import io.jsync.impl.DefaultContext;
import io.jsync.impl.DefaultFutureResult;
import io.jsync.net.NetSocket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import java.io.File;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.UUID;
public class DefaultNetSocket extends ConnectionBase implements NetSocket {
private final String writeHandlerID;
private final Handler> writeHandler;
private final TCPSSLHelper helper;
private Handler dataHandler;
private Handler endHandler;
private Handler drainHandler;
private Queue pendingData;
private boolean paused = false;
private boolean client;
private ChannelFuture writeFuture;
public DefaultNetSocket(AsyncInternal async, Channel channel, DefaultContext context, TCPSSLHelper helper, boolean client) {
super(async, channel, context);
this.helper = helper;
this.client = client;
this.writeHandlerID = UUID.randomUUID().toString();
writeHandler = new Handler>() {
public void handle(Message msg) {
write(msg.body());
}
};
async.eventBus().registerLocalHandler(writeHandlerID, writeHandler);
}
@Override
public String writeHandlerID() {
return writeHandlerID;
}
@Override
public NetSocket write(Buffer data) {
ByteBuf buf = data.getByteBuf();
write(buf);
return this;
}
@Override
public NetSocket write(String str) {
write(Unpooled.copiedBuffer(str, CharsetUtil.UTF_8));
return this;
}
@Override
public NetSocket write(String str, String enc) {
if (enc == null) {
write(str);
} else {
write(Unpooled.copiedBuffer(str, Charset.forName(enc)));
}
return this;
}
@Override
public NetSocket dataHandler(Handler dataHandler) {
this.dataHandler = dataHandler;
return this;
}
@Override
public NetSocket pause() {
paused = true;
doPause();
return this;
}
@Override
public NetSocket resume() {
if (!paused) {
return this;
}
paused = false;
if (pendingData != null) {
for (; ; ) {
final Buffer buf = pendingData.poll();
if (buf == null) {
break;
}
async.runOnContext(new VoidHandler() {
@Override
protected void handle() {
handleDataReceived(buf);
}
});
}
}
doResume();
return this;
}
@Override
public NetSocket setWriteQueueMaxSize(int maxSize) {
doSetWriteQueueMaxSize(maxSize);
return this;
}
@Override
public boolean writeQueueFull() {
return doWriteQueueFull();
}
@Override
public NetSocket endHandler(Handler endHandler) {
this.endHandler = endHandler;
return this;
}
@Override
public NetSocket drainHandler(Handler drainHandler) {
this.drainHandler = drainHandler;
async.runOnContext(new VoidHandler() {
public void handle() {
callDrainHandler(); //If the channel is already drained, we want to call it immediately
}
});
return this;
}
@Override
public NetSocket sendFile(String filename) {
return sendFile(filename, null);
}
@Override
public NetSocket sendFile(String filename, final Handler> resultHandler) {
File f = new File(PathAdjuster.adjust(async, filename));
if (f.isDirectory()) {
throw new IllegalArgumentException("filename must point to a file and not to a directory");
}
ChannelFuture future = super.sendFile(f);
if (resultHandler != null) {
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
final AsyncResult res;
if (future.isSuccess()) {
res = new DefaultFutureResult<>((Void) null);
} else {
res = new DefaultFutureResult<>(future.cause());
}
async.runOnContext(new Handler() {
@Override
public void handle(Void v) {
resultHandler.handle(res);
}
});
}
});
}
return this;
}
@Override
public InetSocketAddress remoteAddress() {
return super.remoteAddress();
}
public InetSocketAddress localAddress() {
return super.localAddress();
}
@Override
public NetSocket exceptionHandler(Handler handler) {
this.exceptionHandler = handler;
return this;
}
@Override
public NetSocket closeHandler(Handler handler) {
this.closeHandler = handler;
return this;
}
@Override
public void close() {
if (writeFuture != null) {
// Close after all data is written
writeFuture.addListener(ChannelFutureListener.CLOSE);
channel.flush();
} else {
super.close();
}
}
protected DefaultContext getContext() {
return super.getContext();
}
protected void handleClosed() {
setContext();
if (endHandler != null) {
try {
endHandler.handle(null);
} catch (Throwable t) {
handleHandlerException(t);
}
}
super.handleClosed();
if (async.eventBus() != null) {
async.eventBus().unregisterHandler(writeHandlerID, writeHandler);
}
}
public void handleInterestedOpsChanged() {
setContext();
callDrainHandler();
}
void handleDataReceived(Buffer data) {
if (paused) {
if (pendingData == null) {
pendingData = new ArrayDeque<>();
}
pendingData.add(data);
return;
}
if (dataHandler != null) {
setContext();
try {
dataHandler.handle(data);
} catch (Throwable t) {
handleHandlerException(t);
}
}
}
private void write(ByteBuf buff) {
writeFuture = super.write(buff);
}
private void callDrainHandler() {
if (drainHandler != null) {
if (!writeQueueFull()) {
try {
drainHandler.handle(null);
} catch (Throwable t) {
handleHandlerException(t);
}
}
}
}
@Override
public NetSocket ssl(final Handler handler) {
SslHandler sslHandler = channel.pipeline().get(SslHandler.class);
if (sslHandler == null) {
sslHandler = helper.createSslHandler(async, client);
channel.pipeline().addFirst(sslHandler);
}
sslHandler.handshakeFuture().addListener(new GenericFutureListener>() {
@Override
public void operationComplete(final Future future) throws Exception {
if (context.isOnCorrectWorker(channel.eventLoop())) {
if (future.isSuccess()) {
try {
async.setContext(context);
handler.handle(null);
} catch (Throwable t) {
context.reportException(t);
}
} else {
context.reportException(future.cause());
}
} else {
context.execute(new Runnable() {
public void run() {
if (future.isSuccess()) {
handler.handle(null);
} else {
context.reportException(future.cause());
}
}
});
}
}
});
return this;
}
@Override
public boolean isSsl() {
return channel.pipeline().get(SslHandler.class) != null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy