Java tutorial
/** * Copyright (c) 1997-2013, www.tinygroup.org (luo_guo@icloud.com). * * Licensed under the GPL, Version 3.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.gnu.org/licenses/gpl.html * * 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 org.tinygroup.nettyremote.impl; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPromise; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.serialization.ClassResolvers; import io.netty.handler.codec.serialization.ObjectDecoder; import io.netty.handler.codec.serialization.ObjectEncoder; import io.netty.util.concurrent.Future; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.tinygroup.event.Event; import org.tinygroup.logger.LogLevel; import org.tinygroup.logger.Logger; import org.tinygroup.logger.LoggerFactory; import org.tinygroup.nettyremote.Client; import org.tinygroup.nettyremote.DisconnectCallBack; import org.tinygroup.nettyremote.Exception.TinyRemoteConnectException; public class ClientImpl implements Client { private static final Logger LOGGER = LoggerFactory.getLogger(ClientImpl.class); private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); private EventLoopGroup group = new NioEventLoopGroup(); private int remotePort;// ?? private String remoteHost;// ?? private boolean ready;// ?? private boolean start = false;// ?? private boolean reConnect = false;// ?,??? private int reConnectInterval = 10; // ??: private DisconnectCallBack callBack; private ClientThread clientThread = new ClientThread(); private ChannelFuture future; public ClientImpl(int remotePort, String remoteHost, boolean reConnect) { this.remotePort = remotePort; this.remoteHost = remoteHost; this.reConnect = reConnect; } public void start() { LOGGER.logMessage(LogLevel.INFO, "??{0}:{1}", remoteHost, remotePort); start = false; clientThread.start(); } public void write(Object o) { if (o instanceof Event) { Event event = (Event) o; LOGGER.logMessage(LogLevel.DEBUG, "?:eventId:{},serviceId:{}", event.getEventId(), event.getServiceRequest().getServiceId()); } if (future == null || future.channel() == null) { throw new RuntimeException(""); } ChannelFuture f = future.channel().writeAndFlush(o); if (f instanceof ChannelPromise) { ChannelPromise p = (ChannelPromise) f; try { p.await(); } catch (InterruptedException e) { LOGGER.logMessage(LogLevel.WARN, "?"); } if (p.isSuccess()) { LOGGER.logMessage(LogLevel.DEBUG, "??{}", p.isSuccess()); } else { LOGGER.logMessage(LogLevel.WARN, "??false"); throw new RuntimeException(p.cause()); } } } private void reConnect() { if (!executor.isShutdown()) { // ???????? executor.execute(new Runnable() { public void run() { try { TimeUnit.SECONDS.sleep(reConnectInterval); LOGGER.logMessage(LogLevel.INFO, "??{0}:{1}", remoteHost, remotePort); connect(remotePort, remoteHost);// ??? } catch (InterruptedException e) { // do nothing } } }); } } private void connect(int port, String host) { // ?NIO try { Bootstrap b = new Bootstrap(); b.group(group); init(b); // ?? future = b.connect(host, port).sync(); future.channel().closeFuture().sync(); } catch (Exception e) { LOGGER.errorMessage("?{0}:{1}?", e, remoteHost, remotePort); if (!reConnect) { throw new TinyRemoteConnectException( "?" + remoteHost + ":" + remotePort + "?", e); } } finally { if (reConnect && start) { reConnect(); } } if (callBack != null) { callBack.call(); } } protected void init(Bootstrap b) { b.channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null))); ch.pipeline().addLast("MessageEncoder", new ObjectEncoder()); ch.pipeline().addLast(new ClientHandler()); } }); } class ClientThread extends Thread { public void run() { if (!start) { start = true; LOGGER.logMessage(LogLevel.INFO, "?{0}:{1}", remoteHost, remotePort); connect(remotePort, remoteHost); } } } public void stop() { LOGGER.logMessage(LogLevel.INFO, ""); if (reConnect == true) { reConnect = false; try { executor.shutdownNow(); } catch (Exception e) { LOGGER.errorMessage("?", e); } } start = false; Future wg = null; try { wg = group.shutdownGracefully(); } catch (Exception e) { LOGGER.errorMessage("Client", e); } try { if (wg != null) { wg.await(); } } catch (InterruptedException e) { LOGGER.logMessage(LogLevel.INFO, "EventLoopGroup shutdownGracefully"); } setReady(false); LOGGER.logMessage(LogLevel.INFO, "?"); } public void doReady() { setReady(true); LOGGER.logMessage(LogLevel.INFO, "?{0}:{1}", remoteHost, remotePort); } public boolean isReady() { if (future == null || future.channel() == null) { return false; } return ready; } public void setReady(boolean ready) { this.ready = ready; } public int getRemotePort() { return remotePort; } public void setRemotePort(int remotePort) { this.remotePort = remotePort; } public String getRemoteHost() { return remoteHost; } public void setRemoteHost(String remoteHost) { this.remoteHost = remoteHost; } public void setCallBack(DisconnectCallBack callBack) { this.callBack = callBack; } }