io.dyn.net.tcp.TcpClient.java Source code

Java tutorial

Introduction

Here is the source code for io.dyn.net.tcp.TcpClient.java

Source

/*
 * Copyright (c) 2011-2012 by the original author or authors.
 *
 * 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 io.dyn.net.tcp;

import static io.dyn.el.SpelExpression.*;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.channels.ClosedChannelException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import io.dyn.core.EventedBase;
import io.dyn.core.Events;
import io.dyn.core.Lifecycle;
import io.dyn.core.Tasks;
import io.dyn.core.handler.CompletionHandler;
import io.dyn.core.handler.Handler;
import io.dyn.core.log.Logger;
import io.dyn.core.sys.Sys;
import io.dyn.net.nio.Buffer;
import io.netty.bootstrap.ClientBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPipelineFactory;
import io.netty.channel.Channels;
import io.netty.channel.socket.nio.NioClientSocketChannelFactory;

/**
 * @author Jon Brisbin <jon@jbrisbin.com>
 */
public abstract class TcpClient<T extends TcpClient<? super T>> extends EventedBase<T> implements Lifecycle<T> {

    protected final Logger log = Logger.logger(getClass());

    protected String host = "localhost";
    protected int port = 3000;
    protected boolean keepAlive = true;
    protected int socketTimeout = 2000;
    protected AtomicBoolean started = new AtomicBoolean(false);
    private ClientBootstrap bootstrap = new ClientBootstrap(
            new NioClientSocketChannelFactory(Executors.newCachedThreadPool(),
                    Executors.newCachedThreadPool(Tasks.newThreadFactory(getClass().getSimpleName().toLowerCase())),
                    Sys.PROCESSORS));
    protected ChannelFuture channelFuture;

    {
        on($("#{#this.endsWith('Exception')}"), new Handler<Throwable>() {
            @Override
            public void handle(Throwable t, Object... args) {
                if (!(t instanceof ClosedChannelException)) {
                    String s = t.getMessage();
                    if (null != s) {
                        switch (s) {
                        case "Broken pipe":
                        case "Connection reset by peer":
                            break;
                        default:
                            log.error(t);
                        }
                    }
                }
            }
        });
    }

    public String host() {
        return host;
    }

    @SuppressWarnings({ "unchecked" })
    public T host(String host) {
        this.host = host;
        return (T) this;
    }

    public int port() {
        return port;
    }

    @SuppressWarnings({ "unchecked" })
    public T port(int port) {
        this.port = port;
        return (T) this;
    }

    public boolean keepAlive() {
        return keepAlive;
    }

    @SuppressWarnings({ "unchecked" })
    public T keepAlive(boolean keepAlive) {
        this.keepAlive = keepAlive;
        return (T) this;
    }

    public int socketTimeout() {
        return socketTimeout;
    }

    @SuppressWarnings({ "unchecked" })
    public T socketTimeout(int socketTimeout) {
        this.socketTimeout = socketTimeout;
        return (T) this;
    }

    @SuppressWarnings({ "unchecked" })
    @Override
    public T start() {
        if (!started.get()) {
            on(Lifecycle.STOP, new CompletionHandler() {
                @Override
                protected void complete() {
                    if (channelFuture.awaitUninterruptibly(15, TimeUnit.SECONDS)) {
                        channelFuture.getChannel().close();
                    }
                    started.set(false);
                }
            });
            bootstrap.setOption("child.keepAlive", keepAlive);
            bootstrap.setOption("child.receiveBufferSize", Buffer.SMALL_BUFFER_SIZE);
            bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
                @Override
                public ChannelPipeline getPipeline() throws Exception {
                    final ChannelPipeline pipeline = Channels.pipeline();
                    TcpClient.this.configurePipeline(pipeline);
                    return pipeline;
                }
            });

            try {
                channelFuture = bootstrap.connect(new InetSocketAddress(InetAddress.getByName(host), port));
                channelFuture.addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture channelFuture) throws Exception {
                        if (channelFuture.isSuccess()) {
                            started.set(true);
                            event(Lifecycle.START);
                        } else {
                            Throwable t = channelFuture.getCause();
                            event(Events.classToEventExpression(t.getClass()), t);
                        }
                    }
                });
            } catch (UnknownHostException e) {
                event(Events.classToEventExpression(e.getClass()), e);
            }
        }
        return (T) this;
    }

    @SuppressWarnings({ "unchecked" })
    @Override
    public T stop() {
        if (started.get()) {
            channelFuture.getChannel().close().addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    started.set(false);
                    event(Lifecycle.STOP);
                }
            });
        }
        return (T) this;
    }

    protected abstract void configurePipeline(ChannelPipeline pipeline);

}