All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.chenzw.sms.core.Connection Maven / Gradle / Ivy

The newest version!
package cn.chenzw.sms.core;


import cn.chenzw.sms.core.support.callback.ConnectionCallback;
import cn.chenzw.sms.core.support.callback.SubmitCallback;
import cn.chenzw.sms.core.support.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.*;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 短信连接字符串
 * @author chenzw
 */
public abstract class Connection implements java.io.Closeable {

    protected static final Logger log = LoggerFactory.getLogger(Connection.class);
    private String host;
    private int port;

    private Socket socket;
    private SafeThread heartbeat;
    private SafeThread receiver;
    private boolean autoReconnect;
    private boolean keepAlive;
    private int keepAliveInterval;
    private int sendInterval;
    private Reader in;
    private Writer out;
    private Queue queue;
    private Session session;
    private List callbacks;

    public Connection() {
        super();
        this.autoReconnect = this.keepAlive = true;
        this.keepAliveInterval = 9000;
        this.sendInterval = 50;
        this.queue = new LinkedBlockingQueue();
        this.callbacks = new CopyOnWriteArrayList();
    }

    public Socket getSocket() {
        return socket;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getHost() {
        return host;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public int getPort() {
        return port;
    }

    public boolean isConnected() {
        return socket != null && socket.isConnected();
    }

    public boolean isClosed() {
        return socket == null || socket.isClosed();
    }

    public Boolean getKeepAlive() {
        return keepAlive;
    }

    public void setKeepAlive(Boolean value) {
        keepAlive = value;
    }

    public int getKeepAliveInterval() {
        return keepAliveInterval;
    }

    public void setKeepAliveInterval(int value) {
        this.keepAliveInterval = value;
    }

    public int getSendInterval() {
        return sendInterval;
    }

    public void setSendInterval(int sendInterval) {
        this.sendInterval = sendInterval;
    }

    public boolean isAutoReconnect() {
        return autoReconnect;
    }

    public void setAutoReconnect(boolean autoReconnect) {
        this.autoReconnect = autoReconnect;
    }

    public void registerCallbackHandler(Callback callback) {
        this.callbacks.add(callback);
    }

    public List getRegistedCallbackHandler() {
        return this.callbacks;
    }

    public Session getSession() {
        return session;
    }

    public void send(Message message) {

        if (!isConnected()) {
            queue.offer(message);
        } else {
            Message msg = (Message) queue.poll();
            if (msg != null) {
                send(msg);
            }
            try {
                out.write(message);
                onSend(message);
            } catch (IOException ex) {
                queue.offer(message);
                disconnect();
                onError("socket connection send msg fail,retry:" + message, ex);
            }
        }
    }

    public void connect(String host, int port) {
        this.host = host;
        this.port = port;
        this.connect();
    }

    public void connect() {
        try {
            if (StringUtils.isBlank(host)) {
                throw new IllegalArgumentException("host is null!");
            }
            if ((this.port <= 0) || (this.port > 65535)) {
                log.error(String.format("port error:%d", this.port));
                throw new IndexOutOfBoundsException(String.format("port error:%d", this.port));
            }
            if (!isConnected()) {
                this.socket = new Socket();
                this.socket.setKeepAlive(keepAlive);
                this.socket.connect(new InetSocketAddress(host, port));
                this.out = createWriter(this.socket.getOutputStream());
                this.in = createReader(this.socket.getInputStream());
                this.startThreads();
                this.onConnect();
            }
        } catch (Exception ex) {
            onError("socket connect failure", ex);
        }
    }

    public void disconnect() {

        killThreads();

        if (socket != null) {
            try {
                socket.shutdownInput();
            } catch (IOException ex) { /* do nothing */
                log.error("socket input close failure", ex);
            }
            try {
                socket.shutdownOutput();
            } catch (IOException ex) { /* do nothing */
                log.error("socket outp close failure", ex);
            }
            try {
                socket.close();
                socket = null;
                in = null;
                out = null;
            } catch (IOException ex) { /* do nothing */
                log.error("socket close failure", ex);
            }
        }

        onDisconnect();
    }

    @Override
    public void close() {
        queue.clear();
        autoReconnect = false;
        if (isConnected()) {
            disconnect();
        }
        onClose();
    }

    protected abstract Session createSession();

    protected abstract Writer createWriter(OutputStream output);

    protected abstract Reader createReader(InputStream input);

    protected void heartbeat() throws IOException {
        Session session = getSession();
        if (session != null && session.isAuthenticated()) {
            session.heartbeat();
        }
    }

    protected void onReceive(Message message) throws IOException {
        log.debug("recv: {} ", message);
        if (message != null) {
            Session session = getSession();
            if (session != null) {
                session.process(message);
            }
        }
    }

    protected void onSend(Message message) throws IOException {
        for (Callback callback : this.callbacks) {
            if (callback instanceof SubmitCallback) {
                ((SubmitCallback) callback).onSend(this, message);
            }
        }
        log.debug("send: {}", message);
    }

    protected void onError(String message) {
        log.error(String.format("%s host=%s,port=%d", message, this.getHost(), this.getPort()));
    }

    protected void onError(String message, Exception error) {
        for (Callback callback : this.callbacks) {
            callback.onError(this, error, message);
        }
        log.error(String.format("%s host=%s,port=%d", message, this.getHost(), this.getPort()), error);
    }

    protected void onConnect() {
        for (Callback callback : this.callbacks) {
            if (callback instanceof ConnectionCallback) {
                ((ConnectionCallback) callback).onConnection(this);
            }
        }
        log.debug(String.format("socket connect success host=%s,port=%d %tc%n", this.getHost(), this.getPort(),
                new Date()));
        if (session == null) {
            session = createSession();
        }
        if (session.authenticate()) {
            sendQueue();
        }
    }

    protected void onDisconnect() {
        for (Callback callback : this.callbacks) {
            if (callback instanceof ConnectionCallback) {
                ((ConnectionCallback) callback).onDisconnect(this);
            }
        }
        log.debug(String.format("socket disconnect success host=%s,port=%d %tc%n", this.getHost(), this.getPort(),
                new Date()));
        if (autoReconnect) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) { }
            connect();
        }
    }

    protected void onClose() {
        log.debug(String.format("socket close success host=%s,port=%d %tc%n", this.getHost(), this.getPort(),
                new Date()));
    }

    protected void sendQueue() {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                sendQueue(sendInterval);
            }
        }, "queue");
        t.setDaemon(true);
        t.start();
    }

    private void sendQueue(int speed) {
        do {
            if (isConnected()) {
                Message msg = (Message) queue.poll();
                if (msg != null) {
                    send(msg);
                    try {
                        Thread.sleep(speed);
                    } catch (InterruptedException ex) { }
                }
            } else {
                break;
            }
        } while (queue.size() > 0);
    }

    private void startThreads() {
        if (this.keepAlive && this.keepAliveInterval > 0) {
            this.heartbeat = new SafeThread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(keepAliveInterval);
                    } catch (InterruptedException ex) { }
                    //检查建立socket连接
                    if (isConnected()) {
                        try {
                            if (queue.isEmpty()) {
                                heartbeat();
                            }
                        } catch (IOException ex) {
                            log.error("heartbeat", ex);
                        }
                    }
                }
            }, "heartbeat");
            this.heartbeat.start();
        }

        this.receiver = new SafeThread(new Runnable() {
            @Override
            public void run() {
                //建立socket连接
                if (isConnected()) {
                    try {
                        Message msg = in.read();
                        if (msg != null) {
                            onReceive(msg);
                        } else {
                            //返回空,关闭socket
                            disconnect();
                            onError("socket connection receive msg null");
                        }
                    } catch (IOException ex) {
                        //主线程退出
                        if (Connection.this != null) {
                            Connection.this.disconnect();
                        }
                        onError("socket connection receive msg error: " + ex.getMessage(), ex);
                    }
                }
            }
        }, "receiver");
        this.receiver.start();
    }

    private void killThreads() {
        if (this.heartbeat != null) {
            this.heartbeat.kill();
            this.heartbeat = null;
        }
        if (this.receiver != null) {
            this.receiver.kill();
            this.receiver = null;
        }
    }

    private final class SafeThread extends Thread {
        private boolean alive = true;

        public SafeThread(Runnable target, String name) {
            super(target, name);
            setDaemon(false);
        }

        public void kill() {
            //安全退出线程
            this.alive = false;
        }

        @Override
        public final void run() {
            while (alive) {
                try {
                    super.run();
                } catch (Exception ex) {
                    log.error("thread error 1", ex);
                } catch (Throwable t) {
                    log.error("thread error 2", t);
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy