From df5743527a94438f5a2047362f566ac25b36cee0 Mon Sep 17 00:00:00 2001 From: lejingw Date: Thu, 30 Jul 2015 10:12:28 +0800 Subject: [PATCH 01/24] add ignore file --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3f4d635a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +*.iml +/build \ No newline at end of file -- Gitee From 0f2472f6639b74c2c3409ffabcda16edbca7cb58 Mon Sep 17 00:00:00 2001 From: lejingw Date: Mon, 3 Aug 2015 16:42:22 +0800 Subject: [PATCH 02/24] update setTopic exception msg --- .gitignore | 2 +- src/main/java/org/zstacks/zbus/client/Consumer.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 3f4d635a..6b534701 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ .idea *.iml -/build \ No newline at end of file +/target \ No newline at end of file diff --git a/src/main/java/org/zstacks/zbus/client/Consumer.java b/src/main/java/org/zstacks/zbus/client/Consumer.java index f56b9806..f58434e0 100644 --- a/src/main/java/org/zstacks/zbus/client/Consumer.java +++ b/src/main/java/org/zstacks/zbus/client/Consumer.java @@ -28,7 +28,7 @@ public class Consumer extends MqAdmin implements Closeable{ public Consumer(MqConfig config){ super(config); - this.topic = config.getTopic(); + setTopic(config.getTopic()); } @@ -135,7 +135,7 @@ public class Consumer extends MqAdmin implements Closeable{ public void setTopic(String topic) { if(!MessageMode.isEnabled(this.mode, MessageMode.PubSub)){ - throw new IllegalStateException("topic support for none-PubSub mode"); + throw new IllegalStateException("topic only support for PubSub mode"); } this.topic = topic; } -- Gitee From 276a066fb0a45bc426d68a2f8447a8bb47f5bed9 Mon Sep 17 00:00:00 2001 From: lejingw Date: Thu, 17 Sep 2015 14:15:29 +0800 Subject: [PATCH 03/24] 1 --- .../zbus/mq/server/support/DiskQueuePool.java | 2 +- src/main/java/org/zbus/net/Client.java | 376 +++++---- src/main/java/org/zbus/net/MsgInvoker.java | 2 +- .../org/zbus/net/core/SelectorThread.java | 471 ++++++----- src/main/java/org/zbus/net/core/Session.java | 732 +++++++++--------- src/main/java/org/zbus/net/http/Message.java | 6 +- .../org/zbus/net/http/MessageAdaptor.java | 199 +++-- .../java/org/zbus/net/http/MessageCodec.java | 144 ++-- .../org/zstacks/zbus/client/Consumer.java | 276 +++---- src/test/java/org/zbus/mq/ProducerSync.java | 2 +- .../org/zbus/mq/diskq/DiskQueueConsume.java | 2 +- .../org/zbus/mq/diskq/DiskQueueProduce.java | 2 +- .../zbus/mq/diskq/MessageDiskQueuePerf.java | 3 +- src/test/java/org/zbus/net/MyClient.java | 7 +- .../java/org/zbus/net/MyServerAdaptor.java | 68 +- .../java/org/zbus/net/codec/StringCodec.java | 58 +- 16 files changed, 1174 insertions(+), 1176 deletions(-) diff --git a/src/main/java/org/zbus/mq/server/support/DiskQueuePool.java b/src/main/java/org/zbus/mq/server/support/DiskQueuePool.java index d34961dd..fedc9f5f 100644 --- a/src/main/java/org/zbus/mq/server/support/DiskQueuePool.java +++ b/src/main/java/org/zbus/mq/server/support/DiskQueuePool.java @@ -110,13 +110,13 @@ public class DiskQueuePool { if (!fileBackupDir.isDirectory()) { throw new IllegalArgumentException("it is not a directory"); } - Map queues = new HashMap(); File[] indexFiles = fileBackupDir.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return DiskQueueIndex.isIndexFile(name); } }); + Map queues = new HashMap(); if (indexFiles != null && indexFiles.length> 0) { for (File indexFile : indexFiles) { String queueName = DiskQueueIndex.parseQueueName(indexFile.getName()); diff --git a/src/main/java/org/zbus/net/Client.java b/src/main/java/org/zbus/net/Client.java index 1ba89204..e370e3df 100644 --- a/src/main/java/org/zbus/net/Client.java +++ b/src/main/java/org/zbus/net/Client.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - * + *

* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + *

* The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + *

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -37,192 +37,190 @@ import org.zbus.net.core.IoAdaptor; import org.zbus.net.core.Session; public class Client extends IoAdaptor implements Closeable { - private static final Logger log = Logger.getLogger(Client.class); - - protected final Dispatcher dispatcher; - protected String host = "127.0.0.1"; - protected int port = 15555; - - protected int readTimeout = 3000; - protected int connectTimeout = 3000; - protected int heartbeatInterval = 60000; // 60s - - protected ConcurrentMap attributes = null; - protected final ScheduledExecutorService heartbeator = Executors.newSingleThreadScheduledExecutor(); - - protected Session session; - - protected volatile MsgHandler msgHandler; - protected ErrorHandler errorHandler; - protected ConnectedHandler connectedHandler; - - public Client(String address, Dispatcher dispatcher) { - String[] blocks = address.split("[:]"); - if(blocks.length != 2){ - throw new IllegalArgumentException(address + " is invalid address"); - } - this.host = blocks[0]; - this.port = Integer.valueOf(blocks[1]); - this.dispatcher = dispatcher; - - dispatcher.start(); - - this.heartbeator.scheduleAtFixedRate(new Runnable() { - public void run() { - heartbeat(); - } - }, heartbeatInterval, heartbeatInterval, TimeUnit.MILLISECONDS); - } - - public Client(String host, int port, Dispatcher dispatcher) { - this(String.format("%s:%d", host, port), dispatcher); - } - - - protected void heartbeat() { - - } - - public boolean hasConnected() { - return session != null && session.isActive(); - } - - public void connectSyncIfNeed() throws IOException { - if (!this.hasConnected()) { - // 同步进行连接操作 - connectAsync(); - this.session.waitToConnect(this.connectTimeout); - } - } - - public void connectAsync() throws IOException { - if (this.session != null) { - if (this.session.isActive() || this.session.isNew()) { - return; - } - } - this.session = dispatcher.registerClientChannel(host, port, this); - } - - @Override - protected void onSessionConnected(Session sess) throws IOException { - super.onSessionConnected(sess); - if(this.connectedHandler != null){ - this.connectedHandler.onConnected(sess); - } else { - log.info("Connected: "+sess); - } - } - - public void send(REQ req) throws IOException{ - connectSyncIfNeed(); - this.session.write(req); - } - - @Override - protected void onMessage(Object obj, Session sess) throws IOException { - @SuppressWarnings("unchecked") - RES res = (RES)obj; - if(msgHandler != null){ - this.msgHandler.handle(res, sess); - return; - } - - log.warn("!!!!!!!!!!!!!!!!!!!!!!!!!!Drop,%s", res); - } - - @Override - protected void onException(Throwable e, Session sess) throws IOException { - if(e instanceof IOException && this.errorHandler != null){ - this.errorHandler.onError((IOException)e, sess); - } else { - super.onException(e, sess); - } - } - - public void onMessage(MsgHandler msgHandler){ - this.msgHandler = msgHandler; - } - - public void onError(ErrorHandler errorHandler){ - this.errorHandler = errorHandler; - } - - public void onConnected(ConnectedHandler connectedHandler){ - this.connectedHandler = connectedHandler; - } - - @Override - public void close() throws IOException { - if (this.session != null) { - this.session.close(); - } - this.heartbeator.shutdown(); - } - - public int getReadTimeout() { - return readTimeout; - } - - public void setReadTimeout(int readTimeout) { - this.readTimeout = readTimeout; - } - - public int getConnectTimeout() { - return connectTimeout; - } - - public void setConnectTimeout(int connectTimeout) { - this.connectTimeout = connectTimeout; - } - - public Session getSession() { - return session; - } - - public ExecutorService getExecutorService(){ - return this.dispatcher.getExecutorService(); - } - - public int getHeartbeatInterval() { - return heartbeatInterval; - } - - public void setHeartbeatInterval(int heartbeatInterval) { - this.heartbeatInterval = heartbeatInterval; - } - - @SuppressWarnings("unchecked") - public V attr(String key) { - if (this.attributes == null) { - return null; - } - - return (V) this.attributes.get(key); - } - - public void attr(String key, V value) { - if (this.attributes == null) { - synchronized (this) { - if (this.attributes == null) { - this.attributes = new ConcurrentHashMap(); - } - } - } - this.attributes.put(key, value); - } - - public static interface ConnectedHandler { - void onConnected(Session sess) throws IOException; - } - - public static interface ErrorHandler { - void onError(IOException e, Session sess) throws IOException; - } - - public static interface MsgHandler { - void handle(T msg, Session sess) throws IOException; - } + private static final Logger log = Logger.getLogger(Client.class); + protected final Dispatcher dispatcher; + protected String host = "127.0.0.1"; + protected int port = 15555; + protected int readTimeout = 3000; + protected int connectTimeout = 3000; + protected int heartbeatInterval = 60000; // 60s + + protected ConcurrentMap attributes = null; + protected final ScheduledExecutorService heartbeator = Executors.newSingleThreadScheduledExecutor(); + + protected Session session; + + protected volatile MsgHandler msgHandler; + protected ErrorHandler errorHandler; + protected ConnectedHandler connectedHandler; + + public Client(String address, Dispatcher dispatcher) { + String[] blocks = address.split("[:]"); + if (blocks.length != 2) { + throw new IllegalArgumentException(address + " is invalid address"); + } + this.host = blocks[0]; + this.port = Integer.valueOf(blocks[1]); + this.dispatcher = dispatcher; + + dispatcher.start(); + + this.heartbeator.scheduleAtFixedRate(new Runnable() { + public void run() { + heartbeat(); + } + }, heartbeatInterval, heartbeatInterval, TimeUnit.MILLISECONDS); + } + + public Client(String host, int port, Dispatcher dispatcher) { + this(String.format("%s:%d", host, port), dispatcher); + } + + + protected void heartbeat() { + + } + + public boolean hasConnected() { + return session != null && session.isActive(); + } + + public void connectSyncIfNeed() throws IOException { + if (!this.hasConnected()) { + // 同步进行连接操作 + connectAsync(); + this.session.waitToConnect(this.connectTimeout); + } + } + + public void connectAsync() throws IOException { + if (this.session != null) { + if (this.session.isActive() || this.session.isNew()) { + return; + } + } + this.session = dispatcher.registerClientChannel(host, port, this); + } + + @Override + protected void onSessionConnected(Session sess) throws IOException { + super.onSessionConnected(sess); + if (this.connectedHandler != null) { + this.connectedHandler.onConnected(sess); + } else { + log.info("Connected: " + sess); + } + } + + public void send(REQ req) throws IOException { + connectSyncIfNeed(); + this.session.write(req); + } + + @Override + protected void onMessage(Object obj, Session sess) throws IOException { + @SuppressWarnings("unchecked") + RES res = (RES) obj; + if (msgHandler != null) { + this.msgHandler.handle(res, sess); + return; + } + + log.warn("!!!!!!!!!!!!!!!!!!!!!!!!!!Drop,%s", res); + } + + @Override + protected void onException(Throwable e, Session sess) throws IOException { + if (e instanceof IOException && this.errorHandler != null) { + this.errorHandler.onError((IOException) e, sess); + } else { + super.onException(e, sess); + } + } + + public void onMessage(MsgHandler msgHandler) { + this.msgHandler = msgHandler; + } + + public void onError(ErrorHandler errorHandler) { + this.errorHandler = errorHandler; + } + + public void onConnected(ConnectedHandler connectedHandler) { + this.connectedHandler = connectedHandler; + } + + @Override + public void close() throws IOException { + if (this.session != null) { + this.session.close(); + } + this.heartbeator.shutdown(); + } + + public int getReadTimeout() { + return readTimeout; + } + + public void setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public Session getSession() { + return session; + } + + public ExecutorService getExecutorService() { + return this.dispatcher.getExecutorService(); + } + + public int getHeartbeatInterval() { + return heartbeatInterval; + } + + public void setHeartbeatInterval(int heartbeatInterval) { + this.heartbeatInterval = heartbeatInterval; + } + + @SuppressWarnings("unchecked") + public V attr(String key) { + if (this.attributes == null) { + return null; + } + + return (V) this.attributes.get(key); + } + + public void attr(String key, V value) { + if (this.attributes == null) { + synchronized (this) { + if (this.attributes == null) { + this.attributes = new ConcurrentHashMap(); + } + } + } + this.attributes.put(key, value); + } + + public interface ConnectedHandler { + void onConnected(Session sess) throws IOException; + } + + public interface ErrorHandler { + void onError(IOException e, Session sess) throws IOException; + } + + public interface MsgHandler { + void handle(T msg, Session sess) throws IOException; + } } diff --git a/src/main/java/org/zbus/net/MsgInvoker.java b/src/main/java/org/zbus/net/MsgInvoker.java index 18a355d1..5782fa3d 100644 --- a/src/main/java/org/zbus/net/MsgInvoker.java +++ b/src/main/java/org/zbus/net/MsgInvoker.java @@ -20,7 +20,7 @@ public interface MsgInvoker { /** * 异步消息模式 * - * @param msg + * @param req * @param callback * @throws IOException */ diff --git a/src/main/java/org/zbus/net/core/SelectorThread.java b/src/main/java/org/zbus/net/core/SelectorThread.java index 827436fc..2c1ff280 100644 --- a/src/main/java/org/zbus/net/core/SelectorThread.java +++ b/src/main/java/org/zbus/net/core/SelectorThread.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - * + *

* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + *

* The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + *

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -37,238 +37,237 @@ import org.zbus.kit.log.Logger; import org.zbus.net.core.Session.SessionStatus; public class SelectorThread extends Thread { - private static final Logger log = Logger.getLogger(SelectorThread.class); - - protected volatile java.nio.channels.Selector selector = null; - protected final Dispatcher dispatcher; - private final Queue register = new LinkedBlockingQueue(); - private final Queue unregister = new LinkedBlockingQueue(); - - public SelectorThread(Dispatcher dispatcher, String name) throws IOException{ - super(name); - this.dispatcher = dispatcher; - this.selector = java.nio.channels.Selector.open(); - } - - public SelectorThread(Dispatcher dispatcher) throws IOException{ - this(dispatcher, "Selector"); - } - - - public void registerChannel(SelectableChannel channel, int ops) throws IOException{ - registerChannel(channel, ops, null); - } - - public void registerSession(int ops, Session sess) throws IOException{ - registerChannel(sess.getChannel(), ops, sess); - } - - public void registerChannel(SelectableChannel channel, int ops, Session sess) throws IOException{ - if(Thread.currentThread() == this){ - SelectionKey key = channel.register(this.selector, ops, sess); - if(sess != null){ - sess.setRegisteredKey(key); - sess.setStatus(SessionStatus.CONNECTED); - sess.getIoAdaptor().onSessionRegistered(sess); - } - } else { - this.register.offer(new Object[]{channel, ops, sess}); - this.selector.wakeup(); - } - } - - public void unregisterSession(Session sess){ - if(this.unregister.contains(sess)){ - return; - } - this.unregister.add(sess); - this.selector.wakeup(); - } - - - @Override - public void interrupt() { - super.interrupt(); - try { - this.selector.close(); - } catch (IOException e) { - log.error(e.getMessage(), e); - } - } - - - @Override - public void run() { - try{ - while(!isInterrupted()){ - selector.select(); - handleRegister(); - - Iterator iter = selector.selectedKeys().iterator(); - while(iter.hasNext()){ - SelectionKey key = iter.next(); - iter.remove(); - if(!key.isValid()) continue; - - Object att = key.attachment(); - if(att != null && att instanceof Session){ - ((Session)att).updateLastOperationTime(); - } - try{ - if(key.isAcceptable()){ - handleAcceptEvent(key); - } else if (key.isConnectable()){ - handleConnectEvent(key); - } else if (key.isReadable()){ - handleReadEvent(key); - } else if (key.isWritable()){ - handleWriteEvent(key); - } - } catch(Throwable e){ - disconnectWithException(key, e); - } - } - handleUnregister(); - } - } catch(Throwable e) { - if(!dispatcher.isStarted()){ - if(log.isDebugEnabled()){ - log.debug(e.getMessage(), e); - } - } else { - log.error(e.getMessage(), e); - } - } - } - - private void disconnectWithException(final SelectionKey key, final Throwable e){ - final Session sess = (Session)key.attachment(); - if(sess == null){ - try{ - key.channel().close(); - key.cancel(); - } catch(Throwable ex){ - log.error(e.getMessage(), ex); - } - return; - } - - sess.setStatus(SessionStatus.ON_ERROR); - dispatcher.asyncRun(new Runnable() { - @Override - public void run() { - try{ - sess.getIoAdaptor().onException(e, sess); - } catch (Throwable ex){ - if(!dispatcher.isStarted()){ - log.debug(ex.getMessage(), ex); - } else { - log.error(ex.getMessage(), ex); - } - } - } - }); - - try{ - sess.close(); - key.cancel(); - } catch(Throwable ex){ - log.error(e.getMessage(), ex); - } - } - - protected void handleRegister(){ - Object[] item = null; - while( (item=this.register.poll()) != null){ - try{ - SelectableChannel channel = (SelectableChannel) item[0]; - if (!channel.isOpen() ) continue; - int ops = (Integer)item[1]; - Session sess = (Session) item[2]; - - SelectionKey key = channel.register(this.selector, ops, sess); - if(sess != null){ - sess.setRegisteredKey(key); - sess.getIoAdaptor().onSessionRegistered(sess); - } - - }catch(Exception e){ - log.error(e.getMessage(), e); - } - } - } - - protected void handleUnregister(){ - Session sess = null; - while( (sess = this.unregister.poll()) != null ){ - try { - sess.close(); - } catch (IOException e) { - log.error(e.getMessage(), e); - } - } - } - - - protected void handleAcceptEvent(SelectionKey key) throws IOException{ - ServerSocketChannel server = (ServerSocketChannel) key.channel(); - - SocketChannel channel = server.accept(); - channel.configureBlocking(false); - - if(log.isDebugEnabled()){ - log.debug("ACCEPT: server(%s) %s=>%s", NetKit.remoteAddress(channel), NetKit.localAddress(channel)); - } - - SocketAddress serverAddress = server.socket().getLocalSocketAddress(); - - IoAdaptor ioAdaptor = dispatcher.ioAdaptor(serverAddress); - if(ioAdaptor == null){ - log.warn("Missing IoAdaptor for %s", serverAddress); - return; - } - - Session sess = new Session(dispatcher, channel, ioAdaptor); - sess.setStatus(SessionStatus.CONNECTED); //set connected - - sess.getIoAdaptor().onSessionAccepted(sess); - - } - - protected void handleConnectEvent(SelectionKey key) throws IOException{ - final SocketChannel channel = (SocketChannel) key.channel(); - - Session sess = (Session) key.attachment(); - if(sess == null){ - throw new IOException("Session not attached yet to SelectionKey"); - } - - if(channel.finishConnect()){ - sess.finishConnect(); - if(log.isDebugEnabled()){ - log.debug("CONNECT: %s=>%s", NetKit.localAddress(channel), NetKit.remoteAddress(channel)); - } - } - sess.setStatus(SessionStatus.CONNECTED); - key.interestOps(0); //!!!clear interest of OP_CONNECT to avoid looping CPU !!! - sess.getIoAdaptor().onSessionConnected(sess); - - } - - protected void handleReadEvent(SelectionKey key) throws IOException{ - Session sess = (Session) key.attachment(); - if(sess == null){ - throw new IOException("Session not attached yet to SelectionKey"); - } - sess.doRead(); - } - - protected void handleWriteEvent(SelectionKey key) throws IOException{ - Session sess = (Session) key.attachment(); - if(sess == null){ - throw new IOException("Session not attached yet to SelectionKey"); - } - sess.doWrite(); - } + private static final Logger log = Logger.getLogger(SelectorThread.class); + + protected volatile java.nio.channels.Selector selector = null; + protected final Dispatcher dispatcher; + private final Queue register = new LinkedBlockingQueue(); + private final Queue unregister = new LinkedBlockingQueue(); + + public SelectorThread(Dispatcher dispatcher, String name) throws IOException { + super(name); + this.dispatcher = dispatcher; + this.selector = java.nio.channels.Selector.open(); + } + + public SelectorThread(Dispatcher dispatcher) throws IOException { + this(dispatcher, "Selector"); + } + + + public void registerChannel(SelectableChannel channel, int ops) throws IOException { + registerChannel(channel, ops, null); + } + + public void registerSession(int ops, Session sess) throws IOException { + registerChannel(sess.getChannel(), ops, sess); + } + + public void registerChannel(SelectableChannel channel, int ops, Session sess) throws IOException { + if (Thread.currentThread() == this) { + SelectionKey key = channel.register(this.selector, ops, sess); + if (sess != null) { + sess.setRegisteredKey(key); + sess.setStatus(SessionStatus.CONNECTED); + sess.getIoAdaptor().onSessionRegistered(sess); + } + } else { + this.register.offer(new Object[]{channel, ops, sess}); + this.selector.wakeup(); + } + } + + public void unregisterSession(Session sess) { + if (this.unregister.contains(sess)) { + return; + } + this.unregister.add(sess); + this.selector.wakeup(); + } + + + @Override + public void interrupt() { + super.interrupt(); + try { + this.selector.close(); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + + + @Override + public void run() { + try { + while (!isInterrupted()) { + selector.select(); + handleRegister(); + + Iterator iter = selector.selectedKeys().iterator(); + while (iter.hasNext()) { + SelectionKey key = iter.next(); + iter.remove(); + if (!key.isValid()) continue; + + Object att = key.attachment(); + if (att != null && att instanceof Session) { + ((Session) att).updateLastOperationTime(); + } + try { + if (key.isAcceptable()) { + handleAcceptEvent(key); + } else if (key.isConnectable()) { + handleConnectEvent(key); + } else if (key.isReadable()) { + handleReadEvent(key); + } else if (key.isWritable()) { + handleWriteEvent(key); + } + } catch (Throwable e) { + disconnectWithException(key, e); + } + } + handleUnregister(); + } + } catch (Throwable e) { + if (!dispatcher.isStarted()) { + if (log.isDebugEnabled()) { + log.debug(e.getMessage(), e); + } + } else { + log.error(e.getMessage(), e); + } + } + } + + private void disconnectWithException(final SelectionKey key, final Throwable e) { + final Session sess = (Session) key.attachment(); + if (sess == null) { + try { + key.channel().close(); + key.cancel(); + } catch (Throwable ex) { + log.error(e.getMessage(), ex); + } + return; + } + + sess.setStatus(SessionStatus.ON_ERROR); + dispatcher.asyncRun(new Runnable() { + @Override + public void run() { + try { + sess.getIoAdaptor().onException(e, sess); + } catch (Throwable ex) { + if (!dispatcher.isStarted()) { + log.debug(ex.getMessage(), ex); + } else { + log.error(ex.getMessage(), ex); + } + } + } + }); + + try { + sess.close(); + key.cancel(); + } catch (Throwable ex) { + log.error(e.getMessage(), ex); + } + } + + protected void handleRegister() { + Object[] item = null; + while ((item = this.register.poll()) != null) { + try { + SelectableChannel channel = (SelectableChannel) item[0]; + if (!channel.isOpen()) continue; + int ops = (Integer) item[1]; + Session sess = (Session) item[2]; + + SelectionKey key = channel.register(this.selector, ops, sess); + if (sess != null) { + sess.setRegisteredKey(key); + sess.getIoAdaptor().onSessionRegistered(sess); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + } + + protected void handleUnregister() { + Session sess = null; + while ((sess = this.unregister.poll()) != null) { + try { + sess.close(); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + } + + + protected void handleAcceptEvent(SelectionKey key) throws IOException { + ServerSocketChannel server = (ServerSocketChannel) key.channel(); + + SocketChannel channel = server.accept(); + channel.configureBlocking(false); + + if (log.isDebugEnabled()) { + log.debug("ACCEPT: server(%s) %s=>%s", NetKit.remoteAddress(channel), NetKit.localAddress(channel)); + } + + SocketAddress serverAddress = server.socket().getLocalSocketAddress(); + + IoAdaptor ioAdaptor = dispatcher.ioAdaptor(serverAddress); + if (ioAdaptor == null) { + log.warn("Missing IoAdaptor for %s", serverAddress); + return; + } + + Session sess = new Session(dispatcher, channel, ioAdaptor); + sess.setStatus(SessionStatus.CONNECTED); //set connected + + sess.getIoAdaptor().onSessionAccepted(sess); + + } + + protected void handleConnectEvent(SelectionKey key) throws IOException { + final SocketChannel channel = (SocketChannel) key.channel(); + + Session sess = (Session) key.attachment(); + if (sess == null) { + throw new IOException("Session not attached yet to SelectionKey"); + } + + if (channel.finishConnect()) { + sess.finishConnect(); + if (log.isDebugEnabled()) { + log.debug("CONNECT: %s=>%s", NetKit.localAddress(channel), NetKit.remoteAddress(channel)); + } + } + sess.setStatus(SessionStatus.CONNECTED); + key.interestOps(0); //!!!clear interest of OP_CONNECT to avoid looping CPU !!! + sess.getIoAdaptor().onSessionConnected(sess); + + } + + protected void handleReadEvent(SelectionKey key) throws IOException { + Session sess = (Session) key.attachment(); + if (sess == null) { + throw new IOException("Session not attached yet to SelectionKey"); + } + sess.doRead(); + } + + protected void handleWriteEvent(SelectionKey key) throws IOException { + Session sess = (Session) key.attachment(); + if (sess == null) { + throw new IOException("Session not attached yet to SelectionKey"); + } + sess.doWrite(); + } } diff --git a/src/main/java/org/zbus/net/core/Session.java b/src/main/java/org/zbus/net/core/Session.java index a7276bce..3b51affd 100644 --- a/src/main/java/org/zbus/net/core/Session.java +++ b/src/main/java/org/zbus/net/core/Session.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - * + *

* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + *

* The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + *

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -39,366 +39,368 @@ import java.util.concurrent.TimeUnit; import org.zbus.kit.NetKit; import org.zbus.kit.log.Logger; -public class Session implements Closeable{ - public static enum SessionStatus { - NEW, CONNECTED, AUTHENED, ON_ERROR, CLOSED - } - private static final Logger log = Logger.getLogger(Session.class); - - private SessionStatus status = SessionStatus.NEW; - private long lastOperationTime = System.currentTimeMillis(); - private final String id; - - private int bufferSize = 1024*8; - private IoBuffer readBuffer = null; - private Queue writeBufferQ = new LinkedBlockingQueue(); - - private CountDownLatch connectLatch = new CountDownLatch(1); - - private final Dispatcher dispatcher; - private final SocketChannel channel; - private SelectionKey registeredKey = null; - - private ConcurrentMap attributes = null; - - private Object attachment; - private volatile IoAdaptor ioAdaptor; - public Session chain; //for chain - - public Session(Dispatcher dispatcher, SocketChannel channel, IoAdaptor ioAdaptor){ - this(dispatcher, channel, null, ioAdaptor); - } - - public Session(Dispatcher dispatcher, SocketChannel channel, Object attachment, IoAdaptor ioAdaptor){ - this.dispatcher = dispatcher; - this.id = UUID.randomUUID().toString(); - this.channel = channel; - this.attachment = attachment; - this.ioAdaptor = ioAdaptor; - } - - - - public String id(){ - return this.id; - } - - public Dispatcher getDispatcher(){ - return this.dispatcher; - } - - public void close() throws IOException { - if(this.status == SessionStatus.CLOSED){ - return; - } - this.status = SessionStatus.CLOSED; - - //放到channel.close前面,避免ClosedChannelException - if(this.registeredKey != null){ - this.registeredKey.cancel(); - this.registeredKey = null; - } - - if(this.channel != null){ - this.channel.close(); - } - - } - - public void asyncClose() throws IOException{ - if(this.registeredKey == null){ - return; - } - SelectorThread selector = dispatcher.getSelector(this.registeredKey); - if(selector == null){ - throw new IOException("failed to find dispatcher for session: "+this); - } - - selector.unregisterSession(this); - } - - public void write(Object msg) throws IOException{ - write(ioAdaptor.encode(msg)); - } - - public void write(IoBuffer buf) throws IOException{ - if(this.registeredKey == null){ - throw new IOException("Session not registered yet:"+this); - } - - if(!writeBufferQ.offer(buf.buf())){ - String msg = "Session write buffer queue is full, message count="+writeBufferQ.size(); - log.warn(msg); - throw new IOException(msg); - } - - registeredKey.interestOps(registeredKey.interestOps() | SelectionKey.OP_WRITE); - registeredKey.selector().wakeup(); //TODO - } - - - - public void doRead() throws IOException { - if(readBuffer == null){ - readBuffer = IoBuffer.allocate(bufferSize); - } - ByteBuffer data = ByteBuffer.allocate(1024*4); - - int n = 0; - while((n = channel.read(data)) > 0){ - data.flip(); - readBuffer.writeBytes(data.array(), data.position(), data.remaining()); - data.clear(); - } - - if(n < 0){ - ioAdaptor.onSessionDestroyed(this); - asyncClose(); - return; - } - - IoBuffer tempBuf = readBuffer.duplicate().flip(); - Object msg = null; - while(true){ - tempBuf.mark(); - if(tempBuf.remaining()>0){ - msg = ioAdaptor.decode(tempBuf); - } else { - msg = null; - } - if(msg == null){ - tempBuf.reset(); - readBuffer = resetIoBuffer(tempBuf); - break; - } - - final Object theMsg = msg; - dispatcher.asyncRun(new Runnable() { - - public void run() { - try{ - ioAdaptor.onMessage(theMsg, Session.this); - } catch(Throwable e){ - log.error(e.getMessage(), e); - try { - ioAdaptor.onException(e, Session.this); - } catch (IOException e1) { - try { - close(); - } catch (Throwable e2) { - log.error(e2.getMessage(), e2); - } - } - } - } - }); - - } - - } - protected IoBuffer resetIoBuffer(IoBuffer buffer) { - IoBuffer newBuffer = null; - - if (buffer != null && buffer.remaining() > 0) { - int len = buffer.remaining(); - byte[] bb = new byte[len]; - buffer.readBytes(bb); - newBuffer = IoBuffer.wrap(bb); - newBuffer.position(len); - } - - return newBuffer; - } - - protected int doWrite() throws IOException{ - int n = 0; - synchronized (writeBufferQ) { - while(true){ - ByteBuffer buf = writeBufferQ.peek(); - if(buf == null){ - registeredKey.interestOps(SelectionKey.OP_READ); - //registeredKey.selector().wakeup(); //TODO - break; - } - - int wbytes = this.channel.write(buf); - - if(wbytes == 0 && buf.remaining() > 0){ - //registeredKey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); - //registeredKey.selector().wakeup(); //TODO - break; - } - - n += wbytes; - if(buf.remaining() == 0){ - writeBufferQ.remove(); - continue; - } else { - break; - } - } - } - return n; - } - - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if(obj instanceof Session){ - Session other = (Session)obj; - return (this.hashCode() == other.hashCode()); - } - return false; - } - - public long getLastOperationTime() { - return lastOperationTime; - } - - public void updateLastOperationTime() { - this.lastOperationTime = System.currentTimeMillis(); - } - - public String getRemoteAddress() { - if (this.status != SessionStatus.CLOSED) { - InetAddress addr = this.channel.socket().getInetAddress(); - if(addr == null) return null; - if(channel.socket() == null) return null; - return String.format("%s:%d", addr.getHostAddress(),channel.socket().getPort()); - } - return null; - } - - public String getLocalAddress() { - if (this.status != SessionStatus.CLOSED) { - return NetKit.localAddress(this.channel); - } - return null; - } - - public int interestOps() throws IOException{ - if(this.registeredKey == null){ - throw new IOException("Session not registered yet:"+this); - } - return this.registeredKey.interestOps(); - } - - public void register(int interestOps) throws IOException{ - dispatcher.registerSession(interestOps, this); - } - - public void interestOps(int ops){ - if(this.registeredKey == null){ - throw new IllegalStateException("registered session required"); - } - this.registeredKey.interestOps(ops); - } - - public void interestOpsAndWakeup(int ops){ - interestOps(ops); - this.registeredKey.selector().wakeup(); - } - - public SelectionKey getRegisteredKey() { - return registeredKey; - } - - public void setRegisteredKey(SelectionKey key) { - this.registeredKey = key; - } - - public void setIoAdaptor(IoAdaptor ioAdaptor){ - this.ioAdaptor = ioAdaptor; - } - - public SessionStatus getStatus() { - return status; - } - - public boolean isActive(){ - return this.status == SessionStatus.CONNECTED; - } - - public boolean isNew(){ - return this.status == SessionStatus.NEW; - } - - public void setStatus(SessionStatus status) { - this.status = status; - } - - public SocketChannel getChannel() { - return channel; - } - - public Dispatcher dispatcher() { - return dispatcher; - } - - public void finishConnect(){ - this.connectLatch.countDown(); - } - - - public boolean waitToConnect(long millis){ - try { - return this.connectLatch.await(millis, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - log.error(e.getMessage(), e); - } - return false; - } - - public void removeAttr(String key){ - if(this.attributes == null) return; - this.attributes.remove(key); - } - - @SuppressWarnings("unchecked") - public T attr(String key){ - if(this.attributes == null){ - return null; - } - - return (T)this.attributes.get(key); - } - - public void attr(String key, T value){ - if(this.attributes == null){ - synchronized (this) { - if(this.attributes == null){ - this.attributes = new ConcurrentHashMap(); - } - } - } - this.attributes.put(key, value); - } - - public String toString() { - return "Session [" - + "remote=" + getRemoteAddress() - + ", status=" + status - + ", id=" + id - + "]"; - } - - - - public Object getAttachment() { - return attachment; - } - - public void setAttachment(Object attachment) { - this.attachment = attachment; - } - - public IoAdaptor getIoAdaptor() { - return ioAdaptor; - } - +public class Session implements Closeable { + public static enum SessionStatus { + NEW, CONNECTED, AUTHENED, ON_ERROR, CLOSED + } + + private static final Logger log = Logger.getLogger(Session.class); + + private SessionStatus status = SessionStatus.NEW; + private long lastOperationTime = System.currentTimeMillis(); + private final String id; + + private int bufferSize = 1024 * 8; + private IoBuffer readBuffer = null; + private Queue writeBufferQ = new LinkedBlockingQueue(); + + private CountDownLatch connectLatch = new CountDownLatch(1); + + private final Dispatcher dispatcher; + private final SocketChannel channel; + private SelectionKey registeredKey = null; + + private ConcurrentMap attributes = null; + + private Object attachment; + private volatile IoAdaptor ioAdaptor; + public Session chain; //for chain + + public Session(Dispatcher dispatcher, SocketChannel channel, IoAdaptor ioAdaptor) { + this(dispatcher, channel, null, ioAdaptor); + } + + public Session(Dispatcher dispatcher, SocketChannel channel, Object attachment, IoAdaptor ioAdaptor) { + this.dispatcher = dispatcher; + this.id = UUID.randomUUID().toString(); + this.channel = channel; + this.attachment = attachment; + this.ioAdaptor = ioAdaptor; + } + + + public String id() { + return this.id; + } + + public Dispatcher getDispatcher() { + return this.dispatcher; + } + + public void close() throws IOException { + if (this.status == SessionStatus.CLOSED) { + return; + } + this.status = SessionStatus.CLOSED; + + //放到channel.close前面,避免ClosedChannelException + if (this.registeredKey != null) { + this.registeredKey.cancel(); + this.registeredKey = null; + } + + if (this.channel != null) { + this.channel.close(); + } + + } + + public void asyncClose() throws IOException { + if (this.registeredKey == null) { + return; + } + SelectorThread selector = dispatcher.getSelector(this.registeredKey); + if (selector == null) { + throw new IOException("failed to find dispatcher for session: " + this); + } + + selector.unregisterSession(this); + } + + public void write(Object msg) throws IOException { + write(ioAdaptor.encode(msg)); + } + + public void write(IoBuffer buf) throws IOException { + if (this.registeredKey == null) { + throw new IOException("Session not registered yet:" + this); + } + + if (!writeBufferQ.offer(buf.buf())) { + String msg = "Session write buffer queue is full, message count=" + writeBufferQ.size(); + log.warn(msg); + throw new IOException(msg); + } + + registeredKey.interestOps(registeredKey.interestOps() | SelectionKey.OP_WRITE); + registeredKey.selector().wakeup(); //TODO + } + + + public void doRead() throws IOException { + if (readBuffer == null) { + readBuffer = IoBuffer.allocate(bufferSize); + } + ByteBuffer data = ByteBuffer.allocate(1024 * 4); + + int n = 0; + while ((n = channel.read(data)) > 0) { + data.flip(); + readBuffer.writeBytes(data.array(), data.position(), data.remaining()); + data.clear(); + } + + if (n < 0) { + ioAdaptor.onSessionDestroyed(this); + asyncClose(); + return; + } + + IoBuffer tempBuf = readBuffer.duplicate().flip(); + Object msg = null; + boolean hasReadMsg = false; + while (true) { + tempBuf.mark(); + if (tempBuf.remaining() > 0) { + msg = ioAdaptor.decode(tempBuf); + } else { + msg = null; + } + if (msg == null) { + tempBuf.reset(); + if (hasReadMsg) { + readBuffer = resetIoBuffer(tempBuf); + } + break; + } + hasReadMsg = true; + final Object theMsg = msg; + dispatcher.asyncRun(new Runnable() { + + public void run() { + try { + ioAdaptor.onMessage(theMsg, Session.this); + } catch (Throwable e) { + log.error(e.getMessage(), e); + try { + ioAdaptor.onException(e, Session.this); + } catch (IOException e1) { + try { + close(); + } catch (Throwable e2) { + log.error(e2.getMessage(), e2); + } + } + } + } + }); + + } + + } + + protected IoBuffer resetIoBuffer(IoBuffer buffer) { + IoBuffer newBuffer = null; + + if (buffer != null && buffer.remaining() > 0) { + int len = buffer.remaining(); + byte[] bb = new byte[len]; + buffer.readBytes(bb); + newBuffer = IoBuffer.wrap(bb); + newBuffer.position(len); + } + + return newBuffer; + } + + protected int doWrite() throws IOException { + int n = 0; + synchronized (writeBufferQ) { + while (true) { + ByteBuffer buf = writeBufferQ.peek(); + if (buf == null) { + registeredKey.interestOps(SelectionKey.OP_READ); + //registeredKey.selector().wakeup(); //TODO + break; + } + + int wbytes = this.channel.write(buf); + + if (wbytes == 0 && buf.remaining() > 0) { + //registeredKey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); + //registeredKey.selector().wakeup(); //TODO + break; + } + + n += wbytes; + if (buf.remaining() == 0) { + writeBufferQ.remove(); + continue; + } else { + break; + } + } + } + return n; + } + + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Session) { + Session other = (Session) obj; + return (this.hashCode() == other.hashCode()); + } + return false; + } + + public long getLastOperationTime() { + return lastOperationTime; + } + + public void updateLastOperationTime() { + this.lastOperationTime = System.currentTimeMillis(); + } + + public String getRemoteAddress() { + if (this.status != SessionStatus.CLOSED) { + InetAddress addr = this.channel.socket().getInetAddress(); + if (addr == null) return null; + if (channel.socket() == null) return null; + return String.format("%s:%d", addr.getHostAddress(), channel.socket().getPort()); + } + return null; + } + + public String getLocalAddress() { + if (this.status != SessionStatus.CLOSED) { + return NetKit.localAddress(this.channel); + } + return null; + } + + public int interestOps() throws IOException { + if (this.registeredKey == null) { + throw new IOException("Session not registered yet:" + this); + } + return this.registeredKey.interestOps(); + } + + public void register(int interestOps) throws IOException { + dispatcher.registerSession(interestOps, this); + } + + public void interestOps(int ops) { + if (this.registeredKey == null) { + throw new IllegalStateException("registered session required"); + } + this.registeredKey.interestOps(ops); + } + + public void interestOpsAndWakeup(int ops) { + interestOps(ops); + this.registeredKey.selector().wakeup(); + } + + public SelectionKey getRegisteredKey() { + return registeredKey; + } + + public void setRegisteredKey(SelectionKey key) { + this.registeredKey = key; + } + + public void setIoAdaptor(IoAdaptor ioAdaptor) { + this.ioAdaptor = ioAdaptor; + } + + public SessionStatus getStatus() { + return status; + } + + public boolean isActive() { + return this.status == SessionStatus.CONNECTED; + } + + public boolean isNew() { + return this.status == SessionStatus.NEW; + } + + public void setStatus(SessionStatus status) { + this.status = status; + } + + public SocketChannel getChannel() { + return channel; + } + + public Dispatcher dispatcher() { + return dispatcher; + } + + public void finishConnect() { + this.connectLatch.countDown(); + } + + + public boolean waitToConnect(long millis) { + try { + return this.connectLatch.await(millis, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + log.error(e.getMessage(), e); + } + return false; + } + + public void removeAttr(String key) { + if (this.attributes == null) return; + this.attributes.remove(key); + } + + @SuppressWarnings("unchecked") + public T attr(String key) { + if (this.attributes == null) { + return null; + } + + return (T) this.attributes.get(key); + } + + public void attr(String key, T value) { + if (this.attributes == null) { + synchronized (this) { + if (this.attributes == null) { + this.attributes = new ConcurrentHashMap(); + } + } + } + this.attributes.put(key, value); + } + + public String toString() { + return "Session [" + + "remote=" + getRemoteAddress() + + ", status=" + status + + ", id=" + id + + "]"; + } + + + public Object getAttachment() { + return attachment; + } + + public void setAttachment(Object attachment) { + this.attachment = attachment; + } + + public IoAdaptor getIoAdaptor() { + return ioAdaptor; + } + } diff --git a/src/main/java/org/zbus/net/http/Message.java b/src/main/java/org/zbus/net/http/Message.java index 3984cc7e..24316f42 100644 --- a/src/main/java/org/zbus/net/http/Message.java +++ b/src/main/java/org/zbus/net/http/Message.java @@ -657,9 +657,9 @@ public class Message implements Id { } } - public static interface MessageHandler extends MsgHandler { } - public static interface MessageInvoker extends MsgInvoker { } - public static interface MessageProcessor { + public interface MessageHandler extends MsgHandler { } + public interface MessageInvoker extends MsgInvoker { } + public interface MessageProcessor { Message process(Message request); } } \ No newline at end of file diff --git a/src/main/java/org/zbus/net/http/MessageAdaptor.java b/src/main/java/org/zbus/net/http/MessageAdaptor.java index 196758d2..707634d0 100644 --- a/src/main/java/org/zbus/net/http/MessageAdaptor.java +++ b/src/main/java/org/zbus/net/http/MessageAdaptor.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - * + *

* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + *

* The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + *

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -31,105 +31,104 @@ import org.zbus.net.core.Session; import org.zbus.net.http.Message.MessageHandler; import org.zbus.net.http.Message.MessageProcessor; -public class MessageAdaptor extends IoAdaptor{ - //全局处理器,优先级最高 - protected MessageHandler filterHandler; - //根据cmd处理,优先级次之 - protected Map cmdHandlerMap = new ConcurrentHashMap(); - //根据Uri处理,优先级最低 - protected Map uriHandlerMap = new ConcurrentHashMap(); - - - public MessageAdaptor(){ - codec(new MessageCodec()); //个性化消息编解码 - this.cmd(Message.HEARTBEAT, new MessageHandler() { - public void handle(Message msg, Session sess) throws IOException { - //ignore - } - }); - } - - public void cmd(String command, MessageHandler handler){ - this.cmdHandlerMap.put(command, handler); +public class MessageAdaptor extends IoAdaptor { + //全局处理器,优先级最高 + protected MessageHandler filterHandler; + //根据cmd处理,优先级次之 + protected Map cmdHandlerMap = new ConcurrentHashMap(); + //根据Uri处理,优先级最低 + protected Map uriHandlerMap = new ConcurrentHashMap(); + + + public MessageAdaptor() { + codec(new MessageCodec()); //个性化消息编解码 + this.cmd(Message.HEARTBEAT, new MessageHandler() { + public void handle(Message msg, Session sess) throws IOException { + //ignore + } + }); + } + + public void cmd(String command, MessageHandler handler) { + this.cmdHandlerMap.put(command, handler); } - - public void uri(String path, final MessageProcessor processor){ - this.uriHandlerMap.put(path, processor); - cmd(path, new MessageHandler() { - @Override - public void handle(Message msg, Session sess) throws IOException { - final String msgId = msg.getId(); - Message res = processor.process(msg); - if(res != null){ - res.setId(msgId); - sess.write(res); - } - } - }); - } - + + public void uri(String path, final MessageProcessor processor) { + this.uriHandlerMap.put(path, processor); + cmd(path, new MessageHandler() { + @Override + public void handle(Message msg, Session sess) throws IOException { + final String msgId = msg.getId(); + Message res = processor.process(msg); + if (res != null) { + res.setId(msgId); + sess.write(res); + } + } + }); + } + public void registerFilterHandler(MessageHandler filterHandler) { - this.filterHandler = filterHandler; - } - - public void onMessage(Object obj, Session sess) throws IOException { - Message msg = (Message)obj; - final String msgId = msg.getId(); - - if(this.filterHandler != null){ - this.filterHandler.handle(msg, sess); - } - - String cmd = msg.getCmd(); - if(cmd != null){ //cmd - MessageHandler handler = cmdHandlerMap.get(cmd); - if(handler != null){ - handler.handle(msg, sess); - return; - } - } - - String path = msg.getRequestPath(); //requestPath - if(path == null){ - Message res = new Message(); - res.setId(msgId); - res.setResponseStatus(400); - res.setBody("Bad Format(400): Missing Command and RequestPath"); - sess.write(res); - return; - } - - MessageProcessor uriHandler = uriHandlerMap.get(path); - if(uriHandler != null){ - Message res = null; - try{ - res = uriHandler.process(msg); - if(res != null){ - res.setId(msgId); - if(res.getResponseStatus() == null){ - res.setResponseStatus(200);// default to 200 - } - sess.write(res); - } - } catch (IOException e){ - throw e; - } catch (Exception e) { - res = new Message(); - res.setResponseStatus(500); - res.setBody("Internal Error(500): " + e); - sess.write(res); - } - - return; - } - - Message res = new Message(); - res.setId(msgId); - res.setResponseStatus(404); - String text = String.format("Not Found(404): %s", path); - res.setBody(text); - sess.write(res); - } + this.filterHandler = filterHandler; + } + + public void onMessage(Object obj, Session sess) throws IOException { + Message msg = (Message) obj; + final String msgId = msg.getId(); + + if (this.filterHandler != null) { + this.filterHandler.handle(msg, sess); + } + + String cmd = msg.getCmd(); + if (cmd != null) { //cmd + MessageHandler handler = cmdHandlerMap.get(cmd); + if (handler != null) { + handler.handle(msg, sess); + return; + } + } + + String path = msg.getRequestPath(); //requestPath + if (path == null) { + Message res = new Message(); + res.setId(msgId); + res.setResponseStatus(400); + res.setBody("Bad Format(400): Missing Command and RequestPath"); + sess.write(res); + return; + } + + MessageProcessor uriHandler = uriHandlerMap.get(path); + if (uriHandler != null) { + Message res = null; + try { + res = uriHandler.process(msg); + if (res != null) { + res.setId(msgId); + if (res.getResponseStatus() == null) { + res.setResponseStatus(200);// default to 200 + } + sess.write(res); + } + } catch (IOException e) { + throw e; + } catch (Exception e) { + res = new Message(); + res.setResponseStatus(500); + res.setBody("Internal Error(500): " + e); + sess.write(res); + } + return; + } + + Message res = new Message(); + res.setId(msgId); + res.setResponseStatus(404); + String text = String.format("Not Found(404): %s", path); + res.setBody(text); + sess.write(res); + } } diff --git a/src/main/java/org/zbus/net/http/MessageCodec.java b/src/main/java/org/zbus/net/http/MessageCodec.java index 00036e2e..fdaf0eef 100644 --- a/src/main/java/org/zbus/net/http/MessageCodec.java +++ b/src/main/java/org/zbus/net/http/MessageCodec.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - * + *

* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + *

* The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + *

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -25,73 +25,73 @@ package org.zbus.net.http; import org.zbus.net.core.Codec; import org.zbus.net.core.IoBuffer; -public class MessageCodec implements Codec{ - - public IoBuffer encode(Object obj) { - if(!(obj instanceof Message)){ - throw new RuntimeException("Message unknown"); - } - - Message msg = (Message)obj; - IoBuffer buf = msg.toIoBuffer(); - return buf; - } - - public Object decode(IoBuffer buf) { - int headerIdx = findHeaderEnd(buf); - if(headerIdx == -1) return null; - - int headerLen = headerIdx+1-buf.position(); - - buf.mark(); - Message msg = new Message(); - msg.decodeHeaders(buf.array(), buf.position(), headerLen); - buf.position(buf.position()+headerLen); - - String contentLength = msg.getHead(Message.CONTENT_LENGTH); - if(contentLength == null){ //just head - return msg; - } - - int bodyLen = Integer.valueOf(contentLength); - if(buf.remaining()()); - - executorService.submit(new Runnable() { - public void run() { - for(;;){ - try { - Message msg; - try { - msg = recv(10000); - } catch (InterruptedException e) { - break; - } - if(msg == null){ - continue; - } - callback.onMessage(msg, client.getSession()); - } catch (IOException e) { - // - } - } - } - }); - - } - - - public String getTopic() { - return topic; - } - - public void setTopic(String topic) { - if(!MessageMode.isEnabled(this.mode, MessageMode.PubSub)){ - throw new IllegalStateException("topic only support for PubSub mode"); - } - this.topic = topic; - } - - public int getMessageCallbackThreadCount() { - return messageCallbackThreadCount; - } - - public void setMessageCallbackThreadCount(int messageCallbackThreadCount) { - this.messageCallbackThreadCount = messageCallbackThreadCount; - } +public class Consumer /*extends MqAdmin implements Closeable*/{ +// private static final Logger log = Logger.getLogger(Consumer.class); +// private RemotingClient client; //消费者拥有一个物理链接 +// //为发布订阅者的主题,当Consumer的模式为发布订阅时候起作用 +// private String topic = null; +// private int messageCallbackThreadCount = 4; +// +// public Consumer(Broker broker, String mq, MessageMode... mode){ +// super(broker, mq, mode); +// } +// +// public Consumer(MqConfig config){ +// super(config); +// setTopic(config.getTopic()); +// } +// +// +// public Message recv(int timeout) throws IOException, InterruptedException{ +// if(this.client == null){ +// this.client = broker.getClient(myClientHint()); +// } +// Message req = new Message(); +// req.setCommand(Proto.Consume); +// req.setMq(mq); +// req.setToken(accessToken); +// if(MessageMode.isEnabled(this.mode, MessageMode.PubSub)){ +// if(this.topic != null){ +// req.setTopic(this.topic); +// } +// } +// +// Message res = null; +// try{ +// res = client.invokeSync(req, timeout); +// if(res != null && res.isStatus404()){ +// if(!this.createMQ()){ +// throw new IllegalStateException("register error"); +// } +// return recv(timeout); +// } +// } catch(IOException e){ +// log.error(e.getMessage(), e); +// try{ +// broker.closeClient(client); +// client = broker.getClient(myClientHint()); +// } catch(IOException ex){ +// log.error(e.getMessage(), e); +// } +// } +// return res; +// } +// +// public void close() throws IOException { +// if(this.client != null){ +// this.broker.closeClient(this.client); +// } +// if(this.executorService != null){ +// this.executorService.shutdown(); +// } +// } +// +// @Override +// protected Message invokeCreateMQ(Message req) throws IOException, InterruptedException { +// if(this.client == null){ +// this.client = broker.getClient(myClientHint()); +// } +// return client.invokeSync(req, invokeTimeout); +// } +// +// +// public void reply(Message msg) throws IOException{ +// if(msg.getStatus() != null){ +// msg.setReplyCode(msg.getStatus()); +// } +// msg.setCommand(Proto.Produce); +// msg.setAck(false); +// client.getSession().write(msg); +// } +// +// +// +// protected ExecutorService executorService = null; +// private MessageCallback callback; +// public void onMessage(MessageCallback cb) throws IOException{ +// this.callback = cb; +// if(executorService != null) return; +// +// executorService = new ThreadPoolExecutor(messageCallbackThreadCount, +// messageCallbackThreadCount, 120, TimeUnit.SECONDS, new LinkedBlockingQueue()); +// +// executorService.submit(new Runnable() { +// public void run() { +// for(;;){ +// try { +// Message msg; +// try { +// msg = recv(10000); +// } catch (InterruptedException e) { +// break; +// } +// if(msg == null){ +// continue; +// } +// callback.onMessage(msg, client.getSession()); +// } catch (IOException e) { +// // +// } +// } +// } +// }); +// +// } +// +// +// public String getTopic() { +// return topic; +// } +// +// public void setTopic(String topic) { +// if(!MessageMode.isEnabled(this.mode, MessageMode.PubSub)){ +// throw new IllegalStateException("topic only support for PubSub mode"); +// } +// this.topic = topic; +// } +// +// public int getMessageCallbackThreadCount() { +// return messageCallbackThreadCount; +// } +// +// public void setMessageCallbackThreadCount(int messageCallbackThreadCount) { +// this.messageCallbackThreadCount = messageCallbackThreadCount; +// } } diff --git a/src/test/java/org/zbus/mq/ProducerSync.java b/src/test/java/org/zbus/mq/ProducerSync.java index 303bc265..00acec59 100644 --- a/src/test/java/org/zbus/mq/ProducerSync.java +++ b/src/test/java/org/zbus/mq/ProducerSync.java @@ -10,7 +10,7 @@ public class ProducerSync { public static void main(String[] args) throws Exception { //创建Broker代理 BrokerConfig config = new BrokerConfig(); - config.setServerAddress("127.0.0.1:15555"); + config.setServerAddress("127.0.0.1:11011"); final Broker broker = new SingleBroker(config); Producer producer = new Producer(broker, "MyMQ"); diff --git a/src/test/java/org/zbus/mq/diskq/DiskQueueConsume.java b/src/test/java/org/zbus/mq/diskq/DiskQueueConsume.java index 3d1cf3f1..a1f9ef2e 100644 --- a/src/test/java/org/zbus/mq/diskq/DiskQueueConsume.java +++ b/src/test/java/org/zbus/mq/diskq/DiskQueueConsume.java @@ -8,7 +8,7 @@ import org.zbus.mq.server.support.DiskQueuePool.DiskQueue; public class DiskQueueConsume { public static void main(String[] args) { - String path = "C:\\DiskQueue"; + String path = "aaabbbccc"; DiskQueuePool.init(path); DiskQueue q = DiskQueuePool.getDiskQueue("test"); diff --git a/src/test/java/org/zbus/mq/diskq/DiskQueueProduce.java b/src/test/java/org/zbus/mq/diskq/DiskQueueProduce.java index 8d740ae7..08fc6f4a 100644 --- a/src/test/java/org/zbus/mq/diskq/DiskQueueProduce.java +++ b/src/test/java/org/zbus/mq/diskq/DiskQueueProduce.java @@ -8,7 +8,7 @@ import org.zbus.mq.server.support.DiskQueuePool.DiskQueue; public class DiskQueueProduce { public static void main(String[] args) { - String path = "mq"; + String path = "aaabbbccc"; DiskQueuePool.init(path); DiskQueue q = DiskQueuePool.getDiskQueue("test"); diff --git a/src/test/java/org/zbus/mq/diskq/MessageDiskQueuePerf.java b/src/test/java/org/zbus/mq/diskq/MessageDiskQueuePerf.java index 59a2a854..7a230b67 100644 --- a/src/test/java/org/zbus/mq/diskq/MessageDiskQueuePerf.java +++ b/src/test/java/org/zbus/mq/diskq/MessageDiskQueuePerf.java @@ -12,8 +12,7 @@ public class MessageDiskQueuePerf { String path = "mq"; DiskQueuePool.init(path); - AbstractQueue q = null; - q = new MessageDiskQueue("test"); + AbstractQueue q = new MessageDiskQueue("test"); long start = System.currentTimeMillis(); diff --git a/src/test/java/org/zbus/net/MyClient.java b/src/test/java/org/zbus/net/MyClient.java index 75dde528..912c0d12 100644 --- a/src/test/java/org/zbus/net/MyClient.java +++ b/src/test/java/org/zbus/net/MyClient.java @@ -9,13 +9,14 @@ public class MyClient { public static void main(String[] args) throws Exception { final Dispatcher dispatcher = new Dispatcher(); - final MessageClient client = new MessageClient("127.0.0.1:80", dispatcher); + final MessageClient client = new MessageClient("127.0.0.1:8080", dispatcher); Message msg = new Message(); msg.setCmd("hello"); - +// msg.setRequestPath("hello"); + msg.setBody("hello world"); - for(int i=0;i<1;i++){ + for(int i=0;i<100;i++){ Message res = client.invokeSync(msg); System.out.println(res); } diff --git a/src/test/java/org/zbus/net/MyServerAdaptor.java b/src/test/java/org/zbus/net/MyServerAdaptor.java index 178db366..da8a011a 100644 --- a/src/test/java/org/zbus/net/MyServerAdaptor.java +++ b/src/test/java/org/zbus/net/MyServerAdaptor.java @@ -9,38 +9,38 @@ import org.zbus.net.http.Message.MessageProcessor; import org.zbus.net.http.MessageAdaptor; -public class MyServerAdaptor extends MessageAdaptor{ - public MyServerAdaptor(){ - uri("/hello", new MessageProcessor() { - - @Override - public Message process(Message request) { - request.setBody("hello"); - return request; - } - }); - } - - public static void main(String[] args) throws Exception { - final Dispatcher dispatcher = new Dispatcher(); - IoAdaptor ioAdaptor = new MyServerAdaptor(); - - final Server server = new Server(dispatcher); - //相同的业务处理逻辑可以便捷的侦听多个地址 - server.registerAdaptor(80, ioAdaptor); - server.registerAdaptor(8080, ioAdaptor); - - server.start(); - - Runtime.getRuntime().addShutdownHook(new Thread(){ - @Override - public void run() { - try { - server.close(); - dispatcher.close(); - } catch (IOException e) { - } - } - }); - } +public class MyServerAdaptor extends MessageAdaptor { + public MyServerAdaptor() { + uri("hello", new MessageProcessor() { + + @Override + public Message process(Message request) { + request.setBody("hello"); + return request; + } + }); + } + + public static void main(String[] args) throws Exception { + final Dispatcher dispatcher = new Dispatcher(); + IoAdaptor ioAdaptor = new MyServerAdaptor(); + + final Server server = new Server(dispatcher); + //相同的业务处理逻辑可以便捷的侦听多个地址 + //server.registerAdaptor(80, ioAdaptor); + server.registerAdaptor(8080, ioAdaptor); + + server.start(); + + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + try { + server.close(); + dispatcher.close(); + } catch (IOException e) { + } + } + }); + } } diff --git a/src/test/java/org/zbus/net/codec/StringCodec.java b/src/test/java/org/zbus/net/codec/StringCodec.java index 437c847b..4f85a965 100644 --- a/src/test/java/org/zbus/net/codec/StringCodec.java +++ b/src/test/java/org/zbus/net/codec/StringCodec.java @@ -3,33 +3,33 @@ package org.zbus.net.codec; import org.zbus.net.core.Codec; import org.zbus.net.core.IoBuffer; -public class StringCodec implements Codec{ - - public IoBuffer encode(Object obj) { - if(!(obj instanceof String)){ - throw new RuntimeException("Message unknown"); - } - - String msg = (String)obj; - byte[] b = msg.getBytes(); - IoBuffer buf = IoBuffer.allocate(4 + b.length); - buf.writeInt(b.length); - buf.writeBytes(b); - - buf.flip(); - return buf; - } - - public Object decode(IoBuffer buf) { - if(buf.remaining() < 4) return null; - buf.mark(); - int len = buf.readInt(); - if(buf.remaining() < len){ - buf.reset(); - return null; - } - byte[] b = new byte[len]; - buf.readBytes(b); - return new String(b); - } +public class StringCodec implements Codec { + + public IoBuffer encode(Object obj) { + if (!(obj instanceof String)) { + throw new RuntimeException("Message unknown"); + } + + String msg = (String) obj; + byte[] b = msg.getBytes(); + IoBuffer buf = IoBuffer.allocate(4 + b.length); + buf.writeInt(b.length); + buf.writeBytes(b); + + buf.flip(); + return buf; + } + + public Object decode(IoBuffer buf) { + if (buf.remaining() < 4) return null; + buf.mark(); + int len = buf.readInt(); + if (buf.remaining() < len) { + buf.reset(); + return null; + } + byte[] b = new byte[len]; + buf.readBytes(b); + return new String(b); + } } \ No newline at end of file -- Gitee From d9932e799b422776ed316f6870279e5ca2880524 Mon Sep 17 00:00:00 2001 From: lejingw Date: Tue, 22 Sep 2015 09:44:05 +0800 Subject: [PATCH 04/24] 1 --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6b534701..22cd7495 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea *.iml -/target \ No newline at end of file +/target +/store \ No newline at end of file -- Gitee From 360d64a132115ab71ff0662e9089800adeeefce6 Mon Sep 17 00:00:00 2001 From: lejingw Date: Tue, 22 Sep 2015 09:44:38 +0800 Subject: [PATCH 05/24] 1 --- ...72\345\205\263\347\263\273\345\233\276.md" | 1 - src/main/java/org/zbus/mq/MqAdmin.java | 121 +++--- src/main/java/org/zbus/mq/Producer.java | 78 ++-- src/main/java/org/zbus/net/Client.java | 393 +++++++++--------- src/main/java/org/zbus/net/Server.java | 218 +++++----- .../org/zbus/net/http/MessageAdaptor.java | 199 ++++----- .../java/org/zbus/net/http/MessageCodec.java | 144 +++---- src/main/java/org/zbus/rpc/mq/Service.java | 1 + src/test/java/org/zbus/mq/ProducerAsync.java | 40 +- src/test/java/org/zbus/mq/ProducerSync.java | 4 +- src/test/java/org/zbus/mq/ServiceExample.java | 70 ++-- src/test/java/org/zbus/net/MyClient.java | 4 +- .../java/org/zbus/net/MyServerAdaptor.java | 68 +-- .../java/org/zbus/net/codec/StringCodec.java | 58 +-- 14 files changed, 710 insertions(+), 689 deletions(-) diff --git "a/doc/02. ZBUS\345\272\224\347\224\250\346\236\204\345\273\272\345\205\263\347\263\273\345\233\276.md" "b/doc/02. ZBUS\345\272\224\347\224\250\346\236\204\345\273\272\345\205\263\347\263\273\345\233\276.md" index f3e26a5b..ce999691 100644 --- "a/doc/02. ZBUS\345\272\224\347\224\250\346\236\204\345\273\272\345\205\263\347\263\273\345\233\276.md" +++ "b/doc/02. ZBUS\345\272\224\347\224\250\346\236\204\345\273\272\345\205\263\347\263\273\345\233\276.md" @@ -13,7 +13,6 @@ ZBUS的消息队列MQ,远程方法调用RPC,总线代理等等功能设计 在消息队列基础上,可以衍生出C=B=S模式:这是CS模式的变种,客户端C请求消息统一到中介商B的队列中,服务端S获取中介商B队列的请求处理后返回给客户端C。这就是借助Broker来实现的C/S模式 -![CBS请求应答](http://git.oschina.net/uploads/images/2015/0701/135128_bc247c16_7458.png "CBS请求应答") Client生产一个请求消息到Broker中,Service消费到请求消息处理后,生产一个应答消息给Broker,最后Client消费到应道消息 diff --git a/src/main/java/org/zbus/mq/MqAdmin.java b/src/main/java/org/zbus/mq/MqAdmin.java index 6cb81a14..366a44a1 100644 --- a/src/main/java/org/zbus/mq/MqAdmin.java +++ b/src/main/java/org/zbus/mq/MqAdmin.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - * + *

* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + *

* The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + *

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -30,63 +30,64 @@ import org.zbus.mq.Protocol.MqMode; import org.zbus.net.http.Message; -public class MqAdmin{ - protected final Broker broker; - protected String mq; //队列唯一性标识 - protected final int mode; - - public MqAdmin(Broker broker, String mq, MqMode... mode){ - this.broker = broker; - this.mq = mq; - if(mode.length == 0){ - this.mode = MqMode.intValue(MqMode.MQ); - } else { - this.mode = MqMode.intValue(mode); - } - } - - public MqAdmin(MqConfig config){ - this.broker = config.getBroker(); - this.mq = config.getMq(); - this.mode = config.getMode(); - } - - protected BrokerHint brokerHint(){ - BrokerHint hint = new BrokerHint(); - hint.setEntry(this.mq); - return hint; - } - - /** - * 默认使用broker代理创建,可以覆盖为Client直接创建,比如Consumer - * @param req - * @return - * @throws IOException - */ - protected Message invokeCreateMQ(Message req) throws IOException, InterruptedException{ - return broker.invokeSync(req, 2500); - } - - public boolean createMQ() throws IOException, InterruptedException{ - Message req = new Message(); - req.setCmd(Protocol.CreateMQ); - req.setHead("mq_name", mq); - req.setHead("mq_mode", "" + mode); - - Message res = invokeCreateMQ(req); - if(res == null) return false; - return res.isStatus200(); - } - - public String getMq() { - return mq; - } +public class MqAdmin { + protected final Broker broker; + protected String mq; //队列唯一性标识 + protected final int mode; - public void setMq(String mq) { - this.mq = mq; - } + public MqAdmin(Broker broker, String mq, MqMode... mode) { + this.broker = broker; + this.mq = mq; + if (mode.length == 0) { + this.mode = MqMode.intValue(MqMode.MQ); + } else { + this.mode = MqMode.intValue(mode); + } + } - public int getMode() { - return mode; - } + public MqAdmin(MqConfig config) { + this.broker = config.getBroker(); + this.mq = config.getMq(); + this.mode = config.getMode(); + } + + protected BrokerHint brokerHint() { + BrokerHint hint = new BrokerHint(); + hint.setEntry(this.mq); + return hint; + } + + /** + * 默认使用broker代理创建,可以覆盖为Client直接创建,比如Consumer + * @param req + * @return + * @throws IOException + */ + protected Message invokeCreateMQ(Message req) throws IOException, InterruptedException { + //TODO + return broker.invokeSync(req, 250000000); + } + + public boolean createMQ() throws IOException, InterruptedException { + Message req = new Message(); + req.setCmd(Protocol.CreateMQ); + req.setHead("mq_name", mq); + req.setHead("mq_mode", "" + mode); + + Message res = invokeCreateMQ(req); + if (res == null) return false; + return res.isStatus200(); + } + + public String getMq() { + return mq; + } + + public void setMq(String mq) { + this.mq = mq; + } + + public int getMode() { + return mode; + } } diff --git a/src/main/java/org/zbus/mq/Producer.java b/src/main/java/org/zbus/mq/Producer.java index 347b3ea1..f3bb90c9 100644 --- a/src/main/java/org/zbus/mq/Producer.java +++ b/src/main/java/org/zbus/mq/Producer.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - * + *

* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + *

* The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + *

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -29,40 +29,40 @@ import org.zbus.mq.Protocol.MqMode; import org.zbus.net.Sync.ResultCallback; import org.zbus.net.http.Message; -public class Producer extends MqAdmin{ - - public Producer(Broker broker, String mq, MqMode... mode) { - super(broker, mq, mode); - } - - public Producer(MqConfig config){ - super(config); - } - - public void sendAsync(Message msg, final ResultCallback callback) - throws IOException { - msg.setCmd(Protocol.Produce); - msg.setMq(this.mq); - msg.setAck(false); - - broker.invokeAsync(msg, callback); - } - - public void sendAsync(Message msg) throws IOException { - sendAsync(msg, null); - } - - - public Message sendSync(Message msg, int timeout) throws IOException, InterruptedException{ - msg.setCmd(Protocol.Produce); - msg.setMq(this.mq); - msg.setAck(true); - - return broker.invokeSync(msg, timeout); - } - - public Message sendSync(Message msg) throws IOException, InterruptedException{ - return sendSync(msg, 10000); - } - +public class Producer extends MqAdmin { + + public Producer(Broker broker, String mq, MqMode... mode) { + super(broker, mq, mode); + } + + public Producer(MqConfig config) { + super(config); + } + + public void sendAsync(Message msg, final ResultCallback callback) + throws IOException { + msg.setCmd(Protocol.Produce); + msg.setMq(this.mq); + msg.setAck(false); + + broker.invokeAsync(msg, callback); + } + + public void sendAsync(Message msg) throws IOException { + sendAsync(msg, null); + } + + + public Message sendSync(Message msg, int timeout) throws IOException, InterruptedException { + msg.setCmd(Protocol.Produce); + msg.setMq(this.mq); + msg.setAck(true); + + return broker.invokeSync(msg, timeout); + } + + public Message sendSync(Message msg) throws IOException, InterruptedException { + return sendSync(msg, 10000); + } + } diff --git a/src/main/java/org/zbus/net/Client.java b/src/main/java/org/zbus/net/Client.java index ed945d52..09200f90 100644 --- a/src/main/java/org/zbus/net/Client.java +++ b/src/main/java/org/zbus/net/Client.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - *

+ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - *

+ * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - *

+ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -37,190 +37,209 @@ import org.zbus.net.core.IoAdaptor; import org.zbus.net.core.Session; public class Client extends IoAdaptor implements Closeable { - private static final Logger log = Logger.getLogger(Client.class); + private static final Logger log = Logger.getLogger(Client.class); + + protected final Dispatcher dispatcher; + protected String host = "127.0.0.1"; + protected int port = 15555; + + protected int readTimeout = 3000; + protected int connectTimeout = 3000; + protected int heartbeatInterval = 60000; // 60s + + protected ConcurrentMap attributes = null; + protected final ScheduledExecutorService heartbeator = Executors.newSingleThreadScheduledExecutor(); + + protected Session session; + + protected volatile MsgHandler msgHandler; + protected ErrorHandler errorHandler; + protected ConnectedHandler connectedHandler; + protected DisconnectedHandler disconnectedHandler; + + public Client(String address, Dispatcher dispatcher) { + String[] blocks = address.split("[:]"); + if(blocks.length != 2){ + throw new IllegalArgumentException(address + " is invalid address"); + } + this.host = blocks[0]; + this.port = Integer.valueOf(blocks[1]); + this.dispatcher = dispatcher; + + dispatcher.start(); + + this.heartbeator.scheduleAtFixedRate(new Runnable() { + public void run() { + heartbeat(); + } + }, heartbeatInterval, heartbeatInterval, TimeUnit.MILLISECONDS); + } + + public Client(String host, int port, Dispatcher dispatcher) { + this(String.format("%s:%d", host, port), dispatcher); + } + + + protected void heartbeat() { + + } + + public boolean hasConnected() { + return session != null && session.isActive(); + } + + public void connectSyncIfNeed() throws IOException { + if (!this.hasConnected()) { + // 同步进行连接操作 + connectAsync(); + this.session.waitToConnect(this.connectTimeout); + } + } + + public void connectAsync() throws IOException { + if (this.session != null) { + if (this.session.isActive() || this.session.isNew()) { + return; + } + } + this.session = dispatcher.registerClientChannel(host, port, this); + } + + @Override + protected void onSessionConnected(Session sess) throws IOException { + super.onSessionConnected(sess); + if(this.connectedHandler != null){ + this.connectedHandler.onConnected(sess); + } else { + log.info("Connected: "+sess); + } + } + + public void send(REQ req) throws IOException{ + connectSyncIfNeed(); + this.session.write(req); + } + + @Override + protected void onMessage(Object obj, Session sess) throws IOException { + @SuppressWarnings("unchecked") + RES res = (RES)obj; + if(msgHandler != null){ + this.msgHandler.handle(res, sess); + return; + } + + log.warn("!!!!!!!!!!!!!!!!!!!!!!!!!!Drop,%s", res); + } + + @Override + protected void onException(Throwable e, Session sess) throws IOException { + if(e instanceof IOException && this.errorHandler != null){ + this.errorHandler.onError((IOException)e, sess); + } else { + super.onException(e, sess); + } + } + + @Override + protected void onSessionDestroyed(Session sess) throws IOException { + super.onSessionDestroyed(sess); + if(disconnectedHandler != null){ + disconnectedHandler.onDisconnected(); + } + } + + public void onMessage(MsgHandler msgHandler){ + this.msgHandler = msgHandler; + } + + public void onError(ErrorHandler errorHandler){ + this.errorHandler = errorHandler; + } + + public void onConnected(ConnectedHandler connectedHandler){ + this.connectedHandler = connectedHandler; + } + + public void onDisconnected(DisconnectedHandler disconnectedHandler){ + this.disconnectedHandler = disconnectedHandler; + } + + @Override + public void close() throws IOException { + if (this.session != null) { + this.session.close(); + } + this.heartbeator.shutdown(); + } + + public int getReadTimeout() { + return readTimeout; + } + + public void setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public Session getSession() { + return session; + } + + public ExecutorService getExecutorService(){ + return this.dispatcher.getExecutorService(); + } + + public int getHeartbeatInterval() { + return heartbeatInterval; + } + + public void setHeartbeatInterval(int heartbeatInterval) { + this.heartbeatInterval = heartbeatInterval; + } + + @SuppressWarnings("unchecked") + public V attr(String key) { + if (this.attributes == null) { + return null; + } + + return (V) this.attributes.get(key); + } + + public void attr(String key, V value) { + if (this.attributes == null) { + synchronized (this) { + if (this.attributes == null) { + this.attributes = new ConcurrentHashMap(); + } + } + } + this.attributes.put(key, value); + } + + public static interface ConnectedHandler { + void onConnected(Session sess) throws IOException; + } + + public static interface DisconnectedHandler { + void onDisconnected() throws IOException; + } + + public static interface ErrorHandler { + void onError(IOException e, Session sess) throws IOException; + } + + public static interface MsgHandler { + void handle(T msg, Session sess) throws IOException; + } - protected final Dispatcher dispatcher; - protected String host = "127.0.0.1"; - protected int port = 15555; - protected int readTimeout = 3000; - protected int connectTimeout = 3000; - protected int heartbeatInterval = 60000; // 60s - - protected ConcurrentMap attributes = null; - protected final ScheduledExecutorService heartbeator = Executors.newSingleThreadScheduledExecutor(); - - protected Session session; - - protected volatile MsgHandler msgHandler; - protected ErrorHandler errorHandler; - protected ConnectedHandler connectedHandler; - - public Client(String address, Dispatcher dispatcher) { - String[] blocks = address.split("[:]"); - if (blocks.length != 2) { - throw new IllegalArgumentException(address + " is invalid address"); - } - this.host = blocks[0]; - this.port = Integer.valueOf(blocks[1]); - this.dispatcher = dispatcher; - - dispatcher.start(); - - this.heartbeator.scheduleAtFixedRate(new Runnable() { - public void run() { - heartbeat(); - } - }, heartbeatInterval, heartbeatInterval, TimeUnit.MILLISECONDS); - } - - public Client(String host, int port, Dispatcher dispatcher) { - this(String.format("%s:%d", host, port), dispatcher); - } - - - protected void heartbeat() { - - } - - public boolean hasConnected() { - return session != null && session.isActive(); - } - - public void connectSyncIfNeed() throws IOException { - if (!this.hasConnected()) { - // 同步进行连接操作 - connectAsync(); - this.session.waitToConnect(this.connectTimeout); - } - } - - public void connectAsync() throws IOException { - if (this.session != null) { - if (this.session.isActive() || this.session.isNew()) { - return; - } - } - this.session = dispatcher.registerClientChannel(host, port, this); - } - - @Override - protected void onSessionConnected(Session sess) throws IOException { - super.onSessionConnected(sess); - if (this.connectedHandler != null) { - this.connectedHandler.onConnected(sess); - } else { - log.info("Connected: " + sess); - } - } - - public void send(REQ req) throws IOException { - connectSyncIfNeed(); - this.session.write(req); - } - - @Override - protected void onMessage(Object obj, Session sess) throws IOException { - @SuppressWarnings("unchecked") - RES res = (RES) obj; - if (msgHandler != null) { - this.msgHandler.handle(res, sess); - return; - } - - log.warn("!!!!!!!!!!!!!!!!!!!!!!!!!!Drop,%s", res); - } - - @Override - protected void onException(Throwable e, Session sess) throws IOException { - if (e instanceof IOException && this.errorHandler != null) { - this.errorHandler.onError((IOException) e, sess); - } else { - super.onException(e, sess); - } - } - - public void onMessage(MsgHandler msgHandler) { - this.msgHandler = msgHandler; - } - - public void onError(ErrorHandler errorHandler) { - this.errorHandler = errorHandler; - } - - public void onConnected(ConnectedHandler connectedHandler) { - this.connectedHandler = connectedHandler; - } - - @Override - public void close() throws IOException { - if (this.session != null) { - this.session.close(); - } - this.heartbeator.shutdown(); - } - - public int getReadTimeout() { - return readTimeout; - } - - public void setReadTimeout(int readTimeout) { - this.readTimeout = readTimeout; - } - - public int getConnectTimeout() { - return connectTimeout; - } - - public void setConnectTimeout(int connectTimeout) { - this.connectTimeout = connectTimeout; - } - - public Session getSession() { - return session; - } - - public ExecutorService getExecutorService() { - return this.dispatcher.getExecutorService(); - } - - public int getHeartbeatInterval() { - return heartbeatInterval; - } - - public void setHeartbeatInterval(int heartbeatInterval) { - this.heartbeatInterval = heartbeatInterval; - } - - @SuppressWarnings("unchecked") - public V attr(String key) { - if (this.attributes == null) { - return null; - } - - return (V) this.attributes.get(key); - } - - public void attr(String key, V value) { - if (this.attributes == null) { - synchronized (this) { - if (this.attributes == null) { - this.attributes = new ConcurrentHashMap(); - } - } - } - this.attributes.put(key, value); - } - - public interface ConnectedHandler { - void onConnected(Session sess) throws IOException; - } - - public interface ErrorHandler { - void onError(IOException e, Session sess) throws IOException; - } - - public interface MsgHandler { - void handle(T msg, Session sess) throws IOException; - } } diff --git a/src/main/java/org/zbus/net/Server.java b/src/main/java/org/zbus/net/Server.java index 0ba41e21..3f5c4bc7 100644 --- a/src/main/java/org/zbus/net/Server.java +++ b/src/main/java/org/zbus/net/Server.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - * + *

* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + *

* The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + *

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -34,111 +34,111 @@ import org.zbus.kit.log.Logger; import org.zbus.net.core.Dispatcher; import org.zbus.net.core.IoAdaptor; -public class Server implements Closeable{ - private static final Logger log = Logger.getLogger(Server.class); - - private static class IoAdaptorInfo{ - public String adaptorName; - public String adaptorAddr; - public ServerSocketChannel serverChannel; - public IoAdaptor serverAdaptor; - } - - protected Dispatcher dispatcher; - protected String serverAddr; //第一个Server注册的地址 - protected String serverName = "Server"; - - protected Map adaptors = new ConcurrentHashMap(); - - public Server(){ - } - - public Server(Dispatcher dispatcher){ - this.dispatcher = dispatcher; - } - - public Server(Dispatcher dispatcher, IoAdaptor serverAdaptor, int port){ - this(dispatcher, serverAdaptor, "0.0.0.0:"+port); - } - - public Server(Dispatcher dispatcher, IoAdaptor serverAdaptor, String address){ - this.dispatcher = dispatcher; - registerAdaptor(address, serverAdaptor); - } - - public void registerAdaptor(int port, IoAdaptor ioAdaptor){ - registerAdaptor("0.0.0.0:"+port, ioAdaptor, null); - } - - public void registerAdaptor(int port, IoAdaptor ioAdaptor, String name){ - registerAdaptor("0.0.0.0:"+port, ioAdaptor, name); - } - - public void registerAdaptor(String address, IoAdaptor ioAdaptor){ - registerAdaptor(address, ioAdaptor, null); - } - - public void registerAdaptor(String address, IoAdaptor ioAdaptor, String name){ - IoAdaptorInfo adaptor = new IoAdaptorInfo(); - String[] blocks = address.split("[:]"); - if(blocks.length != 2){ - throw new IllegalArgumentException(address + " is invalid address"); - } - adaptor.adaptorName = name; - adaptor.adaptorAddr = address; - adaptor.serverAdaptor = ioAdaptor; - - if(adaptors.isEmpty()){ - this.serverAddr = address; - String host = blocks[0]; - int port = Integer.valueOf(blocks[1]); - if("0.0.0.0".equals(host)){ - this.serverAddr = String.format("%s:%d",NetKit.getLocalIp(), port); - } - } - - adaptors.put(address, adaptor); - } - - public void start() throws IOException{ - if(dispatcher == null){ - throw new IllegalStateException("Missing Dispatcher"); - } - this.dispatcher.start(); - - for(Entry e : adaptors.entrySet()){ - IoAdaptorInfo adaptor = e.getValue(); - if(adaptor.serverChannel != null) continue; - - adaptor.serverChannel = dispatcher.registerServerChannel(adaptor.adaptorAddr, adaptor.serverAdaptor); - String info = String.format("%s-%s listening [%s]", this.serverName, adaptor.adaptorName, adaptor.adaptorAddr); - if(adaptor.adaptorName == null){ - info = String.format("%s listening [%s]", this.serverName, adaptor.adaptorAddr); - } - log.info(info); - } - } - - @Override - public void close() throws IOException { - for(Entry e : adaptors.entrySet()){ - IoAdaptorInfo adaptor = e.getValue(); - dispatcher.unregisterServerChannel(adaptor.serverChannel); - adaptor.serverChannel = null; - } - adaptors.clear(); +public class Server implements Closeable { + private static final Logger log = Logger.getLogger(Server.class); + + private static class IoAdaptorInfo { + public String adaptorName; + public String adaptorAddr; + public ServerSocketChannel serverChannel; + public IoAdaptor serverAdaptor; + } + + protected Dispatcher dispatcher; + protected String serverAddr; //第一个Server注册的地址 + protected String serverName = "Server"; + + protected Map adaptors = new ConcurrentHashMap(); + + public Server() { + } + + public Server(Dispatcher dispatcher) { + this.dispatcher = dispatcher; + } + + public Server(Dispatcher dispatcher, IoAdaptor serverAdaptor, int port) { + this(dispatcher, serverAdaptor, "0.0.0.0:" + port); + } + + public Server(Dispatcher dispatcher, IoAdaptor serverAdaptor, String address) { + this.dispatcher = dispatcher; + registerAdaptor(address, serverAdaptor); + } + + public void registerAdaptor(int port, IoAdaptor ioAdaptor) { + registerAdaptor("0.0.0.0:" + port, ioAdaptor, null); + } + + public void registerAdaptor(int port, IoAdaptor ioAdaptor, String name) { + registerAdaptor("0.0.0.0:" + port, ioAdaptor, name); + } + + public void registerAdaptor(String address, IoAdaptor ioAdaptor) { + registerAdaptor(address, ioAdaptor, null); } - - public void setDispatcher(Dispatcher dispatcher) { - this.dispatcher = dispatcher; - } - - public void setServerName(String serverName){ - this.serverName = serverName; - } - - public String getServerAddr() { - return serverAddr; - } - + + public void registerAdaptor(String address, IoAdaptor ioAdaptor, String name) { + IoAdaptorInfo adaptor = new IoAdaptorInfo(); + String[] blocks = address.split("[:]"); + if (blocks.length != 2) { + throw new IllegalArgumentException(address + " is invalid address"); + } + adaptor.adaptorName = name; + adaptor.adaptorAddr = address; + adaptor.serverAdaptor = ioAdaptor; + + if (adaptors.isEmpty()) { + this.serverAddr = address; + String host = blocks[0]; + int port = Integer.valueOf(blocks[1]); + if ("0.0.0.0".equals(host)) { + this.serverAddr = String.format("%s:%d", NetKit.getLocalIp(), port); + } + } + + adaptors.put(address, adaptor); + } + + public void start() throws IOException { + if (dispatcher == null) { + throw new IllegalStateException("Missing Dispatcher"); + } + this.dispatcher.start(); + + for (Entry e : adaptors.entrySet()) { + IoAdaptorInfo adaptor = e.getValue(); + if (adaptor.serverChannel != null) continue; + + adaptor.serverChannel = dispatcher.registerServerChannel(adaptor.adaptorAddr, adaptor.serverAdaptor); + String info = String.format("%s-%s listening [%s]", this.serverName, adaptor.adaptorName, adaptor.adaptorAddr); + if (adaptor.adaptorName == null) { + info = String.format("%s listening [%s]", this.serverName, adaptor.adaptorAddr); + } + log.info(info); + } + } + + @Override + public void close() throws IOException { + for (Entry e : adaptors.entrySet()) { + IoAdaptorInfo adaptor = e.getValue(); + dispatcher.unregisterServerChannel(adaptor.serverChannel); + adaptor.serverChannel = null; + } + adaptors.clear(); + } + + public void setDispatcher(Dispatcher dispatcher) { + this.dispatcher = dispatcher; + } + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public String getServerAddr() { + return serverAddr; + } + } diff --git a/src/main/java/org/zbus/net/http/MessageAdaptor.java b/src/main/java/org/zbus/net/http/MessageAdaptor.java index 707634d0..196758d2 100644 --- a/src/main/java/org/zbus/net/http/MessageAdaptor.java +++ b/src/main/java/org/zbus/net/http/MessageAdaptor.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - *

+ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - *

+ * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - *

+ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -31,104 +31,105 @@ import org.zbus.net.core.Session; import org.zbus.net.http.Message.MessageHandler; import org.zbus.net.http.Message.MessageProcessor; -public class MessageAdaptor extends IoAdaptor { - //全局处理器,优先级最高 - protected MessageHandler filterHandler; - //根据cmd处理,优先级次之 - protected Map cmdHandlerMap = new ConcurrentHashMap(); - //根据Uri处理,优先级最低 - protected Map uriHandlerMap = new ConcurrentHashMap(); - - - public MessageAdaptor() { - codec(new MessageCodec()); //个性化消息编解码 - this.cmd(Message.HEARTBEAT, new MessageHandler() { - public void handle(Message msg, Session sess) throws IOException { - //ignore - } - }); - } - - public void cmd(String command, MessageHandler handler) { - this.cmdHandlerMap.put(command, handler); +public class MessageAdaptor extends IoAdaptor{ + //全局处理器,优先级最高 + protected MessageHandler filterHandler; + //根据cmd处理,优先级次之 + protected Map cmdHandlerMap = new ConcurrentHashMap(); + //根据Uri处理,优先级最低 + protected Map uriHandlerMap = new ConcurrentHashMap(); + + + public MessageAdaptor(){ + codec(new MessageCodec()); //个性化消息编解码 + this.cmd(Message.HEARTBEAT, new MessageHandler() { + public void handle(Message msg, Session sess) throws IOException { + //ignore + } + }); + } + + public void cmd(String command, MessageHandler handler){ + this.cmdHandlerMap.put(command, handler); } - - public void uri(String path, final MessageProcessor processor) { - this.uriHandlerMap.put(path, processor); - cmd(path, new MessageHandler() { - @Override - public void handle(Message msg, Session sess) throws IOException { - final String msgId = msg.getId(); - Message res = processor.process(msg); - if (res != null) { - res.setId(msgId); - sess.write(res); - } - } - }); - } - + + public void uri(String path, final MessageProcessor processor){ + this.uriHandlerMap.put(path, processor); + cmd(path, new MessageHandler() { + @Override + public void handle(Message msg, Session sess) throws IOException { + final String msgId = msg.getId(); + Message res = processor.process(msg); + if(res != null){ + res.setId(msgId); + sess.write(res); + } + } + }); + } + public void registerFilterHandler(MessageHandler filterHandler) { - this.filterHandler = filterHandler; - } - - public void onMessage(Object obj, Session sess) throws IOException { - Message msg = (Message) obj; - final String msgId = msg.getId(); - - if (this.filterHandler != null) { - this.filterHandler.handle(msg, sess); - } - - String cmd = msg.getCmd(); - if (cmd != null) { //cmd - MessageHandler handler = cmdHandlerMap.get(cmd); - if (handler != null) { - handler.handle(msg, sess); - return; - } - } - - String path = msg.getRequestPath(); //requestPath - if (path == null) { - Message res = new Message(); - res.setId(msgId); - res.setResponseStatus(400); - res.setBody("Bad Format(400): Missing Command and RequestPath"); - sess.write(res); - return; - } - - MessageProcessor uriHandler = uriHandlerMap.get(path); - if (uriHandler != null) { - Message res = null; - try { - res = uriHandler.process(msg); - if (res != null) { - res.setId(msgId); - if (res.getResponseStatus() == null) { - res.setResponseStatus(200);// default to 200 - } - sess.write(res); - } - } catch (IOException e) { - throw e; - } catch (Exception e) { - res = new Message(); - res.setResponseStatus(500); - res.setBody("Internal Error(500): " + e); - sess.write(res); - } - return; - } - - Message res = new Message(); - res.setId(msgId); - res.setResponseStatus(404); - String text = String.format("Not Found(404): %s", path); - res.setBody(text); - sess.write(res); - } + this.filterHandler = filterHandler; + } + + public void onMessage(Object obj, Session sess) throws IOException { + Message msg = (Message)obj; + final String msgId = msg.getId(); + + if(this.filterHandler != null){ + this.filterHandler.handle(msg, sess); + } + + String cmd = msg.getCmd(); + if(cmd != null){ //cmd + MessageHandler handler = cmdHandlerMap.get(cmd); + if(handler != null){ + handler.handle(msg, sess); + return; + } + } + + String path = msg.getRequestPath(); //requestPath + if(path == null){ + Message res = new Message(); + res.setId(msgId); + res.setResponseStatus(400); + res.setBody("Bad Format(400): Missing Command and RequestPath"); + sess.write(res); + return; + } + + MessageProcessor uriHandler = uriHandlerMap.get(path); + if(uriHandler != null){ + Message res = null; + try{ + res = uriHandler.process(msg); + if(res != null){ + res.setId(msgId); + if(res.getResponseStatus() == null){ + res.setResponseStatus(200);// default to 200 + } + sess.write(res); + } + } catch (IOException e){ + throw e; + } catch (Exception e) { + res = new Message(); + res.setResponseStatus(500); + res.setBody("Internal Error(500): " + e); + sess.write(res); + } + + return; + } + + Message res = new Message(); + res.setId(msgId); + res.setResponseStatus(404); + String text = String.format("Not Found(404): %s", path); + res.setBody(text); + sess.write(res); + } } diff --git a/src/main/java/org/zbus/net/http/MessageCodec.java b/src/main/java/org/zbus/net/http/MessageCodec.java index fdaf0eef..00036e2e 100644 --- a/src/main/java/org/zbus/net/http/MessageCodec.java +++ b/src/main/java/org/zbus/net/http/MessageCodec.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - *

+ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - *

+ * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - *

+ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -25,73 +25,73 @@ package org.zbus.net.http; import org.zbus.net.core.Codec; import org.zbus.net.core.IoBuffer; -public class MessageCodec implements Codec { - - public IoBuffer encode(Object obj) { - if (!(obj instanceof Message)) { - throw new RuntimeException("Message unknown"); - } - - Message msg = (Message) obj; - IoBuffer buf = msg.toIoBuffer(); - return buf; - } - - public Object decode(IoBuffer buf) { - int headerIdx = findHeaderEnd(buf); - if (headerIdx == -1) return null; - - int headerLen = headerIdx + 1 - buf.position(); - - buf.mark(); - Message msg = new Message(); - msg.decodeHeaders(buf.array(), buf.position(), headerLen); - buf.position(buf.position() + headerLen); - - String contentLength = msg.getHead(Message.CONTENT_LENGTH); - if (contentLength == null) { //just head - return msg; - } - - int bodyLen = Integer.valueOf(contentLength); - if (buf.remaining() < bodyLen) { - buf.reset(); - return null; - } - - byte[] body = new byte[bodyLen]; - buf.readBytes(body); - msg.setBody(body); - - return msg; - } - - private static int findHeaderEnd(IoBuffer buf) { - byte[] data = buf.array(); - int i = buf.position(); - int limit = buf.limit(); - while (i + 3 < limit) { - if (data[i] != '\r') { - i += 1; - continue; - } - if (data[i + 1] != '\n') { - i += 1; - continue; - } - - if (data[i + 2] != '\r') { - i += 3; - continue; - } - - if (data[i + 3] != '\n') { - i += 3; - continue; - } - - return i + 3; - } - return -1; - } +public class MessageCodec implements Codec{ + + public IoBuffer encode(Object obj) { + if(!(obj instanceof Message)){ + throw new RuntimeException("Message unknown"); + } + + Message msg = (Message)obj; + IoBuffer buf = msg.toIoBuffer(); + return buf; + } + + public Object decode(IoBuffer buf) { + int headerIdx = findHeaderEnd(buf); + if(headerIdx == -1) return null; + + int headerLen = headerIdx+1-buf.position(); + + buf.mark(); + Message msg = new Message(); + msg.decodeHeaders(buf.array(), buf.position(), headerLen); + buf.position(buf.position()+headerLen); + + String contentLength = msg.getHead(Message.CONTENT_LENGTH); + if(contentLength == null){ //just head + return msg; + } + + int bodyLen = Integer.valueOf(contentLength); + if(buf.remaining() Date: Tue, 22 Sep 2015 09:46:04 +0800 Subject: [PATCH 06/24] 1 --- .../org/zstacks/zbus/client/Consumer.java | 152 ------------------ 1 file changed, 152 deletions(-) delete mode 100644 src/main/java/org/zstacks/zbus/client/Consumer.java diff --git a/src/main/java/org/zstacks/zbus/client/Consumer.java b/src/main/java/org/zstacks/zbus/client/Consumer.java deleted file mode 100644 index 58037bec..00000000 --- a/src/main/java/org/zstacks/zbus/client/Consumer.java +++ /dev/null @@ -1,152 +0,0 @@ -package org.zstacks.zbus.client; - -import java.io.Closeable; -import java.io.IOException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -//import org.zstacks.zbus.protocol.MessageMode; -//import org.zstacks.zbus.protocol.Proto; -//import org.zstacks.znet.Message; -//import org.zstacks.znet.RemotingClient; -//import org.zstacks.znet.callback.MessageCallback; -//import org.zstacks.znet.log.Logger; - - -public class Consumer /*extends MqAdmin implements Closeable*/{ -// private static final Logger log = Logger.getLogger(Consumer.class); -// private RemotingClient client; //消费者拥有一个物理链接 -// //为发布订阅者的主题,当Consumer的模式为发布订阅时候起作用 -// private String topic = null; -// private int messageCallbackThreadCount = 4; -// -// public Consumer(Broker broker, String mq, MessageMode... mode){ -// super(broker, mq, mode); -// } -// -// public Consumer(MqConfig config){ -// super(config); -// setTopic(config.getTopic()); -// } -// -// -// public Message recv(int timeout) throws IOException, InterruptedException{ -// if(this.client == null){ -// this.client = broker.getClient(myClientHint()); -// } -// Message req = new Message(); -// req.setCommand(Proto.Consume); -// req.setMq(mq); -// req.setToken(accessToken); -// if(MessageMode.isEnabled(this.mode, MessageMode.PubSub)){ -// if(this.topic != null){ -// req.setTopic(this.topic); -// } -// } -// -// Message res = null; -// try{ -// res = client.invokeSync(req, timeout); -// if(res != null && res.isStatus404()){ -// if(!this.createMQ()){ -// throw new IllegalStateException("register error"); -// } -// return recv(timeout); -// } -// } catch(IOException e){ -// log.error(e.getMessage(), e); -// try{ -// broker.closeClient(client); -// client = broker.getClient(myClientHint()); -// } catch(IOException ex){ -// log.error(e.getMessage(), e); -// } -// } -// return res; -// } -// -// public void close() throws IOException { -// if(this.client != null){ -// this.broker.closeClient(this.client); -// } -// if(this.executorService != null){ -// this.executorService.shutdown(); -// } -// } -// -// @Override -// protected Message invokeCreateMQ(Message req) throws IOException, InterruptedException { -// if(this.client == null){ -// this.client = broker.getClient(myClientHint()); -// } -// return client.invokeSync(req, invokeTimeout); -// } -// -// -// public void reply(Message msg) throws IOException{ -// if(msg.getStatus() != null){ -// msg.setReplyCode(msg.getStatus()); -// } -// msg.setCommand(Proto.Produce); -// msg.setAck(false); -// client.getSession().write(msg); -// } -// -// -// -// protected ExecutorService executorService = null; -// private MessageCallback callback; -// public void onMessage(MessageCallback cb) throws IOException{ -// this.callback = cb; -// if(executorService != null) return; -// -// executorService = new ThreadPoolExecutor(messageCallbackThreadCount, -// messageCallbackThreadCount, 120, TimeUnit.SECONDS, new LinkedBlockingQueue()); -// -// executorService.submit(new Runnable() { -// public void run() { -// for(;;){ -// try { -// Message msg; -// try { -// msg = recv(10000); -// } catch (InterruptedException e) { -// break; -// } -// if(msg == null){ -// continue; -// } -// callback.onMessage(msg, client.getSession()); -// } catch (IOException e) { -// // -// } -// } -// } -// }); -// -// } -// -// -// public String getTopic() { -// return topic; -// } -// -// public void setTopic(String topic) { -// if(!MessageMode.isEnabled(this.mode, MessageMode.PubSub)){ -// throw new IllegalStateException("topic only support for PubSub mode"); -// } -// this.topic = topic; -// } -// -// public int getMessageCallbackThreadCount() { -// return messageCallbackThreadCount; -// } -// -// public void setMessageCallbackThreadCount(int messageCallbackThreadCount) { -// this.messageCallbackThreadCount = messageCallbackThreadCount; -// } - - -} -- Gitee From 520d110a04fec9d145b25422c6a647836736aedf Mon Sep 17 00:00:00 2001 From: lejingw Date: Mon, 28 Sep 2015 10:28:07 +0800 Subject: [PATCH 07/24] 1 --- .gitignore | 3 ++- .../java/org/zbus/broker/ha/TrackServer.java | 2 +- src/main/java/org/zbus/mq/MqAdmin.java | 2 +- .../java/org/zbus/mq/server/MqServer.java | 3 ++- src/test/java/org/zbus/mq/ProducerSync.java | 6 +++-- .../mq/service_via_mq/ServiceExample.java | 20 ++++++++-------- .../java/org/zbus/proxy/ClientExample.java | 2 +- src/test/java/org/zbus/proxy/ClientPerf.java | 2 +- .../java/org/zbus/proxy/ConnectionPerf.java | 2 +- .../java/org/zbus/proxy/TargetServer.java | 23 +++++++++---------- src/test/java/org/zbus/pubsub/PubSync.java | 17 +++++++------- .../java/org/zbus/rpc/biz/InterfaceImpl.java | 2 +- 12 files changed, 43 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index 22cd7495..f5599b71 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea *.iml /target -/store \ No newline at end of file +/store +/store2 \ No newline at end of file diff --git a/src/main/java/org/zbus/broker/ha/TrackServer.java b/src/main/java/org/zbus/broker/ha/TrackServer.java index c252211e..54031fe4 100644 --- a/src/main/java/org/zbus/broker/ha/TrackServer.java +++ b/src/main/java/org/zbus/broker/ha/TrackServer.java @@ -72,7 +72,7 @@ public class TrackServer extends Server{ public static void main(String[] args) throws Exception { String host = ConfigKit.option(args, "-h", "0.0.0.0"); - int port = ConfigKit.option(args, "-p", 16666); + int port = ConfigKit.option(args, "-p", 16667); boolean verbose = ConfigKit.option(args, "-verbose", true); final TrackServer server = new TrackServer(host+":"+port); server.setVerbose(verbose); diff --git a/src/main/java/org/zbus/mq/MqAdmin.java b/src/main/java/org/zbus/mq/MqAdmin.java index 366a44a1..632df49f 100644 --- a/src/main/java/org/zbus/mq/MqAdmin.java +++ b/src/main/java/org/zbus/mq/MqAdmin.java @@ -65,7 +65,7 @@ public class MqAdmin { */ protected Message invokeCreateMQ(Message req) throws IOException, InterruptedException { //TODO - return broker.invokeSync(req, 250000000); + return broker.invokeSync(req, 2500); } public boolean createMQ() throws IOException, InterruptedException { diff --git a/src/main/java/org/zbus/mq/server/MqServer.java b/src/main/java/org/zbus/mq/server/MqServer.java index 4d2c564c..321cb9ab 100644 --- a/src/main/java/org/zbus/mq/server/MqServer.java +++ b/src/main/java/org/zbus/mq/server/MqServer.java @@ -165,7 +165,8 @@ public class MqServer extends Server{ config.executorCount = ConfigKit.option(args, "-executor", 64); config.verbose = ConfigKit.option(args, "-verbose", false); config.storePath = ConfigKit.option(args, "-store", "store"); - config.trackServerList = ConfigKit.option(args, "-track", null); +// config.trackServerList = ConfigKit.option(args, "-track", null); + config.trackServerList = ConfigKit.option(args, "-track", "localhost:16666;localhost:16667"); config.thriftServer = ConfigKit.option(args, "-thrift", null); final MqServer server = new MqServer(config); diff --git a/src/test/java/org/zbus/mq/ProducerSync.java b/src/test/java/org/zbus/mq/ProducerSync.java index e7c8b779..f2e3ad61 100644 --- a/src/test/java/org/zbus/mq/ProducerSync.java +++ b/src/test/java/org/zbus/mq/ProducerSync.java @@ -23,10 +23,12 @@ public class ProducerSync { long start = System.currentTimeMillis(); Message msg = new Message(); msg.setBody("hello world"+i); - producer.sendSync(msg); + producer.sendSync(msg); long end = System.currentTimeMillis(); total += (end-start); - System.out.format("Time: %.1f\n", total*1.0/(i+1)); + if(0 == i%1000) { + System.out.format("Time: %.1f\n", total * 1.0 / (i + 1)); + } } broker.close(); diff --git a/src/test/java/org/zbus/mq/service_via_mq/ServiceExample.java b/src/test/java/org/zbus/mq/service_via_mq/ServiceExample.java index 91a04183..5f1439e9 100644 --- a/src/test/java/org/zbus/mq/service_via_mq/ServiceExample.java +++ b/src/test/java/org/zbus/mq/service_via_mq/ServiceExample.java @@ -11,30 +11,30 @@ import org.zbus.rpc.mq.Service; import org.zbus.rpc.mq.ServiceConfig; public class ServiceExample { - - public static void main(String[] args) throws IOException, Exception{ + + public static void main(String[] args) throws IOException { //配置Broker BrokerConfig brokerConfig = new BrokerConfig(); - brokerConfig.setServerAddress("127.0.0.1:15555"); + brokerConfig.setServerAddress("127.0.0.1:15555"); Broker broker = new SingleBroker(brokerConfig); - - ServiceConfig config = new ServiceConfig(); + + ServiceConfig config = new ServiceConfig(); config.setMq("MyService"); config.setBroker(broker); config.setConsumerCount(2); - + //处理逻辑 - config.setMessageProcessor(new MessageProcessor() { + config.setMessageProcessor(new MessageProcessor() { @Override - public Message process(Message request) { + public Message process(Message request) { //System.out.println(request); Message result = new Message(); result.setResponseStatus("200"); - result.setBody("Server time: "+System.currentTimeMillis()); + result.setBody("Server time: " + System.currentTimeMillis()); return result; } }); - + @SuppressWarnings("resource") Service svc = new Service(config); svc.start(); diff --git a/src/test/java/org/zbus/proxy/ClientExample.java b/src/test/java/org/zbus/proxy/ClientExample.java index e469bb00..3719b451 100644 --- a/src/test/java/org/zbus/proxy/ClientExample.java +++ b/src/test/java/org/zbus/proxy/ClientExample.java @@ -8,7 +8,7 @@ public class ClientExample { public static void main(String[] args) throws Exception { Dispatcher dispatcher = new Dispatcher(); - MessageClient client = new MessageClient("127.0.0.1:80", dispatcher); + MessageClient client = new MessageClient("127.0.0.1:15555", dispatcher); Message req = new Message(); req.setCmd("hello"); diff --git a/src/test/java/org/zbus/proxy/ClientPerf.java b/src/test/java/org/zbus/proxy/ClientPerf.java index 926e5897..2e95304c 100644 --- a/src/test/java/org/zbus/proxy/ClientPerf.java +++ b/src/test/java/org/zbus/proxy/ClientPerf.java @@ -15,7 +15,7 @@ public class ClientPerf { req.setBody("hello"); for(int i=0;i<1000;i++){ - MessageClient client = new MessageClient("127.0.0.1:80", dispatcher); + MessageClient client = new MessageClient("127.0.0.1:15555", dispatcher); Message res = client.invokeSync(req); System.out.println(">>>"+i+"\n"+res); client.close(); diff --git a/src/test/java/org/zbus/proxy/ConnectionPerf.java b/src/test/java/org/zbus/proxy/ConnectionPerf.java index 4eec661c..5acc056a 100644 --- a/src/test/java/org/zbus/proxy/ConnectionPerf.java +++ b/src/test/java/org/zbus/proxy/ConnectionPerf.java @@ -10,7 +10,7 @@ public class ConnectionPerf { Dispatcher dispatcher = new Dispatcher(); for(int i=0;i<100000;i++){ - MessageClient client = new MessageClient("127.0.0.1:80", dispatcher); + MessageClient client = new MessageClient("127.0.0.1:15555", dispatcher); Message req = new Message(); req.setCmd("hello"); diff --git a/src/test/java/org/zbus/proxy/TargetServer.java b/src/test/java/org/zbus/proxy/TargetServer.java index 778ef6c3..b1ed6b1b 100644 --- a/src/test/java/org/zbus/proxy/TargetServer.java +++ b/src/test/java/org/zbus/proxy/TargetServer.java @@ -9,26 +9,25 @@ import org.zbus.net.http.Message; import org.zbus.net.http.Message.MessageHandler; import org.zbus.net.http.MessageAdaptor; -public class TargetServer extends MessageAdaptor { - - public TargetServer(){ - cmd("hello", new MessageHandler() { +public class TargetServer extends MessageAdaptor { + + public TargetServer() { + cmd("hello", new MessageHandler() { @Override public void handle(Message msg, Session sess) throws IOException { msg.setResponseStatus(200); - msg.setBody(""+System.currentTimeMillis()); + msg.setBody("" + System.currentTimeMillis()); sess.write(msg); } }); - } - - public static void main(String[] args) throws Exception { - Dispatcher dispatcher = new Dispatcher(); + } + + public static void main(String[] args) throws Exception { + Dispatcher dispatcher = new Dispatcher(); TargetServer ioAdaptor = new TargetServer(); - + @SuppressWarnings("resource") Server server = new Server(dispatcher, ioAdaptor, 15555); - server.start(); + server.start(); } - } diff --git a/src/test/java/org/zbus/pubsub/PubSync.java b/src/test/java/org/zbus/pubsub/PubSync.java index ef649678..43e2356d 100644 --- a/src/test/java/org/zbus/pubsub/PubSync.java +++ b/src/test/java/org/zbus/pubsub/PubSync.java @@ -8,21 +8,20 @@ import org.zbus.mq.Protocol.MqMode; import org.zbus.net.http.Message; public class PubSync { - public static void main(String[] args) throws Exception{ + public static void main(String[] args) throws Exception { BrokerConfig config = new BrokerConfig(); config.setServerAddress("127.0.0.1:15555"); final Broker broker = new SingleBroker(config); - + Producer producer = new Producer(broker, "MyPubSub", MqMode.PubSub); - producer.createMQ(); - + producer.createMQ(); + Message msg = new Message(); - msg.setTopic("sse"); + msg.setTopic("sse"); msg.setBody("hello world"); - + producer.sendSync(msg); - - + broker.close(); - } + } } diff --git a/src/test/java/org/zbus/rpc/biz/InterfaceImpl.java b/src/test/java/org/zbus/rpc/biz/InterfaceImpl.java index 2190b56c..0aafc5ec 100644 --- a/src/test/java/org/zbus/rpc/biz/InterfaceImpl.java +++ b/src/test/java/org/zbus/rpc/biz/InterfaceImpl.java @@ -37,7 +37,7 @@ class PrivateRuntimeException extends RuntimeException{ public class InterfaceImpl implements Interface{ public String getString(String name) { - return "Hello World ZBUS " + name; + return "Hello World " + name; } @Override -- Gitee From bb59b6ef7ac397de064e8cb645c18f0c56c1cad7 Mon Sep 17 00:00:00 2001 From: lejingw Date: Mon, 28 Sep 2015 10:34:43 +0800 Subject: [PATCH 08/24] 1 --- Readme.md | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/Readme.md b/Readme.md index 3c3054a8..cdf4b568 100644 --- a/Readme.md +++ b/Readme.md @@ -8,33 +8,23 @@ * **亿级消息堆积能力、支持HA高可用** * **单个Jar包无依赖 ~300K** * **服务代理 -- 适配改造已有业务系统,使之具备跨平台与语言** -* **丰富的API--JAVA/C/C++/C#/Python/Node.JS多语言接入** - -## QQ群: 467741880 - +* **丰富的API--JAVA/C/C++/C#/Python/Node.JS多语言接入** ## ZBUS 启动与监控 zbus-dist选择zbus.sh或者zbus.bat直接执行 -![简单监控](http://git.oschina.net/uploads/images/2015/0818/132153_425b58e9_7458.png) - 总线默认占用 **15555** 端口, [http://localhost:15555](http://localhost:15555 "默认监控地址") 可以直接进入监控,注意zbus因为原生兼容HTTP协议所以监控与消息队列使用同一个端口 ## ZBUS 角色概要 -![zbus-arch](http://git.oschina.net/uploads/images/2015/0818/145645_0a1651bf_7458.png) - ## ZBUS 消息通讯基础(NET模块) ZBUS项目不依赖其他第三方库,消息通讯基于NIO完成(NET子项目)。NET包对NIO做了简洁的封装,相对Netty而言,学习成本低几个量级,模型简单,但不失扩展性。 - -![znet-arch](http://git.oschina.net/uploads/images/2015/0818/151248_bde11d15_7458.png) - 框架结构保持 **Dispatcher + N SelectorThread + IoAdaptor** **Dispatcher** 负责管理N个Selector线程 @@ -46,23 +36,6 @@ ZBUS项目不依赖其他第三方库,消息通讯基于NIO完成(NET子项 基于NET的服务器程序基本只要关心IoAdaptor的个性化,比如ZBUS入口就是MqAdaptor -## ZBUS API - -* [Java API](http://git.oschina.net/rushmore/zbus "zbus") -* [C/C++ API](http://git.oschina.net/rushmore/zbus-api-c "zbus-api-c") -* [Python API](http://git.oschina.net/rushmore/zbus-api-python "zbus-api-python") -* [C# API](http://git.oschina.net/rushmore/zbus-api-csharp "zbus-api-csharp") -* [Node.JS API](http://git.oschina.net/rushmore/zbus-api-nodejs "zbus-api-nodejs") - -## ZBUS PROXY - -* [微软MSMQ|国信交易调度](http://git.oschina.net/rushmore/zbus-proxy-msmq "zbus-proxy-msmq") -* [金证KCXP](http://git.oschina.net/rushmore/zbus-proxy-kcxp "zbus-proxy-kcxp") -* [国信TC](http://git.oschina.net/rushmore/zbus-proxy-tc "zbus-proxy-tc") -* [桥接JAVA客户端](http://git.oschina.net/rushmore/zbus-proxy-java "zbus-proxy-java") -* [国泰君安GTA](http://git.oschina.net/rushmore/zbus-proxy-gta "zbus-proxy-gta") - - ## ZBUS 示例 ### Java Maven 依赖 @@ -225,8 +198,3 @@ ZBUS项目不依赖其他第三方库,消息通讯基于NIO完成(NET子项 System.out.println(intf.listMap()); } } - - -## ZBUS消息协议 - -* [08 ZBUS高阶话题--协议](http://git.oschina.net/rushmore/zbus/blob/master/doc/08.%20ZBUS%E9%AB%98%E9%98%B6%E8%AF%9D%E9%A2%98--%E5%8D%8F%E8%AE%AE.md?dir=0&filepath=doc%2F08.+ZBUS%E9%AB%98%E9%98%B6%E8%AF%9D%E9%A2%98--%E5%8D%8F%E8%AE%AE.md&oid=61c459ed0b6dcb0b6d204711cb4d58d183715a3a&sha=9473c1b43089291e385b15eb3deaa32f7277a428 "08 ZBUS高阶话题--协议") \ No newline at end of file -- Gitee From 9034e1c5f8272cb240c7d13f0946ae2b960ae23a Mon Sep 17 00:00:00 2001 From: lejingw Date: Tue, 29 Sep 2015 11:14:11 +0800 Subject: [PATCH 09/24] 1 --- Readme.md => README.md | 0 .../java/org/zbus/mq/server/MqServer.java | 3 +-- src/test/java/org/zbus/ha/ConsumerHA.java | 20 +++++++++---------- .../java/org/zbus/mq/ConsumerExample.java | 12 +++++------ src/test/java/org/zbus/mq/ProducerSync.java | 1 - 5 files changed, 16 insertions(+), 20 deletions(-) rename Readme.md => README.md (100%) diff --git a/Readme.md b/README.md similarity index 100% rename from Readme.md rename to README.md diff --git a/src/main/java/org/zbus/mq/server/MqServer.java b/src/main/java/org/zbus/mq/server/MqServer.java index 321cb9ab..bea1be3b 100644 --- a/src/main/java/org/zbus/mq/server/MqServer.java +++ b/src/main/java/org/zbus/mq/server/MqServer.java @@ -165,8 +165,7 @@ public class MqServer extends Server{ config.executorCount = ConfigKit.option(args, "-executor", 64); config.verbose = ConfigKit.option(args, "-verbose", false); config.storePath = ConfigKit.option(args, "-store", "store"); -// config.trackServerList = ConfigKit.option(args, "-track", null); - config.trackServerList = ConfigKit.option(args, "-track", "localhost:16666;localhost:16667"); + config.trackServerList = ConfigKit.option(args, "-track", null);//-track localhost:16666;localhost:16667 config.thriftServer = ConfigKit.option(args, "-thrift", null); final MqServer server = new MqServer(config); diff --git a/src/test/java/org/zbus/ha/ConsumerHA.java b/src/test/java/org/zbus/ha/ConsumerHA.java index 5fb0fa2d..fd0b775c 100644 --- a/src/test/java/org/zbus/ha/ConsumerHA.java +++ b/src/test/java/org/zbus/ha/ConsumerHA.java @@ -12,21 +12,21 @@ import org.zbus.net.http.Message; import org.zbus.net.http.Message.MessageHandler; public class ConsumerHA { - public static void main(String[] args) throws Exception{ + public static void main(String[] args) throws Exception { //创建Broker代表 BrokerConfig brokerConfig = new BrokerConfig(); brokerConfig.setTrackServerList("127.0.0.1:16666;127.0.0.1:16667"); Broker broker = new HaBroker(brokerConfig); - - MqConfig config = new MqConfig(); + + MqConfig config = new MqConfig(); config.setBroker(broker); config.setMq("MyMQ"); - + //创建消费者 @SuppressWarnings("resource") - Consumer c = new Consumer(config); - - c.onMessage(new MessageHandler() { + Consumer c = new Consumer(config); + + c.onMessage(new MessageHandler() { @Override public void handle(Message msg, Session sess) throws IOException { System.out.println(msg); @@ -34,7 +34,7 @@ public class ConsumerHA { }); //启动消费线程 - c.start(); - - } + c.start(); + + } } diff --git a/src/test/java/org/zbus/mq/ConsumerExample.java b/src/test/java/org/zbus/mq/ConsumerExample.java index ca0c5b33..ce8b17e1 100644 --- a/src/test/java/org/zbus/mq/ConsumerExample.java +++ b/src/test/java/org/zbus/mq/ConsumerExample.java @@ -1,16 +1,14 @@ package org.zbus.mq; -import java.io.IOException; - import org.zbus.broker.Broker; import org.zbus.broker.BrokerConfig; import org.zbus.broker.SingleBroker; -import org.zbus.mq.Consumer; -import org.zbus.mq.MqConfig; import org.zbus.net.core.Session; import org.zbus.net.http.Message; import org.zbus.net.http.Message.MessageHandler; +import java.io.IOException; + public class ConsumerExample { public static void main(String[] args) throws Exception{ //创建Broker代表 @@ -24,11 +22,11 @@ public class ConsumerExample { //创建消费者 @SuppressWarnings("resource") - Consumer c = new Consumer(config); - c.onMessage(new MessageHandler() { + Consumer c = new Consumer(config); + c.onMessage(new MessageHandler() { @Override public void handle(Message msg, Session sess) throws IOException { - System.out.println(msg); + System.out.println(msg); } }); diff --git a/src/test/java/org/zbus/mq/ProducerSync.java b/src/test/java/org/zbus/mq/ProducerSync.java index f2e3ad61..0c02159d 100644 --- a/src/test/java/org/zbus/mq/ProducerSync.java +++ b/src/test/java/org/zbus/mq/ProducerSync.java @@ -3,7 +3,6 @@ package org.zbus.mq; import org.zbus.broker.Broker; import org.zbus.broker.BrokerConfig; import org.zbus.broker.SingleBroker; -import org.zbus.mq.Producer; import org.zbus.net.http.Message; public class ProducerSync { -- Gitee From 852677935c94d51c54b021a2ded076b6051b9f94 Mon Sep 17 00:00:00 2001 From: lejingw Date: Tue, 29 Sep 2015 18:43:40 +0800 Subject: [PATCH 10/24] 1 --- pom.xml | 55 +++++++++-------- .../java/org/zbus/mq/ConsumerExample.java | 2 +- src/test/java/org/zbus/mq/ProducerSync.java | 2 +- .../org/zbus/spring/mq/SpringMqConsumer.java | 43 ++++++++++++++ .../org/zbus/spring/mq/SpringMqProducer.java | 31 ++++++++++ src/test/resources/log4j.properties | 4 +- src/test/resources/mq/SpringMqConsumer.xml | 25 ++++++++ src/test/resources/mq/SpringMqProducer.xml | 59 +++++++++++++++++++ zbus-dist/zbus.sh | 4 +- 9 files changed, 194 insertions(+), 31 deletions(-) create mode 100644 src/test/java/org/zbus/spring/mq/SpringMqConsumer.java create mode 100644 src/test/java/org/zbus/spring/mq/SpringMqProducer.java create mode 100644 src/test/resources/mq/SpringMqConsumer.xml create mode 100644 src/test/resources/mq/SpringMqProducer.xml diff --git a/pom.xml b/pom.xml index 53bffe19..cb34172c 100644 --- a/pom.xml +++ b/pom.xml @@ -2,10 +2,10 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 - jar - org.zbus + com.jingcai.apps zbus - 6.2.0 + 1.0-RELEASE + jar zbus lightweight MQ, RPC, PROXY https://zbus.org @@ -19,27 +19,30 @@ - - - rushmore - 44194462@qq.com - - - - scm:git@git.oschina.net:rushmore/zbus.git - scm:git@git.oschina.net:rushmore/zbus.git - git@git.oschina.net:rushmore/zbus.git + scm:git:git@192.168.0.20:java/zbus.git + scm:git:git@192.168.0.20:java/zbus.git + http://192.168.0.20/java/zbus UTF-8 + - oss - https://oss.sonatype.org/content/repositories/snapshots/ + jingcai_snapshots + http://192.168.0.20:8081/nexus/content/repositories/jingcai_snapshots/ + + true + always + + + + jingcai_nexus + jingcai nexus repository + http://192.168.0.20:8081/nexus/content/groups/public/ @@ -67,8 +70,8 @@ org.springframework - spring - 2.5.6 + spring-context + 3.2.8.RELEASE true test @@ -93,7 +96,7 @@ 1.6 1.6 - UTF8 + UTF-8 @@ -130,11 +133,11 @@ - + + --> + - oss - https://oss.sonatype.org/content/repositories/snapshots/ + jingcai_snapshots + http://192.168.0.20:8081/nexus/content/repositories/jingcai_snapshots/ - oss - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + jingcai_release + http://192.168.0.20:8081/nexus/content/repositories/jingcai_release/ diff --git a/src/test/java/org/zbus/mq/ConsumerExample.java b/src/test/java/org/zbus/mq/ConsumerExample.java index ce8b17e1..3362a78e 100644 --- a/src/test/java/org/zbus/mq/ConsumerExample.java +++ b/src/test/java/org/zbus/mq/ConsumerExample.java @@ -13,7 +13,7 @@ public class ConsumerExample { public static void main(String[] args) throws Exception{ //创建Broker代表 BrokerConfig brokerConfig = new BrokerConfig(); - brokerConfig.setServerAddress("127.0.0.1:15555"); + brokerConfig.setServerAddress("192.168.0.11:15555"); Broker broker = new SingleBroker(brokerConfig); MqConfig config = new MqConfig(); diff --git a/src/test/java/org/zbus/mq/ProducerSync.java b/src/test/java/org/zbus/mq/ProducerSync.java index 0c02159d..fb977e1a 100644 --- a/src/test/java/org/zbus/mq/ProducerSync.java +++ b/src/test/java/org/zbus/mq/ProducerSync.java @@ -9,7 +9,7 @@ public class ProducerSync { public static void main(String[] args) throws Exception { //创建Broker代理 BrokerConfig config = new BrokerConfig(); - config.setServerAddress("127.0.0.1:15555"); + config.setServerAddress("192.168.0.11:15555"); final Broker broker = new SingleBroker(config); Producer producer = new Producer(broker, "MyMQ"); diff --git a/src/test/java/org/zbus/spring/mq/SpringMqConsumer.java b/src/test/java/org/zbus/spring/mq/SpringMqConsumer.java new file mode 100644 index 00000000..3e7eb3ee --- /dev/null +++ b/src/test/java/org/zbus/spring/mq/SpringMqConsumer.java @@ -0,0 +1,43 @@ +package org.zbus.spring.mq; + +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.zbus.mq.Consumer; +import org.zbus.mq.MqConfig; +import org.zbus.mq.Producer; +import org.zbus.net.core.Session; +import org.zbus.net.http.Message; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; + +public class SpringMqConsumer { + public static void main(String[] args) throws IOException, InterruptedException { + final AbstractApplicationContext context = new ClassPathXmlApplicationContext("mq/SpringMqConsumer.xml"); + context.registerShutdownHook(); + +// final AtomicInteger atomicInteger = new AtomicInteger(0); + Consumer c = context.getBean(Consumer.class); + c.onMessage(new Message.MessageHandler() { + @Override + public void handle(Message msg, Session sess) throws IOException { + System.out.println(msg); +// if (atomicInteger.incrementAndGet() > 3) { +// System.out.println("--------------"); +// try { +// Thread.sleep(5000); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// context.close(); +// } + } + }); + c.start(); +// Thread.sleep(5000); +// System.out.println("---------"); +//// c.close(); +// c.close(); +// context.close(); + } +} \ No newline at end of file diff --git a/src/test/java/org/zbus/spring/mq/SpringMqProducer.java b/src/test/java/org/zbus/spring/mq/SpringMqProducer.java new file mode 100644 index 00000000..6e37d559 --- /dev/null +++ b/src/test/java/org/zbus/spring/mq/SpringMqProducer.java @@ -0,0 +1,31 @@ +package org.zbus.spring.mq; + +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.zbus.mq.Producer; +import org.zbus.net.http.Message; + +import java.io.IOException; + +public class SpringMqProducer { + public static void main(String[] args) throws IOException, InterruptedException { + AbstractApplicationContext context = new ClassPathXmlApplicationContext("mq/SpringMqProducer.xml"); + context.registerShutdownHook(); + + Producer producer = context.getBean(Producer.class); + + long total = 0; + for (int i = 0; i < 50; i++) { + long start = System.currentTimeMillis(); + Message msg = new Message(); + msg.setBody("hello world" + i); + producer.sendSync(msg); + long end = System.currentTimeMillis(); + total += (end - start); + if (0 == i % 1000) { + System.out.format("Time: %.1f\n", total * 1.0 / (i + 1)); + } + } + context.close(); + } +} diff --git a/src/test/resources/log4j.properties b/src/test/resources/log4j.properties index 005c16ff..51c2fbcc 100644 --- a/src/test/resources/log4j.properties +++ b/src/test/resources/log4j.properties @@ -5,11 +5,11 @@ log4j.rootLogger=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p %c{1}:%L - %m%n log4j.appender.file=org.apache.log4j.DailyRollingFileAppender log4j.appender.file.File=zbus log4j.appender.file.DatePattern='.'yyyy-MM-dd log4j.appender.file.layout=org.apache.log4j.PatternLayout -log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n \ No newline at end of file +log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p %c{1}:%L - %m%n \ No newline at end of file diff --git a/src/test/resources/mq/SpringMqConsumer.xml b/src/test/resources/mq/SpringMqConsumer.xml new file mode 100644 index 00000000..a1ec470d --- /dev/null +++ b/src/test/resources/mq/SpringMqConsumer.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/mq/SpringMqProducer.xml b/src/test/resources/mq/SpringMqProducer.xml new file mode 100644 index 00000000..e2fc76a3 --- /dev/null +++ b/src/test/resources/mq/SpringMqProducer.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/zbus-dist/zbus.sh b/zbus-dist/zbus.sh index 1beb144a..80c582bb 100644 --- a/zbus-dist/zbus.sh +++ b/zbus-dist/zbus.sh @@ -1,10 +1,10 @@ #/usr/bin -JAVA_HOME=/apps/jdk7 +JAVA_HOME=/usr/local/java/jdk7 ZBUS_HOME=. JAVA_OPTS="-Dfile.encoding=UTF-8 -server -Xms64m -Xmx1024m -XX:+UseParallelGC" MAIN_CLASS=org.zbus.mq.server.MqServer MAIN_OPTS="-h 0.0.0.0 -p 15555 -verbose false -conf zbus.properties -store store -track" LIB_OPTS="$ZBUS_HOME/lib:$ZBUS_HOME/*" -nohup $JAVA_HOME/bin/java $JAVA_OPTS -cp $LIB_OPTS $MAIN_CLASS $MAIN_OPTS & +nohup $JAVA_HOME/bin/java $JAVA_OPTS -cp $LIB_OPTS $MAIN_CLASS $MAIN_OPTS > stdout.log 2>&1 & -- Gitee From 774a6c32446769e6ed6d2700e3549e8c87825751 Mon Sep 17 00:00:00 2001 From: lejingw Date: Mon, 12 Oct 2015 11:58:37 +0800 Subject: [PATCH 11/24] 1 --- pom.xml | 2 +- .../java/org/zbus/mq/ConsumerStartStop.java | 6 +++--- src/test/java/org/zbus/mq/ProducerSync.java | 3 ++- .../org/zbus/spring/mq/SpringMqConsumer.java | 18 ------------------ 4 files changed, 6 insertions(+), 23 deletions(-) diff --git a/pom.xml b/pom.xml index cb34172c..efd94517 100644 --- a/pom.xml +++ b/pom.xml @@ -102,7 +102,7 @@ - + release diff --git a/src/test/java/org/zbus/mq/ConsumerStartStop.java b/src/test/java/org/zbus/mq/ConsumerStartStop.java index 10efcf24..fc233522 100644 --- a/src/test/java/org/zbus/mq/ConsumerStartStop.java +++ b/src/test/java/org/zbus/mq/ConsumerStartStop.java @@ -15,7 +15,7 @@ public class ConsumerStartStop { public static void main(String[] args) throws Exception{ //创建Broker代表 BrokerConfig brokerConfig = new BrokerConfig(); - brokerConfig.setServerAddress("127.0.0.1:15555"); + brokerConfig.setServerAddress("192.168.11:15555"); Broker broker = new SingleBroker(brokerConfig); MqConfig config = new MqConfig(); @@ -34,9 +34,9 @@ public class ConsumerStartStop { while(true){ c.start(); - Thread.sleep(4000); + Thread.sleep(1000); c.stop(); - Thread.sleep(4000); + Thread.sleep(1000); } } } diff --git a/src/test/java/org/zbus/mq/ProducerSync.java b/src/test/java/org/zbus/mq/ProducerSync.java index fb977e1a..03b642e3 100644 --- a/src/test/java/org/zbus/mq/ProducerSync.java +++ b/src/test/java/org/zbus/mq/ProducerSync.java @@ -18,9 +18,10 @@ public class ProducerSync { //创建消息,消息体可以是任意binary,应用协议交给使用者 long total = 0; - for(int i=0;i<100000;i++){ + for(int i=0;i<1;i++){ long start = System.currentTimeMillis(); Message msg = new Message(); + //msg.setTopic("topic1"); msg.setBody("hello world"+i); producer.sendSync(msg); long end = System.currentTimeMillis(); diff --git a/src/test/java/org/zbus/spring/mq/SpringMqConsumer.java b/src/test/java/org/zbus/spring/mq/SpringMqConsumer.java index 3e7eb3ee..ca114661 100644 --- a/src/test/java/org/zbus/spring/mq/SpringMqConsumer.java +++ b/src/test/java/org/zbus/spring/mq/SpringMqConsumer.java @@ -3,41 +3,23 @@ package org.zbus.spring.mq; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.zbus.mq.Consumer; -import org.zbus.mq.MqConfig; -import org.zbus.mq.Producer; import org.zbus.net.core.Session; import org.zbus.net.http.Message; import java.io.IOException; -import java.util.concurrent.atomic.AtomicInteger; public class SpringMqConsumer { public static void main(String[] args) throws IOException, InterruptedException { final AbstractApplicationContext context = new ClassPathXmlApplicationContext("mq/SpringMqConsumer.xml"); context.registerShutdownHook(); -// final AtomicInteger atomicInteger = new AtomicInteger(0); Consumer c = context.getBean(Consumer.class); c.onMessage(new Message.MessageHandler() { @Override public void handle(Message msg, Session sess) throws IOException { System.out.println(msg); -// if (atomicInteger.incrementAndGet() > 3) { -// System.out.println("--------------"); -// try { -// Thread.sleep(5000); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } -// context.close(); -// } } }); c.start(); -// Thread.sleep(5000); -// System.out.println("---------"); -//// c.close(); -// c.close(); -// context.close(); } } \ No newline at end of file -- Gitee From 570f1742a9e353664c56a5ab3df96cdb11801176 Mon Sep 17 00:00:00 2001 From: lejingw Date: Tue, 20 Oct 2015 15:05:50 +0800 Subject: [PATCH 12/24] 1 --- .../{StringAdaptor.java => StringServer.java} | 30 ++++++++++--------- src/test/java/org/zbus/pubsub/PubSync.java | 3 +- src/test/java/org/zbus/pubsub/Sub.java | 6 ++-- 3 files changed, 22 insertions(+), 17 deletions(-) rename src/test/java/org/zbus/net/codec/{StringAdaptor.java => StringServer.java} (43%) diff --git a/src/test/java/org/zbus/net/codec/StringAdaptor.java b/src/test/java/org/zbus/net/codec/StringServer.java similarity index 43% rename from src/test/java/org/zbus/net/codec/StringAdaptor.java rename to src/test/java/org/zbus/net/codec/StringServer.java index 46c269bc..806a3287 100644 --- a/src/test/java/org/zbus/net/codec/StringAdaptor.java +++ b/src/test/java/org/zbus/net/codec/StringServer.java @@ -7,21 +7,23 @@ import org.zbus.net.core.Dispatcher; import org.zbus.net.core.IoAdaptor; import org.zbus.net.core.Session; -public class StringAdaptor extends IoAdaptor{ - public StringAdaptor(){ +public class StringServer extends IoAdaptor { + public StringServer() { codec(new StringCodec()); - } - public void onMessage(Object obj, Session sess) throws IOException { - System.out.println("recv: " + obj); - sess.write(obj); - } - @SuppressWarnings("resource") - public static void main(String[] args) throws Exception { - Dispatcher dispatcher = new Dispatcher(); //事件分发器 + } + + public void onMessage(Object obj, Session sess) throws IOException { + System.out.println("recv: " + obj); + sess.write(obj); + } + + @SuppressWarnings("resource") + public static void main(String[] args) throws Exception { + Dispatcher dispatcher = new Dispatcher(); //事件分发器 Server server = new Server(dispatcher); //创建一个Server //指定端口侦听处理逻辑,可以侦听多个端口,每个端口相同处理IO逻辑或者不同IO逻辑 - server.registerAdaptor(8080, new StringAdaptor()); - server.start(); - } + server.registerAdaptor(8080, new StringServer(), "adaptor1"); + server.registerAdaptor(8081, new StringServer(), "adaptor2"); + server.start(); + } } - diff --git a/src/test/java/org/zbus/pubsub/PubSync.java b/src/test/java/org/zbus/pubsub/PubSync.java index 43e2356d..b51bfd6f 100644 --- a/src/test/java/org/zbus/pubsub/PubSync.java +++ b/src/test/java/org/zbus/pubsub/PubSync.java @@ -10,7 +10,8 @@ import org.zbus.net.http.Message; public class PubSync { public static void main(String[] args) throws Exception { BrokerConfig config = new BrokerConfig(); - config.setServerAddress("127.0.0.1:15555"); +// config.setServerAddress("192.168.0.11:15555"); + config.setServerAddress("0.0.0.0:15555"); final Broker broker = new SingleBroker(config); Producer producer = new Producer(broker, "MyPubSub", MqMode.PubSub); diff --git a/src/test/java/org/zbus/pubsub/Sub.java b/src/test/java/org/zbus/pubsub/Sub.java index a24518af..d3f56295 100644 --- a/src/test/java/org/zbus/pubsub/Sub.java +++ b/src/test/java/org/zbus/pubsub/Sub.java @@ -16,12 +16,14 @@ public class Sub { public static void main(String[] args) throws Exception{ //1)创建Broker代表 BrokerConfig config = new BrokerConfig(); - config.setServerAddress("127.0.0.1:15555"); +// config.setServerAddress("192.168.0.11:15555"); + config.setServerAddress("0.0.0.0:15555"); final Broker broker = new SingleBroker(config); //2) 创建消费者 Consumer c = new Consumer(broker, "MyPubSub", MqMode.PubSub); - c.setTopic("sse"); + c.setTopic("sse"); + c.setConsumeTimeout(1000*1000); c.onMessage(new MessageHandler() { @Override -- Gitee From 6c9a83f1c58e5c8336aea0c164ae179f87a4ee52 Mon Sep 17 00:00:00 2001 From: lejingw Date: Wed, 21 Oct 2015 11:49:33 +0800 Subject: [PATCH 13/24] 1 --- src/main/java/org/zbus/mq/server/PubSub.java | 2 +- src/main/java/org/zbus/rpc/RpcFactory.java | 103 ++++++++++--------- 2 files changed, 57 insertions(+), 48 deletions(-) diff --git a/src/main/java/org/zbus/mq/server/PubSub.java b/src/main/java/org/zbus/mq/server/PubSub.java index 8e22f260..84ec70d3 100644 --- a/src/main/java/org/zbus/mq/server/PubSub.java +++ b/src/main/java/org/zbus/mq/server/PubSub.java @@ -92,7 +92,7 @@ public class PubSub extends AbstractMQ{ if(pullMessage == null) continue; msg = pull.getMsgQ().poll(); - if(msg == null) break; + if(msg == null) continue; msg.setResponseStatus(200); //支持浏览器 msg.setRawId(msg.getId()); diff --git a/src/main/java/org/zbus/rpc/RpcFactory.java b/src/main/java/org/zbus/rpc/RpcFactory.java index 54d01a80..9b3db440 100644 --- a/src/main/java/org/zbus/rpc/RpcFactory.java +++ b/src/main/java/org/zbus/rpc/RpcFactory.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - * + *

* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + *

* The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + *

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -33,102 +33,111 @@ import org.zbus.kit.log.Logger; import org.zbus.net.http.Message.MessageInvoker; -public class RpcFactory { +public class RpcFactory { private static final Logger log = Logger.getLogger(RpcFactory.class); private static Constructor rpcInvokerCtor; - private Map rpcInvokerCache = new ConcurrentHashMap(); - private final MessageInvoker messageInvoker; + private Map rpcInvokerCache = new ConcurrentHashMap(); + private final MessageInvoker messageInvoker; + static { try { - rpcInvokerCtor = RpcInvocationHandler.class.getConstructor(new Class[] {RpcInvoker.class }); + rpcInvokerCtor = RpcInvocationHandler.class.getConstructor(new Class[]{RpcInvoker.class}); } catch (Exception e) { log.error(e.getMessage(), e); } - } - + } + public RpcFactory(MessageInvoker messageInvoker) { this.messageInvoker = messageInvoker; } - public T getService(Class api) throws Exception{ + + public T getService(Class api) throws Exception { return getService(api, new RpcConfig()); } - public T getService(Class api, String serviceUrl) throws Exception { - RpcConfig config = parseRpcConfig(serviceUrl); + + public T getService(Class api, String serviceUrl) throws Exception { + RpcConfig config = parseRpcConfig(serviceUrl); return getService(api, config); - } - + } + @SuppressWarnings("unchecked") - public T getService(Class api, RpcConfig config) throws Exception { + public T getService(Class api, RpcConfig config) throws Exception { String module = config.getModule(); - if(module == null ||module.trim().length()==0){ + if (module == null || module.trim().length() == 0) { module = api.getSimpleName(); config.setModule(module); } - + String encoding = config.getEncoding(); - int timeout = config.getTimeout(); - + int timeout = config.getTimeout(); + String cacheKey = String.format("module=%s&&encoding=%s&&timeout=%d", module, encoding, timeout); - + RpcInvocationHandler rpcInvoker = rpcInvokerCache.get(cacheKey); - Class[] interfaces = new Class[] { api }; - if(rpcInvoker == null){ + Class[] interfaces = new Class[]{api}; + if (rpcInvoker == null) { RpcInvoker rpc = new RpcInvoker(messageInvoker, config); - rpcInvoker = rpcInvokerCtor.newInstance(rpc); - rpcInvokerCache.put(cacheKey, rpcInvoker); + rpcInvoker = rpcInvokerCtor.newInstance(rpc); + rpcInvokerCache.put(cacheKey, rpcInvoker); } ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); return (T) Proxy.newProxyInstance(classLoader, interfaces, rpcInvoker); - } - + } + private static RpcConfig parseRpcConfig(String kvstring) { - RpcConfig config = new RpcConfig(); + RpcConfig config = new RpcConfig(); String[] parts = kvstring.split("\\&"); - for(String kv : parts){ + for (String kv : parts) { String[] kvp = kv.split("="); String key = kvp[0].trim(); String val = ""; - if(kvp.length>1){ + if (kvp.length > 1) { val = kvp[1].trim(); - } - if("module".equals(key)){ + } + if ("module".equals(key)) { config.setModule(val); - } else if("encoding".equals(key)){ + } else if ("encoding".equals(key)) { config.setEncoding(val); - } else if("timeout".equals(key)){ + } else if ("timeout".equals(key)) { int timeout = 2500;//default - try{ timeout = Integer.valueOf(val); }catch(Exception e){} + try { + timeout = Integer.valueOf(val); + } catch (Exception e) { + } config.setTimeout(timeout); - } else if("verbose".equals(key)){ + } else if ("verbose".equals(key)) { boolean verbose = false; - try{ verbose = Boolean.valueOf(val); }catch(Exception e){} + try { + verbose = Boolean.valueOf(val); + } catch (Exception e) { + } config.setVerbose(verbose); - } + } } return config; - } + } } -class RpcInvocationHandler implements InvocationHandler { - private RpcInvoker rpc; +class RpcInvocationHandler implements InvocationHandler { + private RpcInvoker rpc; private static final Object REMOTE_METHOD_CALL = new Object(); public RpcInvocationHandler(RpcInvoker rpc) { this.rpc = rpc; } - + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if(args == null){ + if (args == null) { args = new Object[0]; } Object value = handleLocalMethod(proxy, method, args); - if (value != REMOTE_METHOD_CALL) return value; - Class returnType = method.getReturnType(); - return rpc.invokeSync(returnType, method.getName(),method.getParameterTypes(), args); + if (value != REMOTE_METHOD_CALL) return value; + Class returnType = method.getReturnType(); + return rpc.invokeSync(returnType, method.getName(), method.getParameterTypes(), args); } protected Object handleLocalMethod(Object proxy, Method method, - Object[] args) throws Throwable { + Object[] args) throws Throwable { String methodName = method.getName(); Class[] params = method.getParameterTypes(); @@ -145,5 +154,5 @@ class RpcInvocationHandler implements InvocationHandler { return "RpcInvocationHandler[" + this.rpc + "]"; } return REMOTE_METHOD_CALL; - } + } } \ No newline at end of file -- Gitee From b9655df71811aeb2903b4c7414c3247136db50fd Mon Sep 17 00:00:00 2001 From: lejingw Date: Wed, 21 Oct 2015 13:21:18 +0800 Subject: [PATCH 14/24] 1 --- zbus-dist/zbus-6.2.0.jar => zbus-6.2.0.jar | Bin zbus-dist/zbus-1.0-RELEASE.jar | Bin 0 -> 278767 bytes zbus-dist/zbus.sh | 4 +--- 3 files changed, 1 insertion(+), 3 deletions(-) rename zbus-dist/zbus-6.2.0.jar => zbus-6.2.0.jar (100%) create mode 100644 zbus-dist/zbus-1.0-RELEASE.jar mode change 100644 => 100755 zbus-dist/zbus.sh diff --git a/zbus-dist/zbus-6.2.0.jar b/zbus-6.2.0.jar similarity index 100% rename from zbus-dist/zbus-6.2.0.jar rename to zbus-6.2.0.jar diff --git a/zbus-dist/zbus-1.0-RELEASE.jar b/zbus-dist/zbus-1.0-RELEASE.jar new file mode 100644 index 0000000000000000000000000000000000000000..1fbbd68c39884f825be28ae70de645ff955a3d8c GIT binary patch literal 278767 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š==$a{o$Pg6Ldfx`@)D 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%0A@T*1Y=o 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%0Ada~a>s4vviWpi{6Qh-j_Z10ht3sxYhGLm^b> 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
  • M<9by|IRNDH!7^! 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 literal 0 HcmV?d00001 diff --git a/zbus-dist/zbus.sh b/zbus-dist/zbus.sh old mode 100644 new mode 100755 index 80c582bb..9cfc545d --- a/zbus-dist/zbus.sh +++ b/zbus-dist/zbus.sh @@ -1,10 +1,8 @@ #/usr/bin -JAVA_HOME=/usr/local/java/jdk7 +JAVA_HOME=`/usr/libexec/java_home -v 1.7` ZBUS_HOME=. JAVA_OPTS="-Dfile.encoding=UTF-8 -server -Xms64m -Xmx1024m -XX:+UseParallelGC" MAIN_CLASS=org.zbus.mq.server.MqServer MAIN_OPTS="-h 0.0.0.0 -p 15555 -verbose false -conf zbus.properties -store store -track" LIB_OPTS="$ZBUS_HOME/lib:$ZBUS_HOME/*" nohup $JAVA_HOME/bin/java $JAVA_OPTS -cp $LIB_OPTS $MAIN_CLASS $MAIN_OPTS > stdout.log 2>&1 & - - -- Gitee From cfcf7f3d477e234ff62739330ce5d75e23648ee3 Mon Sep 17 00:00:00 2001 From: lejingw Date: Fri, 23 Oct 2015 10:40:49 +0800 Subject: [PATCH 15/24] 1 --- .../java/org/zbus/broker/SingleBroker.java | 2 + src/main/java/org/zbus/rpc/mq/Service.java | 53 +++++++++---------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/zbus/broker/SingleBroker.java b/src/main/java/org/zbus/broker/SingleBroker.java index 50bf12ab..52a23b1e 100644 --- a/src/main/java/org/zbus/broker/SingleBroker.java +++ b/src/main/java/org/zbus/broker/SingleBroker.java @@ -49,6 +49,8 @@ public class SingleBroker implements Broker { if(config.getDispatcher() == null){ this.ownDispatcher = true; this.dispatcher = new Dispatcher(); + this.dispatcher.selectorCount(config.getSelectorCount()); + this.dispatcher.executorCount(config.getExecutorCount()); this.config.setDispatcher(dispatcher); } else { this.dispatcher = config.getDispatcher(); diff --git a/src/main/java/org/zbus/rpc/mq/Service.java b/src/main/java/org/zbus/rpc/mq/Service.java index 0870b2fa..68dba4b3 100644 --- a/src/main/java/org/zbus/rpc/mq/Service.java +++ b/src/main/java/org/zbus/rpc/mq/Service.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -33,9 +33,9 @@ import org.zbus.net.http.Message; import org.zbus.net.http.Message.MessageHandler; import org.zbus.net.http.Message.MessageProcessor; -public class Service implements Closeable { - private final ServiceConfig config; - private Consumer[][] consumerGroups; +public class Service implements Closeable { + private final ServiceConfig config; + private Consumer[][] consumerGroups; private boolean isStarted = false; public Service(ServiceConfig config){ this.config = config; @@ -44,9 +44,9 @@ public class Service implements Closeable { } if(config.getMessageProcessor() == null){ throw new IllegalArgumentException("ServiceHandler required"); - } + } } - + @Override public void close() throws IOException { if(this.consumerGroups != null){ @@ -55,43 +55,43 @@ public class Service implements Closeable { consumer.stop(); } } - } + } } - - public void start() throws IOException{ + + public void start() throws IOException{ if(isStarted) return; - + final MessageProcessor processor = config.getMessageProcessor(); Broker[] brokers = config.getBrokers(); int consumerCount = config.getConsumerCount(); if(brokers.length < 1 || consumerCount < 1) return; - + this.consumerGroups = new Consumer[brokers.length][]; for(int i=0; i Date: Mon, 9 Nov 2015 17:03:46 +0800 Subject: [PATCH 16/24] 1 --- ChangeLog | 17 ++ README.md | 2 +- ToDo | 37 +++ ...72\345\205\263\347\263\273\345\233\276.md" | 1 + doc/IoAdaptor.png | Bin 0 -> 12829 bytes doc/tcp_proxy_example.png | Bin 0 -> 35743 bytes ...7\357\274\210\344\270\200\357\274\211.doc" | Bin 0 -> 22016 bytes ...7\357\274\210\344\272\214\357\274\211.doc" | Bin 0 -> 138752 bytes pom.xml | 24 ++ .../zbus/broker/ha/DefaultBrokerSelector.java | 8 +- .../org/zbus/broker/ha/ServerEntryTable.java | 10 + .../java/org/zbus/broker/ha/TrackServer.java | 2 +- .../java/org/zbus/broker/ha/TrackSub.java | 2 +- src/main/java/org/zbus/kit/NetKit.java | 31 +- src/main/java/org/zbus/kit/log/Logger.java | 17 +- .../zbus/kit/log/impl/Sl4jLoggerFactory.java | 137 +++++++++ .../java/org/zbus/kit/pool/PoolConfig.java | 6 +- src/main/java/org/zbus/mq/Consumer.java | 19 +- src/main/java/org/zbus/mq/MqAdmin.java | 137 +++++---- src/main/java/org/zbus/mq/MqConfig.java | 23 +- src/main/java/org/zbus/mq/Producer.java | 32 ++- src/main/java/org/zbus/mq/Protocol.java | 12 +- .../java/org/zbus/mq/server/AbstractMQ.java | 26 ++ src/main/java/org/zbus/mq/server/Auth.java | 16 ++ src/main/java/org/zbus/mq/server/MQ.java | 3 +- .../java/org/zbus/mq/server/MqAdaptor.java | 264 ++++++++++++------ .../java/org/zbus/mq/server/MqServer.java | 8 +- .../org/zbus/mq/server/MqServerConfig.java | 120 +------- src/main/java/org/zbus/mq/server/PubSub.java | 5 +- src/main/java/org/zbus/mq/server/UrlInfo.java | 131 +++++++++ src/main/java/org/zbus/net/Client.java | 7 +- .../java/org/zbus/net/InvokingClient.java | 6 + src/main/java/org/zbus/net/Server.java | 137 +++++---- src/main/java/org/zbus/net/Sync.java | 7 + .../java/org/zbus/net/core/Dispatcher.java | 24 +- .../org/zbus/net/core/SelectorThread.java | 7 +- src/main/java/org/zbus/net/http/Message.java | 28 +- .../java/org/zbus/proxy/TcpProxyServer.java | 39 ++- src/main/java/org/zbus/rpc/RpcFactory.java | 16 +- src/main/java/org/zbus/rpc/RpcInvoker.java | 8 + src/main/java/org/zbus/rpc/RpcMethod.java | 37 +++ src/main/java/org/zbus/rpc/RpcProcessor.java | 154 ++++++++-- .../java/org/zbus/rpc/direct/Service.java | 30 +- .../org/zbus/rpc/direct/ServiceConfig.java | 57 +++- .../java/org/zbus/rpc/mq/ServiceConfig.java | 4 +- src/main/resources/logback.xml | 20 ++ src/main/resources/proxy.properties | 2 + src/main/resources/zbus.htm | 71 +++-- src/test/java/org/zbus/diskq/DiskQueue.java | 161 +++++++++++ .../java/org/zbus/diskq/DiskQueueBlock.java | 181 ++++++++++++ .../java/org/zbus/diskq/DiskQueueFork.java | 195 +++++++++++++ .../java/org/zbus/diskq/DiskQueueIndex.java | 242 ++++++++++++++++ .../java/org/zbus/diskq/DiskQueuePool.java | 158 +++++++++++ src/test/java/org/zbus/diskq/ForkedIndex.java | 117 ++++++++ .../org/zbus/ha/tracker/TrackSubExample.java | 2 +- .../org/zbus/httpclient/HttpClientRpc.java | 4 +- src/test/java/org/zbus/mq/ProducerSync.java | 9 +- src/test/java/org/zbus/mq/QueryMqExample.java | 22 ++ .../org/zbus/mq/diskq/DiskQueueProduce.java | 2 +- .../mq/service_via_mq/ServiceExample.java | 4 +- src/test/java/org/zbus/net/MyClient.java | 20 +- .../java/org/zbus/net/MyServerAdaptor.java | 30 +- .../java/org/zbus/net/TcpProxyAdaptor.java | 99 +++++++ .../org/zbus/net/codec/StringAdaptor.java | 27 ++ src/test/java/org/zbus/perf/ConsumerPerf.java | 52 ++++ src/test/java/org/zbus/perf/Perf.java | 103 +++++++ src/test/java/org/zbus/perf/ProducerPerf.java | 39 +++ .../zbus/perf/latency/ConsumerLatency.java | 32 +++ .../zbus/perf/latency/ProducerLatency.java | 36 +++ .../org/zbus/perf/latency/ReqRepLatency.java | 43 +++ src/test/java/org/zbus/perf/net/NetPerf.java | 42 +++ .../java/org/zbus/perf/net/NetServer.java | 40 +++ src/test/java/org/zbus/perf/rpc/RpcPerf.java | 93 ++++++ .../java/org/zbus/proxy/ClientExample.java | 2 +- src/test/java/org/zbus/proxy/ClientPerf.java | 2 +- .../java/org/zbus/proxy/ConnectionPerf.java | 2 +- src/test/java/org/zbus/pubsub/PubSync.java | 27 +- src/test/java/org/zbus/pubsub/Sub.java | 6 +- src/test/java/org/zbus/rpc/RpcClient.java | 4 +- src/test/java/org/zbus/rpc/RpcClientRaw.java | 9 +- .../java/org/zbus/rpc/RpcClientTestNull.java | 33 +++ src/test/java/org/zbus/rpc/biz/Interface.java | 4 + .../java/org/zbus/rpc/biz/InterfaceImpl.java | 14 +- .../org/zbus/rpc/direct/DirectRpcClient.java | 11 +- .../zbus/rpc/direct/DirectRpcClientHA.java | 4 +- .../org/zbus/rpc/direct/DirectRpcService.java | 4 +- .../zbus/rpc/direct/DirectRpcServiceHA.java | 5 +- .../java/org/zbus/rpc/mq/MqRpcClient.java | 19 +- .../java/org/zbus/rpc/mq/MqRpcClientHA.java | 60 ++-- .../java/org/zbus/rpc/mq/MqRpcService.java | 17 +- .../java/org/zbus/rpc/mq/MqRpcServiceHA.java | 2 +- .../zbus/rpc/mq/MqRpcServiceMultiBroker.java | 38 +++ src/test/resources/logback.xml | 20 ++ zbus-dist/zbus.bat | 4 +- zbus-dist/zbus.sh | 13 +- 95 files changed, 3208 insertions(+), 589 deletions(-) create mode 100644 ChangeLog create mode 100644 ToDo create mode 100644 doc/IoAdaptor.png create mode 100644 doc/tcp_proxy_example.png create mode 100644 "doc/zbus.NET\351\200\232\350\256\257\346\250\241\345\235\227\357\274\210\344\270\200\357\274\211.doc" create mode 100644 "doc/zbus.NET\351\200\232\350\256\257\346\250\241\345\235\227\357\274\210\344\272\214\357\274\211.doc" create mode 100644 src/main/java/org/zbus/kit/log/impl/Sl4jLoggerFactory.java create mode 100644 src/main/java/org/zbus/mq/server/Auth.java create mode 100644 src/main/java/org/zbus/mq/server/UrlInfo.java create mode 100644 src/main/java/org/zbus/rpc/RpcMethod.java create mode 100644 src/main/resources/logback.xml create mode 100644 src/main/resources/proxy.properties create mode 100644 src/test/java/org/zbus/diskq/DiskQueue.java create mode 100644 src/test/java/org/zbus/diskq/DiskQueueBlock.java create mode 100644 src/test/java/org/zbus/diskq/DiskQueueFork.java create mode 100644 src/test/java/org/zbus/diskq/DiskQueueIndex.java create mode 100644 src/test/java/org/zbus/diskq/DiskQueuePool.java create mode 100644 src/test/java/org/zbus/diskq/ForkedIndex.java create mode 100644 src/test/java/org/zbus/mq/QueryMqExample.java create mode 100644 src/test/java/org/zbus/net/TcpProxyAdaptor.java create mode 100644 src/test/java/org/zbus/net/codec/StringAdaptor.java create mode 100644 src/test/java/org/zbus/perf/ConsumerPerf.java create mode 100644 src/test/java/org/zbus/perf/Perf.java create mode 100644 src/test/java/org/zbus/perf/ProducerPerf.java create mode 100644 src/test/java/org/zbus/perf/latency/ConsumerLatency.java create mode 100644 src/test/java/org/zbus/perf/latency/ProducerLatency.java create mode 100644 src/test/java/org/zbus/perf/latency/ReqRepLatency.java create mode 100644 src/test/java/org/zbus/perf/net/NetPerf.java create mode 100644 src/test/java/org/zbus/perf/net/NetServer.java create mode 100644 src/test/java/org/zbus/perf/rpc/RpcPerf.java create mode 100644 src/test/java/org/zbus/rpc/RpcClientTestNull.java create mode 100644 src/test/java/org/zbus/rpc/mq/MqRpcServiceMultiBroker.java create mode 100644 src/test/resources/logback.xml diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..6a5ffb07 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,17 @@ +zbus-6.2.0 发布,整个项目模块化重构,改进内容: +1. MQ默认直接采用持久化。MQ速度在SSD磁盘上可达200M+/s,数十亿级消息堆积测试(100G+磁盘) +2. RPC支持分为直接RPC与基于MQ的RPC,直接RPC性能优于基于MQ的RPC。 +3. Broker独立模型重构,支持HA高可用,不只面向MQ工作,可以方便支持直接RPC的负载均衡。 +4. 添加Thrfit协议接入(RPC),整体上支持HTTP短链接,Extend HTTP的TCP长连接,Thrift客户端接入。 +5. 消息通讯基础zbus.NET保持小、模块化(~50K),方便个性化协议扩展 +6. 添加支持普通TCP代理,DMZ网络安全结构的的TCP代理 +7. 提供大量示例,包括MQ,PubSub,RPC,Proxy,Thrift,Simple HTTP等。 + + +zbus-6.3.0 changelog +1. fix net.Client close, disable disconnected handler when close actively. +2. "content-encoding" in HTTP changed to "encoding" (extend HTTP) for + compatibility to standard HTTP when using browser. +3. 增加支持不指定随机端口启动Server +4. 修复Rpc客户端运行中失败引起Sevice响应实例清除的bug +5. zbus重启,service快速注册返回,InvokingClient增加Sync清除 \ No newline at end of file diff --git a/README.md b/README.md index cdf4b568..f38e8a7d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ##ZBUS = MQ + RPC + PROXY -* **支持消息队列, 发布订阅, RPC, 代理(TCP/HTTP/DMZ)** +* **支持消息队列, 发布订阅, RPC, 代理(TCP/DMZ)** * **亿级消息堆积能力、支持HA高可用** * **单个Jar包无依赖 ~300K** * **服务代理 -- 适配改造已有业务系统,使之具备跨平台与语言** diff --git a/ToDo b/ToDo new file mode 100644 index 00000000..4dafb2cf --- /dev/null +++ b/ToDo @@ -0,0 +1,37 @@ +支持消息队列复制(不同业务维度消费同一个消息) + +Index与Block分离 +MyMQ.idx +readNum +readPos +readCount + +MyMQ.idx +MyMQ.fork + + + +sub-index-id,二级指针 + +支持zbus内部事件消息通知PubSub + +增加直接返回网络测试 : +http://localhost:15555/test + +增加RPC请求的简单URL解释支持: +http://localhost:15555/MyRpc/echo?hong + +增加监控单个服务的详细信息 +http://localhost:15555/MyRpc + +/MyRpc/plus?1,2 +/MyRpc/plus?params=1,2&&module=xxx +/mq=MyRpc&&method=plus&¶ms=1,2 + + +/ +/?cmd=admin&&sub_cmd=data +/?cmd=admin&&sub_cmd=jquery +/?cmd=test + + diff --git "a/doc/02. ZBUS\345\272\224\347\224\250\346\236\204\345\273\272\345\205\263\347\263\273\345\233\276.md" "b/doc/02. ZBUS\345\272\224\347\224\250\346\236\204\345\273\272\345\205\263\347\263\273\345\233\276.md" index ce999691..f3e26a5b 100644 --- "a/doc/02. ZBUS\345\272\224\347\224\250\346\236\204\345\273\272\345\205\263\347\263\273\345\233\276.md" +++ "b/doc/02. ZBUS\345\272\224\347\224\250\346\236\204\345\273\272\345\205\263\347\263\273\345\233\276.md" @@ -13,6 +13,7 @@ ZBUS的消息队列MQ,远程方法调用RPC,总线代理等等功能设计 在消息队列基础上,可以衍生出C=B=S模式:这是CS模式的变种,客户端C请求消息统一到中介商B的队列中,服务端S获取中介商B队列的请求处理后返回给客户端C。这就是借助Broker来实现的C/S模式 +![CBS请求应答](http://git.oschina.net/uploads/images/2015/0701/135128_bc247c16_7458.png "CBS请求应答") Client生产一个请求消息到Broker中,Service消费到请求消息处理后,生产一个应答消息给Broker,最后Client消费到应道消息 diff --git a/doc/IoAdaptor.png b/doc/IoAdaptor.png new file mode 100644 index 0000000000000000000000000000000000000000..229374cb6c6e5ee85a068c3803359e8c54375656 GIT binary patch literal 12829 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%0AjW8|uFpf!+0X7im=2udy-KT1alen3 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 literal 0 HcmV?d00001 diff --git "a/doc/zbus.NET\351\200\232\350\256\257\346\250\241\345\235\227\357\274\210\344\270\200\357\274\211.doc" "b/doc/zbus.NET\351\200\232\350\256\257\346\250\241\345\235\227\357\274\210\344\270\200\357\274\211.doc" new file mode 100644 index 0000000000000000000000000000000000000000..bd8fe00cdd3cbf4775c032360cd1403391c0cb53 GIT binary patch literal 22016 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

    Q)JOw3@o}R7Fot#`R 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 z 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 zo)uxd+fprovided + + org.slf4j + slf4j-api + 1.7.5 + provided + + + + + org.slf4j + slf4j-log4j12 + 1.7.5 + provided + + log4j log4j @@ -68,6 +90,8 @@ provided + + org.springframework spring-context diff --git a/src/main/java/org/zbus/broker/ha/DefaultBrokerSelector.java b/src/main/java/org/zbus/broker/ha/DefaultBrokerSelector.java index c306f066..c50f7308 100644 --- a/src/main/java/org/zbus/broker/ha/DefaultBrokerSelector.java +++ b/src/main/java/org/zbus/broker/ha/DefaultBrokerSelector.java @@ -166,9 +166,13 @@ public class DefaultBrokerSelector implements BrokerSelector{ if(se.consumerCount > 0) activeCount++; } if(activeCount == 0){ - activeCount = allBrokers.size(); + activeCount = serverList.consumerFirstList.size(); } - int idx = localIpHashCode%activeCount; + if(activeCount == 0){ + return null; + } + + int idx = localIpHashCode%activeCount; ServerEntry se = serverList.consumerFirstList.get(idx); if(se != null){ broker = getBroker(se.serverAddr); diff --git a/src/main/java/org/zbus/broker/ha/ServerEntryTable.java b/src/main/java/org/zbus/broker/ha/ServerEntryTable.java index 40710a6d..2b3a3620 100644 --- a/src/main/java/org/zbus/broker/ha/ServerEntryTable.java +++ b/src/main/java/org/zbus/broker/ha/ServerEntryTable.java @@ -207,10 +207,20 @@ public class ServerEntryTable implements Closeable{ public void setVerbose(boolean verbose) { this.verbose = verbose; + } + + public Map getEntry2ServerList() { + return entry2ServerList; + } + + public Map> getServer2EntryList() { + return server2EntryList; } + + public static class ServerList implements Iterable{ public final String entryId; public Map serverTable = new ConcurrentHashMap(); diff --git a/src/main/java/org/zbus/broker/ha/TrackServer.java b/src/main/java/org/zbus/broker/ha/TrackServer.java index 54031fe4..c252211e 100644 --- a/src/main/java/org/zbus/broker/ha/TrackServer.java +++ b/src/main/java/org/zbus/broker/ha/TrackServer.java @@ -72,7 +72,7 @@ public class TrackServer extends Server{ public static void main(String[] args) throws Exception { String host = ConfigKit.option(args, "-h", "0.0.0.0"); - int port = ConfigKit.option(args, "-p", 16667); + int port = ConfigKit.option(args, "-p", 16666); boolean verbose = ConfigKit.option(args, "-verbose", true); final TrackServer server = new TrackServer(host+":"+port); server.setVerbose(verbose); diff --git a/src/main/java/org/zbus/broker/ha/TrackSub.java b/src/main/java/org/zbus/broker/ha/TrackSub.java index c0b0a042..0970422b 100644 --- a/src/main/java/org/zbus/broker/ha/TrackSub.java +++ b/src/main/java/org/zbus/broker/ha/TrackSub.java @@ -193,7 +193,7 @@ public class TrackSub implements Closeable{ @Override public void close() throws IOException { - for(MessageClient client : allTrackers){ + for(MessageClient client : allTrackers){ client.close(); } allTrackers.clear(); diff --git a/src/main/java/org/zbus/kit/NetKit.java b/src/main/java/org/zbus/kit/NetKit.java index 2fb4f578..a988e00e 100644 --- a/src/main/java/org/zbus/kit/NetKit.java +++ b/src/main/java/org/zbus/kit/NetKit.java @@ -64,25 +64,38 @@ public class NetKit { public static String getLocalIp() { try { - Pattern pattern = Pattern.compile("(192|172|10)\\.[0-9]+\\.[0-9]+\\.[0-9]+"); + Pattern pattern = Pattern.compile("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"); Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); - + String condidate = null; while (interfaces.hasMoreElements()) { NetworkInterface ni = interfaces.nextElement(); + if(!ni.isUp()){ + continue; + } Enumeration en = ni.getInetAddresses(); while (en.hasMoreElements()) { InetAddress addr = en.nextElement(); String ip = addr.getHostAddress(); Matcher matcher = pattern.matcher(ip); - if (matcher.matches()) { + if (matcher.matches()) { + if(ip.startsWith("127.")) continue; + if(ip.startsWith("10.") + || ip.startsWith("172.") + || ip.startsWith("192.") + ){ + if(condidate == null){ + condidate = ip; + } + continue; + } return ip; - } - } + } + } } - return "0.0.0.0"; - } catch (Throwable e) { - e.printStackTrace(); - return "0.0.0.0"; + if(condidate != null) return condidate; + return "127.0.0.1"; + } catch (Throwable e) { + return "127.0.0.1"; } } diff --git a/src/main/java/org/zbus/kit/log/Logger.java b/src/main/java/org/zbus/kit/log/Logger.java index 7d04baad..63271c9d 100644 --- a/src/main/java/org/zbus/kit/log/Logger.java +++ b/src/main/java/org/zbus/kit/log/Logger.java @@ -49,13 +49,28 @@ public abstract class Logger { if (factory != null){ return ; } - String defaultFactory = String.format("%s.impl.Log4jLoggerFactory", Logger.class.getPackage().getName()); + try { //default to Log4j Class.forName("org.apache.log4j.Logger"); + String defaultFactory = String.format("%s.impl.Log4jLoggerFactory", Logger.class.getPackage().getName()); Class factoryClass = Class.forName(defaultFactory); factory = (LoggerFactory)factoryClass.newInstance(); + return; + } catch (Exception e) { + } + + try { + //try slf4j + Class.forName("org.slf4j.Logger"); + String defaultFactory = String.format("%s.impl.Sl4jLoggerFactory", Logger.class.getPackage().getName()); + Class factoryClass = Class.forName(defaultFactory); + factory = (LoggerFactory)factoryClass.newInstance(); + return; } catch (Exception e) { + } + + if(factory == null){ factory = new JdkLoggerFactory(); } } diff --git a/src/main/java/org/zbus/kit/log/impl/Sl4jLoggerFactory.java b/src/main/java/org/zbus/kit/log/impl/Sl4jLoggerFactory.java new file mode 100644 index 00000000..4751585c --- /dev/null +++ b/src/main/java/org/zbus/kit/log/impl/Sl4jLoggerFactory.java @@ -0,0 +1,137 @@ +/** + * The MIT License (MIT) + * Copyright (c) 2009-2015 HONG LEIMING + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.zbus.kit.log.impl; + + +import org.slf4j.spi.LocationAwareLogger; +import org.zbus.kit.log.Logger; +import org.zbus.kit.log.LoggerFactory; + +public class Sl4jLoggerFactory implements LoggerFactory { + + public Logger getLogger(Class clazz) { + return new Sl4jLogger(clazz); + } + + public Logger getLogger(String name) { + return new Sl4jLogger(name); + } + + public static void main(String[] args){ + Logger log = new Sl4jLogger(Sl4jLoggerFactory.class); + log.info("test"); + } +} + +class Sl4jLogger extends Logger { + private org.slf4j.Logger log; + private final String FQCN = Sl4jLogger.class.getName(); + + Sl4jLogger(Class clazz) { + log = org.slf4j.LoggerFactory.getLogger(clazz); + } + + Sl4jLogger(String name) { + log = org.slf4j.LoggerFactory.getLogger(name); + } + + public void info(String message) { + info(message, (Throwable)null); + } + + public void info(String message, Throwable t) { + if (log instanceof LocationAwareLogger) { + ((LocationAwareLogger) log).log(null, FQCN, + LocationAwareLogger.INFO_INT, message, null, t); + } else { + log.info(message, t); + } + } + + public void debug(String message) { + debug(message, (Throwable)null); + } + + public void debug(String message, Throwable t) { + if (log instanceof LocationAwareLogger) { + ((LocationAwareLogger) log).log(null, FQCN, + LocationAwareLogger.DEBUG_INT, message, null, t); + } else { + log.debug(message, t); + } + } + + public void warn(String message) { + warn(message, (Throwable)null); + } + + public void warn(String message, Throwable t) { + if (log instanceof LocationAwareLogger) { + ((LocationAwareLogger) log).log(null, FQCN, + LocationAwareLogger.WARN_INT, message, null, t); + } else { + log.warn(message); + } + } + + public void error(String message) { + error(message, (Throwable)null); + } + + public void error(String message, Throwable t) { + if (log instanceof LocationAwareLogger) { + ((LocationAwareLogger) log).log(null, FQCN, + LocationAwareLogger.ERROR_INT, message, null, t); + } else { + log.error(message); + } + } + + public void fatal(String message) { + error(message); + } + + public void fatal(String message, Throwable t) { + error(message, t); + } + + public boolean isDebugEnabled() { + return log.isDebugEnabled(); + } + + public boolean isInfoEnabled() { + return log.isInfoEnabled(); + } + + public boolean isWarnEnabled() { + return log.isWarnEnabled(); + } + + public boolean isErrorEnabled() { + return log.isErrorEnabled(); + } + + public boolean isFatalEnabled() { + return log.isErrorEnabled(); + } +} \ No newline at end of file diff --git a/src/main/java/org/zbus/kit/pool/PoolConfig.java b/src/main/java/org/zbus/kit/pool/PoolConfig.java index 0a3c5548..3d13f799 100644 --- a/src/main/java/org/zbus/kit/pool/PoolConfig.java +++ b/src/main/java/org/zbus/kit/pool/PoolConfig.java @@ -23,9 +23,9 @@ package org.zbus.kit.pool; public class PoolConfig implements Cloneable{ - private int maxTotal = 8; - private int maxIdle = 8; - private int minIdle = 0; + private int maxTotal = 64; + private int maxIdle = 64; + private int minIdle = 64; private long minEvictableIdleTimeMillis = 1000L * 60L * 30L; private Object support; diff --git a/src/main/java/org/zbus/mq/Consumer.java b/src/main/java/org/zbus/mq/Consumer.java index 8221a609..15917a5d 100644 --- a/src/main/java/org/zbus/mq/Consumer.java +++ b/src/main/java/org/zbus/mq/Consumer.java @@ -38,7 +38,7 @@ public class Consumer extends MqAdmin implements Closeable { private MessageClient client; // 消费者拥有一个物理链接 private String topic = null; // 为发布订阅者的主题,当Consumer的模式为发布订阅时候起作用 - private int consumeTimeout = 10000; //ms + private int consumeTimeout = 300000; //5 minutes public Consumer(Broker broker, String mq, MqMode... mode) { super(broker, mq, mode); } @@ -64,6 +64,7 @@ public class Consumer extends MqAdmin implements Closeable { Message req = new Message(); req.setCmd(Protocol.Consume); req.setMq(mq); + req.setHead("token", accessToken); if (MqMode.isEnabled(this.mode, MqMode.PubSub)) { if (this.topic != null) { req.setTopic(this.topic); @@ -73,16 +74,18 @@ public class Consumer extends MqAdmin implements Closeable { Message res = null; try { res = client.invokeSync(req, timeout); - if (res != null && res.isStatus404()) { + if(res == null) return res; + res.setId(res.getRawId()); + res.removeHead(Message.RAWID); + if(res.isStatus200()) return res; + + if(res.isStatus404()) { if (!this.createMQ()) { - throw new IllegalStateException("register error"); + throw new MqException(res.getBodyString()); } return recv(timeout); } - if(res != null){ - res.setId(res.getRawId()); - res.removeHead(Message.RAWID); - } + throw new MqException(res.getBodyString()); } catch (ClosedByInterruptException e) { throw new InterruptedException(e.getMessage()); } catch (IOException e) { @@ -105,7 +108,7 @@ public class Consumer extends MqAdmin implements Closeable { } @Override - protected Message invokeCreateMQ(Message req) throws IOException, + protected Message invokeSync(Message req) throws IOException, InterruptedException { ensureClient(); return client.invokeSync(req); diff --git a/src/main/java/org/zbus/mq/MqAdmin.java b/src/main/java/org/zbus/mq/MqAdmin.java index 632df49f..bfbbb0df 100644 --- a/src/main/java/org/zbus/mq/MqAdmin.java +++ b/src/main/java/org/zbus/mq/MqAdmin.java @@ -1,17 +1,17 @@ /** * The MIT License (MIT) * Copyright (c) 2009-2015 HONG LEIMING - *

    + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - *

    + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - *

    + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -30,64 +30,79 @@ import org.zbus.mq.Protocol.MqMode; import org.zbus.net.http.Message; -public class MqAdmin { - protected final Broker broker; - protected String mq; //队列唯一性标识 - protected final int mode; +public class MqAdmin{ + protected final Broker broker; + protected String mq; //队列唯一性标识 + protected final int mode; + protected String accessToken = ""; + protected String registerToken = ""; + + public MqAdmin(Broker broker, String mq, MqMode... mode){ + this.broker = broker; + this.mq = mq; + if(mode.length == 0){ + this.mode = MqMode.intValue(MqMode.MQ); + } else { + this.mode = MqMode.intValue(mode); + } + } + + public MqAdmin(MqConfig config){ + this.broker = config.getBroker(); + this.mq = config.getMq(); + this.mode = config.getMode(); + this.accessToken = config.getAccessToken(); + this.registerToken = config.getRegisterToken(); + } + + protected BrokerHint brokerHint(){ + BrokerHint hint = new BrokerHint(); + hint.setEntry(this.mq); + return hint; + } + + /** + * 默认使用broker代理创建,可以覆盖为Client直接创建,比如Consumer + * @param req + * @return + * @throws IOException + */ + protected Message invokeSync(Message req) throws IOException, InterruptedException{ + return broker.invokeSync(req, 2500); + } + + public Message queryMQ() throws IOException, InterruptedException{ + Message req = new Message(); + req.setCmd(Protocol.Query); + req.setMq(this.mq); + req.setHead("register_token", registerToken); + req.setHead("access_token", accessToken); + + return invokeSync(req); + } + + public boolean createMQ() throws IOException, InterruptedException{ + Message req = new Message(); + req.setCmd(Protocol.CreateMQ); + req.setHead("mq_name", mq); + req.setHead("mq_mode", "" + mode); + req.setHead("register_token", registerToken); + req.setHead("access_token", accessToken); + + Message res = invokeSync(req); + if(res == null) return false; + return res.isStatus200(); + } + + public String getMq() { + return mq; + } - public MqAdmin(Broker broker, String mq, MqMode... mode) { - this.broker = broker; - this.mq = mq; - if (mode.length == 0) { - this.mode = MqMode.intValue(MqMode.MQ); - } else { - this.mode = MqMode.intValue(mode); - } - } + public void setMq(String mq) { + this.mq = mq; + } - public MqAdmin(MqConfig config) { - this.broker = config.getBroker(); - this.mq = config.getMq(); - this.mode = config.getMode(); - } - - protected BrokerHint brokerHint() { - BrokerHint hint = new BrokerHint(); - hint.setEntry(this.mq); - return hint; - } - - /** - * 默认使用broker代理创建,可以覆盖为Client直接创建,比如Consumer - * @param req - * @return - * @throws IOException - */ - protected Message invokeCreateMQ(Message req) throws IOException, InterruptedException { - //TODO - return broker.invokeSync(req, 2500); - } - - public boolean createMQ() throws IOException, InterruptedException { - Message req = new Message(); - req.setCmd(Protocol.CreateMQ); - req.setHead("mq_name", mq); - req.setHead("mq_mode", "" + mode); - - Message res = invokeCreateMQ(req); - if (res == null) return false; - return res.isStatus200(); - } - - public String getMq() { - return mq; - } - - public void setMq(String mq) { - this.mq = mq; - } - - public int getMode() { - return mode; - } + public int getMode() { + return mode; + } } diff --git a/src/main/java/org/zbus/mq/MqConfig.java b/src/main/java/org/zbus/mq/MqConfig.java index c6affd53..b4d1289f 100644 --- a/src/main/java/org/zbus/mq/MqConfig.java +++ b/src/main/java/org/zbus/mq/MqConfig.java @@ -30,7 +30,10 @@ public class MqConfig implements Cloneable { protected String mq; //MQ标识,必须设置 protected int mode = MqMode.MQ.intValue(); //创建消息队列时采用到 protected String topic = null; //发布订阅模式下使用 - private boolean verbose = false; + protected boolean verbose = false; + protected String registerToken = ""; + protected String accessToken = ""; + public Broker getBroker() { return broker; @@ -76,6 +79,24 @@ public class MqConfig implements Cloneable { this.verbose = verbose; } + + + public String getRegisterToken() { + return registerToken; + } + + public void setRegisterToken(String registerToken) { + this.registerToken = registerToken; + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + @Override public MqConfig clone() { try { diff --git a/src/main/java/org/zbus/mq/Producer.java b/src/main/java/org/zbus/mq/Producer.java index c9fa7ead..4c23ccf8 100644 --- a/src/main/java/org/zbus/mq/Producer.java +++ b/src/main/java/org/zbus/mq/Producer.java @@ -28,8 +28,9 @@ import org.zbus.broker.Broker; import org.zbus.mq.Protocol.MqMode; import org.zbus.net.Sync.ResultCallback; import org.zbus.net.http.Message; +import org.zbus.net.http.Message.MessageInvoker; -public class Producer extends MqAdmin{ +public class Producer extends MqAdmin implements MessageInvoker{ public Producer(Broker broker, String mq, MqMode... mode) { super(broker, mq, mode); @@ -41,11 +42,7 @@ public class Producer extends MqAdmin{ public void sendAsync(Message msg, final ResultCallback callback) throws IOException { - msg.setCmd(Protocol.Produce); - msg.setMq(this.mq); - msg.setAck(true); - - broker.invokeAsync(msg, callback); + invokeAsync(msg, callback); } public void sendAsync(Message msg) throws IOException { @@ -54,15 +51,32 @@ public class Producer extends MqAdmin{ public Message sendSync(Message msg, int timeout) throws IOException, InterruptedException{ + return invokeSync(msg, timeout); + } + + public Message sendSync(Message msg) throws IOException, InterruptedException{ + return sendSync(msg, 10000); + } + + + @Override + public Message invokeSync(Message msg, int timeout) throws IOException, + InterruptedException { msg.setCmd(Protocol.Produce); msg.setMq(this.mq); msg.setAck(true); return broker.invokeSync(msg, timeout); } - - public Message sendSync(Message msg) throws IOException, InterruptedException{ - return sendSync(msg, 10000); + + @Override + public void invokeAsync(Message msg, ResultCallback callback) + throws IOException { + msg.setCmd(Protocol.Produce); + msg.setMq(this.mq); + msg.setAck(true); + + broker.invokeAsync(msg, callback); } } diff --git a/src/main/java/org/zbus/mq/Protocol.java b/src/main/java/org/zbus/mq/Protocol.java index 5e7b67f4..5de0f944 100644 --- a/src/main/java/org/zbus/mq/Protocol.java +++ b/src/main/java/org/zbus/mq/Protocol.java @@ -34,14 +34,20 @@ public class Protocol { public static final String Consume = "consume"; //消费消息 public static final String Route = "route"; //请求等待应答消息 public static final String CreateMQ = "create_mq"; //创建队列 - public static final String Auth = "auth"; + public static final String Auth = "auth"; + public static final String Query = "query"; + public static final String Test = "test"; + + + public static final String Data = "data"; + public static final String Jquery = "jquery"; - public static final String Admin = "admin"; //管理类消息 public static enum MqMode { MQ, //消息队列 PubSub, //发布订阅 - Memory; //是否临时 + Memory, //是否临时 + RPC; private MqMode(){ mask = (1 << ordinal()); diff --git a/src/main/java/org/zbus/mq/server/AbstractMQ.java b/src/main/java/org/zbus/mq/server/AbstractMQ.java index 4f6a9cd3..417b0b73 100644 --- a/src/main/java/org/zbus/mq/server/AbstractMQ.java +++ b/src/main/java/org/zbus/mq/server/AbstractMQ.java @@ -32,9 +32,13 @@ import org.zbus.net.http.Message; public abstract class AbstractMQ{ protected final String name; protected String creator; + protected int mode; protected long lastUpdateTime = System.currentTimeMillis(); protected final AbstractQueue msgQ; + protected String accessToken = ""; + + protected Auth auth; public AbstractMQ(String name, AbstractQueue msgQ) { this.msgQ = msgQ; @@ -59,4 +63,26 @@ public abstract class AbstractMQ{ public abstract void cleanSession(); public abstract MqInfo getMqInfo(); + + public void setAccessToken(String accessToken){ + this.accessToken = accessToken; + this.auth = new DefaultAuth(this.accessToken); + } + + public void setAuth(Auth auth){ + this.auth = auth; + } + + public boolean auth(String appid, String token){ + if(this.auth == null) return true; + return this.auth.auth(appid, token); + } + + public int getMode() { + return mode; + } + + public void setMode(int mode) { + this.mode = mode; + } } diff --git a/src/main/java/org/zbus/mq/server/Auth.java b/src/main/java/org/zbus/mq/server/Auth.java new file mode 100644 index 00000000..5a74cd19 --- /dev/null +++ b/src/main/java/org/zbus/mq/server/Auth.java @@ -0,0 +1,16 @@ +package org.zbus.mq.server; + +public interface Auth { + boolean auth(String appid, String token); +} + +class DefaultAuth implements Auth{ + private String accessToken; + public DefaultAuth(String accessToken){ + this.accessToken = accessToken; + } + @Override + public boolean auth(String appid, String token) { + return accessToken.equals(token); + } +} diff --git a/src/main/java/org/zbus/mq/server/MQ.java b/src/main/java/org/zbus/mq/server/MQ.java index 8c46228f..04273cba 100644 --- a/src/main/java/org/zbus/mq/server/MQ.java +++ b/src/main/java/org/zbus/mq/server/MQ.java @@ -34,7 +34,6 @@ import java.util.concurrent.LinkedBlockingQueue; import org.zbus.kit.log.Logger; import org.zbus.mq.Protocol.ConsumerInfo; import org.zbus.mq.Protocol.MqInfo; -import org.zbus.mq.Protocol.MqMode; import org.zbus.net.core.Session; import org.zbus.net.http.Message; @@ -133,7 +132,7 @@ public class MQ extends AbstractMQ{ info.name = name; info.lastUpdateTime = lastUpdateTime; info.creator = creator; - info.mode = MqMode.MQ.intValue(); + info.mode = this.mode; info.unconsumedMsgCount = msgQ.size(); info.consumerCount = pullSessions.size(); info.consumerInfoList = new ArrayList(); diff --git a/src/main/java/org/zbus/mq/server/MqAdaptor.java b/src/main/java/org/zbus/mq/server/MqAdaptor.java index edd4541d..83c00d5a 100644 --- a/src/main/java/org/zbus/mq/server/MqAdaptor.java +++ b/src/main/java/org/zbus/mq/server/MqAdaptor.java @@ -34,6 +34,7 @@ public class MqAdaptor extends IoAdaptor implements Closeable { private boolean verbose = false; private final MqServer mqServer; + private String registerToken = ""; public MqAdaptor(MqServer mqServer){ @@ -41,15 +42,65 @@ public class MqAdaptor extends IoAdaptor implements Closeable { this.mqServer = mqServer; this.mqTable = mqServer.getMqTable(); this.sessionTable = mqServer.getSessionTable(); + this.registerToken = mqServer.getRegisterToken(); registerHandler(Protocol.Produce, produceHandler); registerHandler(Protocol.Consume, consumeHandler); registerHandler(Protocol.Route, routeHandler); - registerHandler(Protocol.CreateMQ, createMqHandler); - registerHandler(Protocol.Admin, new AdminHandler()); + registerHandler(Protocol.CreateMQ, createMqHandler); + registerHandler(Protocol.Test, testHandler); + registerHandler(Protocol.Query, queryHandler); + + registerHandler("", homeHandler); + registerHandler(Protocol.Data, dataHandler); + registerHandler(Protocol.Jquery, jqueryHandler); + registerHandler(Message.HEARTBEAT, heartbeatHandler); } + + private Message handleUrlMessage(Message msg){ + UrlInfo url = new UrlInfo(msg.getRequestString()); + if(url.empty){ + msg.setCmd(""); //default to home monitor + return msg; + } + + if(url.mq != null){ + if(msg.getMq() == null){ + msg.setMq(url.mq); + } + String method = url.method; + if(method == null){ + method = ""; + } + if(url.method != null || url.cmd == null){ + AbstractMQ mq = mqTable.get(url.mq); + if(mq != null && MqMode.isEnabled(mq.getMode(), MqMode.RPC)){ + msg.setMq(url.mq); + msg.setAck(false); + msg.setCmd(Protocol.Produce); + String module = url.module == null? "" : url.module; + String json = "{"; + json += "\"module\": " + "\"" + module + "\""; + json += ", \"method\": " + "\"" + method + "\""; + if(url.params != null){ + json += ", \"params\": " + "[" + url.params + "]"; + } + json += "}"; + msg.setJsonBody(json); + } + } + } + + if(url.cmd != null){ + if(msg.getCmd() == null){ + msg.setCmd(url.cmd); + } + } + + return msg; + } public void onMessage(Object obj, Session sess) throws IOException { Message msg = (Message)obj; @@ -62,14 +113,17 @@ public class MqAdaptor extends IoAdaptor implements Closeable { } String cmd = msg.getCmd(); - if(cmd == null){ //default to Admin - cmd = Protocol.Admin; - } - - MessageHandler handler = handlerMap.get(cmd); - if(handler != null){ - handler.handle(msg, sess); - return; + + if(cmd == null){ //处理URL消息格式,否则url忽略不计 + msg = handleUrlMessage(msg); + cmd = msg.getCmd(); + } + if(cmd != null){ + MessageHandler handler = handlerMap.get(cmd); + if(handler != null){ + handler.handle(msg, sess); + return; + } } Message res = new Message(); @@ -99,6 +153,11 @@ public class MqAdaptor extends IoAdaptor implements Closeable { public void handle(Message msg, Session sess) throws IOException { AbstractMQ mq = findMQ(msg, sess); if(mq == null) return; + if(!auth(mq, msg)){ + ReplyKit.reply403(msg, sess); + return; + } + boolean ack = msg.isAck(); msg.removeHead(Message.CMD); msg.removeHead(Message.ACK); @@ -116,6 +175,11 @@ public class MqAdaptor extends IoAdaptor implements Closeable { public void handle(Message msg, Session sess) throws IOException { AbstractMQ mq = findMQ(msg, sess); if(mq == null) return; + if(!auth(mq, msg)){ + ReplyKit.reply403(msg, sess); + return; + } + mq.consume(msg, sess); String mqName = sess.attr("mq"); @@ -141,13 +205,25 @@ public class MqAdaptor extends IoAdaptor implements Closeable { msg.removeHead(Message.ACK); msg.removeHead(Message.RECVER); msg.removeHead(Message.CMD); - target.write(msg); + try{ + target.write(msg); + } catch(Exception ex){ + log.warn("Target(%s) write failed, Ignore", recver); + return; //just ignore + } } }; private MessageHandler createMqHandler = new MessageHandler() { @Override public void handle(Message msg, Session sess) throws IOException { + String registerToken = msg.getHead("register_token", ""); + if(!MqAdaptor.this.registerToken.equals(registerToken)){ + msg.setBody("registerToken unmatched"); + ReplyKit.reply403(msg, sess); + return; + } + String mqName = msg.getHead("mq_name", ""); mqName = mqName.trim(); if("".equals(mqName)){ @@ -166,11 +242,12 @@ public class MqAdaptor extends IoAdaptor implements Closeable { try{ mode = Integer.valueOf(mqMode); } catch (Exception e){ - msg.setBody("mqMode invalid"); + msg.setBody("mq_mode invalid"); ReplyKit.reply400(msg, sess); return; } + String accessToken = msg.getHead("access_token", ""); AbstractMQ mq = null; synchronized (mqTable) { mq = mqTable.get(mqName); @@ -180,7 +257,8 @@ public class MqAdaptor extends IoAdaptor implements Closeable { } AbstractQueue support = null; - if(MqMode.isEnabled(mode, MqMode.Memory)){ + if(MqMode.isEnabled(mode, MqMode.Memory) || + MqMode.isEnabled(mode, MqMode.RPC)){ support = new MessageMemoryQueue(); } else { support = new MessageDiskQueue(mqName, mode); @@ -191,7 +269,10 @@ public class MqAdaptor extends IoAdaptor implements Closeable { } else { mq = new MQ(mqName, support); } + mq.setMode(mode); mq.creator = sess.getRemoteAddress(); + mq.setAccessToken(accessToken); + log.info("MQ Created: %s", mq); mqTable.put(mqName, mq); ReplyKit.reply200(msg, sess); @@ -201,6 +282,78 @@ public class MqAdaptor extends IoAdaptor implements Closeable { } }; + private MessageHandler testHandler = new MessageHandler() { + public void handle(Message msg, Session sess) throws IOException { + Message res = new Message(); + res.setResponseStatus(200); + res.setId(msg.getId()); + res.setBody("OK"); + sess.write(res); + } + }; + + private MessageHandler homeHandler = new MessageHandler() { + public void handle(Message msg, Session sess) throws IOException { + msg = new Message(); + msg.setResponseStatus("200"); + msg.setHead("content-type", "text/html"); + String body = FileKit.loadFileContent("zbus.htm"); + if ("".equals(body)) { + body = "zbus.htm file missing"; + } + msg.setBody(body); + sess.write(msg); + } + }; + + private MessageHandler jqueryHandler = new MessageHandler() { + public void handle(Message msg, Session sess) throws IOException { + msg = new Message(); + msg.setResponseStatus("200"); + msg.setHead("content-type", "application/javascript"); + String body = FileKit.loadFileContent("jquery.js"); + msg.setBody(body); + sess.write(msg); + } + }; + + private MessageHandler dataHandler = new MessageHandler() { + public void handle(Message msg, Session sess) throws IOException { + BrokerInfo info = getStatInfo(); + + Message data = new Message(); + data.setResponseStatus("200"); + data.setId(msg.getId()); + data.setHead("content-type", "application/json"); + data.setBody(JsonKit.toJson(info)); + sess.write(data); + } + }; + + private MessageHandler queryHandler = new MessageHandler() { + public void handle(Message msg, Session sess) throws IOException { + String json = ""; + if(msg.getMq() == null){ + BrokerInfo info = getStatInfo(); + json = JsonKit.toJson(info); + } else { + AbstractMQ mq = findMQ(msg, sess); + if(mq == null){ + return; + } else { + json = JsonKit.toJson(mq.getMqInfo()); + } + } + + Message data = new Message(); + data.setResponseStatus("200"); + data.setId(msg.getId()); + data.setHead("content-type", "application/json"); + data.setBody(json); + sess.write(data); + } + }; + private MessageHandler heartbeatHandler = new MessageHandler() { @Override public void handle(Message msg, Session sess) throws IOException { @@ -238,6 +391,12 @@ public class MqAdaptor extends IoAdaptor implements Closeable { super.onSessionToDestroy(sess); } + private boolean auth(AbstractMQ mq, Message msg){ + String appid = msg.getHead("appid", ""); + String token = msg.getHead("token", ""); + return mq.auth(appid, token); + } + public void setVerbose(boolean verbose) { this.verbose = verbose; } @@ -245,7 +404,9 @@ public class MqAdaptor extends IoAdaptor implements Closeable { public BrokerInfo getStatInfo(){ Map table = new HashMap(); for(Map.Entry e : this.mqTable.entrySet()){ - table.put(e.getKey(), e.getValue().getMqInfo()); + MqInfo info = e.getValue().getMqInfo(); + info.consumerInfoList.clear(); //clear to avoid long list + table.put(e.getKey(), info); } BrokerInfo info = new BrokerInfo(); info.broker = mqServer.getServerAddr(); @@ -266,10 +427,11 @@ public class MqAdaptor extends IoAdaptor implements Closeable { int flag = diskq.getFlag(); AbstractQueue queue = new MessageDiskQueue(name, diskq); if( MqMode.isEnabled(flag, MqMode.PubSub)){ - mq = new PubSub(name, queue); + mq = new PubSub(name, queue); } else { - mq = new MQ(name, queue); + mq = new MQ(name, queue); } + mq.setMode(flag); mq.lastUpdateTime = System.currentTimeMillis(); mq.creator = "System"; mqTable.put(name, mq); @@ -281,73 +443,5 @@ public class MqAdaptor extends IoAdaptor implements Closeable { public void close() throws IOException { DiskQueuePool.destory(); - } - - - private class AdminHandler implements MessageHandler { - private Map handlerMap = new ConcurrentHashMap(); - public AdminHandler() { - handlerMap.put("", homeHandler); - handlerMap.put("jquery", jqueryHandler); - handlerMap.put("data", dataHandler); - } - - public void handle(Message msg, Session sess) throws IOException { - String subCmd = msg.getSubCmd(); //from header first - if (subCmd == null){ - subCmd = msg.getRequestParam(Message.SUB_CMD); //from request Param - } - if(subCmd == null){ //default to home - subCmd = ""; - } - - MessageHandler handler = this.handlerMap.get(subCmd); - if (handler == null) { - msg.setBody("sub_cmd=%s Not Found", subCmd); - ReplyKit.reply404(msg, sess); - return; - } - handler.handle(msg, sess); - } - - private MessageHandler homeHandler = new MessageHandler() { - public void handle(Message msg, Session sess) throws IOException { - msg = new Message(); - msg.setResponseStatus("200"); - msg.setHead("content-type", "text/html"); - String body = FileKit.loadFileContent("zbus.htm"); - if ("".equals(body)) { - body = "zbus.htm file missing"; - } - msg.setBody(body); - sess.write(msg); - } - }; - - private MessageHandler jqueryHandler = new MessageHandler() { - public void handle(Message msg, Session sess) throws IOException { - msg = new Message(); - msg.setResponseStatus("200"); - msg.setHead("content-type", "application/javascript"); - String body = FileKit.loadFileContent("jquery.js"); - msg.setBody(body); - sess.write(msg); - } - }; - - private MessageHandler dataHandler = new MessageHandler() { - public void handle(Message msg, Session sess) throws IOException { - BrokerInfo info = getStatInfo(); - - Message data = new Message(); - data.setResponseStatus("200"); - data.setId(msg.getId()); - data.setHead("content-type", "application/json"); - data.setBody(JsonKit.toJson(info)); - sess.write(data); - } - }; - - } - + } } \ No newline at end of file diff --git a/src/main/java/org/zbus/mq/server/MqServer.java b/src/main/java/org/zbus/mq/server/MqServer.java index bea1be3b..aea354de 100644 --- a/src/main/java/org/zbus/mq/server/MqServer.java +++ b/src/main/java/org/zbus/mq/server/MqServer.java @@ -52,10 +52,12 @@ public class MqServer extends Server{ private long trackInterval = 5000; private MqServerConfig config; + private String registerToken = ""; public MqServer(MqServerConfig config){ this.config = config; serverName = "MqServer"; + registerToken = config.registerToken; dispatcher = new Dispatcher(); dispatcher.selectorCount(config.selectorCount); dispatcher.executorCount(config.executorCount); @@ -149,6 +151,10 @@ public class MqServer extends Server{ trackPub.pubEntryUpdate(se); } + public String getRegisterToken(){ + return registerToken; + } + public Map getMqTable() { return mqTable; } @@ -161,7 +167,7 @@ public class MqServer extends Server{ MqServerConfig config = new MqServerConfig(); config.serverHost = ConfigKit.option(args, "-h", "0.0.0.0"); config.serverPort = ConfigKit.option(args, "-p", 15555); - config.selectorCount = ConfigKit.option(args, "-selector", 1); + config.selectorCount = ConfigKit.option(args, "-selector", 0); //0 means default to CPU/4 config.executorCount = ConfigKit.option(args, "-executor", 64); config.verbose = ConfigKit.option(args, "-verbose", false); config.storePath = ConfigKit.option(args, "-store", "store"); diff --git a/src/main/java/org/zbus/mq/server/MqServerConfig.java b/src/main/java/org/zbus/mq/server/MqServerConfig.java index 833e1edd..c924e188 100644 --- a/src/main/java/org/zbus/mq/server/MqServerConfig.java +++ b/src/main/java/org/zbus/mq/server/MqServerConfig.java @@ -22,21 +22,8 @@ */ package org.zbus.mq.server; -import static org.zbus.kit.ConfigKit.value; -import static org.zbus.kit.ConfigKit.valueSet; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashSet; -import java.util.Properties; -import java.util.Set; - -import org.zbus.kit.FileKit; -import org.zbus.kit.log.Logger; - -public class MqServerConfig{ - private static final Logger log = Logger.getLogger(MqServerConfig.class); - +public class MqServerConfig{ public String trackServerList = "127.0.0.1:16666;127.0.0.1:16667"; public String serverHost = "0.0.0.0"; @@ -46,111 +33,10 @@ public class MqServerConfig{ public int selectorCount = 1; public int executorCount = 64; public boolean verbose = true; - public String storePath = "mq"; - - - public Set roles = new HashSet(); - public Set users = new HashSet(); - public Set mqs = new HashSet(); - public Set pubsubs = new HashSet(); - + public String storePath = "store"; + public String registerToken = ""; public String getServerAddress(){ return serverHost + ":" + serverPort; - } - - public void load(InputStream is) throws IOException{ - Properties props = new Properties(); - if(is == null){ - log.info("Using default settings, missing config file"); - } else { - props.load(is); - } - - this.serverHost = value(props, "zbus.serverHost", "0.0.0.0"); - this.serverPort = value(props, "zbus.serverPort", 15555); - this.selectorCount = value(props, "zbus.selectorCount", 1); - this.executorCount = value(props, "zbus.executorCount", 64); - this.verbose = value(props, "zbus.verbose", true); - this.storePath = value(props, "zbus.storePath", "mq"); - - this.roles = valueSet(props, "zbus.role"); - Set userNames = valueSet(props, "zbus.user"); - for(String name : userNames){ - User user = new User(); - user.name = name; - user.password = value(props, String.format("zbus.user.%s.password", name)); - user.roles = valueSet(props, String.format("zbus.user.%s.role", name)); - - this.users.add(user); - } - - for(String name : valueSet(props, "zbus.mq")){ - MqEntry entry = new MqEntry(); - entry.name = name; - entry.allowUsers = valueSet(props, String.format("zbus.mq.%s.allowUser", name)); - entry.allowRoles = valueSet(props, String.format("zbus.mq.%s.allowRole", name)); - - this.mqs.add(entry); - } - - for(String name : valueSet(props, "zbus.pubsub")){ - MqEntry entry = new MqEntry(); - entry.name = name; - entry.allowUsers = valueSet(props, String.format("zbus.pubsub.%s.allowUser", name)); - entry.allowRoles = valueSet(props, String.format("zbus.pubsub.%s.allowRole", name)); - - this.pubsubs.add(entry); - } - } - - public void load(String fileName) throws IOException{ - try{ - InputStream is = FileKit.loadFile(fileName); - if(is == null){ - log.info("Using default settings, missing config file"); - } else { - load(is); - } - } catch(Exception e){ - log.error(e.getMessage(), e); - } } - - public static class User { - public String name; - public String password; - public Set roles = new HashSet(); - @Override - public String toString() { - return "User [name=" + name + ", password=" + password + ", roles=" - + roles + "]"; - } - } - - public static class MqEntry { - public String name; - public Set allowUsers = new HashSet(); - public Set allowRoles = new HashSet(); - @Override - public String toString() { - return "MqEntry [name=" + name + ", allowUsers=" + allowUsers - + ", allowRoles=" + allowRoles + "]"; - } - - } - - - - public static void main(String[] args) throws Exception{ - MqServerConfig config = new MqServerConfig(); - - config.load("zbus.properties"); - - System.out.println("roles:"+config.roles); - System.out.println("users:"+config.users); - System.out.println("mqs:"+config.mqs); - System.out.println("pubsubs:"+config.pubsubs); - } - } \ No newline at end of file diff --git a/src/main/java/org/zbus/mq/server/PubSub.java b/src/main/java/org/zbus/mq/server/PubSub.java index 84ec70d3..db8eaa9c 100644 --- a/src/main/java/org/zbus/mq/server/PubSub.java +++ b/src/main/java/org/zbus/mq/server/PubSub.java @@ -33,7 +33,6 @@ import java.util.concurrent.ConcurrentMap; import org.zbus.kit.log.Logger; import org.zbus.mq.Protocol.ConsumerInfo; import org.zbus.mq.Protocol.MqInfo; -import org.zbus.mq.Protocol.MqMode; import org.zbus.net.core.Session; import org.zbus.net.http.Message; @@ -137,12 +136,14 @@ public class PubSub extends AbstractMQ{ info.name = name; info.lastUpdateTime = lastUpdateTime; info.creator = creator; - info.mode = MqMode.PubSub.intValue(); + info.mode = this.mode; + info.unconsumedMsgCount = msgQ.size(); info.consumerInfoList = new ArrayList(); for(PullSession pull : pullMap.values()){ info.consumerInfoList.add(pull.getConsumerInfo()); } + info.consumerCount = info.consumerInfoList.size(); return info; } } diff --git a/src/main/java/org/zbus/mq/server/UrlInfo.java b/src/main/java/org/zbus/mq/server/UrlInfo.java new file mode 100644 index 00000000..5888bec0 --- /dev/null +++ b/src/main/java/org/zbus/mq/server/UrlInfo.java @@ -0,0 +1,131 @@ +package org.zbus.mq.server; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class UrlInfo{ + public String cmd; + public String mq; + public String module; + public String method; + public String params; + public Map extra; + public boolean empty = false; + + public UrlInfo(String url){ + this(url, false); + } + + public UrlInfo(String url, boolean directRpc){ + if(url == null || "".equals(url)){ + empty = true; + return; + } + if(url.length() == 1 && url.charAt(0) == '/'){ + empty = true; + return; + } + try { + url = URLDecoder.decode(url, "UTF8"); + } catch (UnsupportedEncodingException e) { + return; + } + String kvs; + boolean hasKvs = url.indexOf('?') != -1; + String[] bb = url.split("[/?]+"); + if(hasKvs){ + kvs = bb[bb.length-1]; + if(!directRpc){ + if(bb.length >= 5){ + mq = bb[1]; + module = bb[2]; + method = bb[3]; + } else if(bb.length >= 4){ + mq = bb[1]; + method = bb[2]; + } else if(bb.length >= 3){ + mq = bb[1]; + } + } else { + if(bb.length >= 4){ + module = bb[1]; + method = bb[2]; + } else if(bb.length >= 3){ + method = bb[1]; + } + } + } else { + if(!directRpc){ + if(bb.length >= 4){ + mq = bb[1]; + module = bb[2]; + method = bb[3]; + } else if(bb.length >= 3){ + mq = bb[1]; + method = bb[2]; + } else if(bb.length >= 2){ + mq = bb[1]; + } + } else { + if(bb.length >= 3){ + module = bb[1]; + method = bb[2]; + } else if(bb.length >= 2){ + method = bb[1]; + } + } + return; + } + + bb = kvs.split("[&]+"); + for(String b : bb){ + if("".equals(b)) continue; + int idx = b.indexOf('='); + if(idx < 0){ + if(params == null || params.equals("")){ + params = b; + } + continue; + } + String key = b.substring(0, idx); + String val = b.substring(idx+1); + if(extra == null){ + synchronized (this) { + if(extra == null){ + extra = new ConcurrentHashMap(); + } + } + } + extra.put(key, val); + } + if(extra != null){ + if(cmd == null && extra.containsKey("cmd")){ + cmd = extra.get("cmd"); + } + if(mq == null && extra.containsKey("mq")){ + mq = extra.get("mq"); + } + if(method == null && extra.containsKey("method")){ + method = extra.get("method"); + } + if(params == null && extra.containsKey("params")){ + params = extra.get("params"); + } + } + } + + @Override + public String toString() { + return "UrlInfo [cmd=" + cmd + ", mq=" + mq + ", module=" + module + + ", method=" + method + ", params=" + params + ", extra=" + + extra + "]"; + } + + public static void main(String[] args){ + UrlInfo url = new UrlInfo("/t2/xxx?ok", true); + System.out.println(url); + } + +} diff --git a/src/main/java/org/zbus/net/Client.java b/src/main/java/org/zbus/net/Client.java index 09200f90..1c06bec4 100644 --- a/src/main/java/org/zbus/net/Client.java +++ b/src/main/java/org/zbus/net/Client.java @@ -53,9 +53,9 @@ public class Client extends IoAdaptor implements Closeable { protected Session session; protected volatile MsgHandler msgHandler; - protected ErrorHandler errorHandler; - protected ConnectedHandler connectedHandler; - protected DisconnectedHandler disconnectedHandler; + protected volatile ErrorHandler errorHandler; + protected volatile ConnectedHandler connectedHandler; + protected volatile DisconnectedHandler disconnectedHandler; public Client(String address, Dispatcher dispatcher) { String[] blocks = address.split("[:]"); @@ -167,6 +167,7 @@ public class Client extends IoAdaptor implements Closeable { @Override public void close() throws IOException { + this.onDisconnected(null); //clear disconnection handler if (this.session != null) { this.session.close(); } diff --git a/src/main/java/org/zbus/net/InvokingClient.java b/src/main/java/org/zbus/net/InvokingClient.java index 4ac54102..6b299506 100644 --- a/src/main/java/org/zbus/net/InvokingClient.java +++ b/src/main/java/org/zbus/net/InvokingClient.java @@ -90,6 +90,12 @@ public class InvokingClient return this.invokeSync(req, this.readTimeout); } + @Override + protected void onSessionDestroyed(Session sess) throws IOException { + super.onSessionDestroyed(sess); + sync.clearTicket(); + } + public RES invokeSync(REQ req, int timeout) throws IOException, InterruptedException { Ticket ticket = null; try { diff --git a/src/main/java/org/zbus/net/Server.java b/src/main/java/org/zbus/net/Server.java index 3f5c4bc7..f7848b2f 100644 --- a/src/main/java/org/zbus/net/Server.java +++ b/src/main/java/org/zbus/net/Server.java @@ -24,6 +24,7 @@ package org.zbus.net; import java.io.Closeable; import java.io.IOException; +import java.net.ServerSocket; import java.nio.channels.ServerSocketChannel; import java.util.Map; import java.util.Map.Entry; @@ -34,49 +35,49 @@ import org.zbus.kit.log.Logger; import org.zbus.net.core.Dispatcher; import org.zbus.net.core.IoAdaptor; -public class Server implements Closeable { - private static final Logger log = Logger.getLogger(Server.class); - - private static class IoAdaptorInfo { - public String adaptorName; - public String adaptorAddr; - public ServerSocketChannel serverChannel; - public IoAdaptor serverAdaptor; - } - - protected Dispatcher dispatcher; - protected String serverAddr; //第一个Server注册的地址 - protected String serverName = "Server"; - - protected Map adaptors = new ConcurrentHashMap(); - - public Server() { - } - - public Server(Dispatcher dispatcher) { - this.dispatcher = dispatcher; - } - - public Server(Dispatcher dispatcher, IoAdaptor serverAdaptor, int port) { - this(dispatcher, serverAdaptor, "0.0.0.0:" + port); - } - - public Server(Dispatcher dispatcher, IoAdaptor serverAdaptor, String address) { - this.dispatcher = dispatcher; - registerAdaptor(address, serverAdaptor); - } - - public void registerAdaptor(int port, IoAdaptor ioAdaptor) { - registerAdaptor("0.0.0.0:" + port, ioAdaptor, null); - } - - public void registerAdaptor(int port, IoAdaptor ioAdaptor, String name) { - registerAdaptor("0.0.0.0:" + port, ioAdaptor, name); - } - - public void registerAdaptor(String address, IoAdaptor ioAdaptor) { - registerAdaptor(address, ioAdaptor, null); - } +public class Server implements Closeable{ + private static final Logger log = Logger.getLogger(Server.class); + + private static class IoAdaptorInfo{ + public String adaptorName; + public String adaptorAddr; + public ServerSocketChannel serverChannel; + public IoAdaptor serverAdaptor; + } + + protected Dispatcher dispatcher; + protected String serverAddr; //第一个Server注册的地址, 当侦听启动后才有效 + protected String serverName = "Server"; + + protected Map adaptors = new ConcurrentHashMap(); + + public Server(){ + } + + public Server(Dispatcher dispatcher){ + this.dispatcher = dispatcher; + } + + public Server(Dispatcher dispatcher, IoAdaptor serverAdaptor, int port){ + this(dispatcher, serverAdaptor, "0.0.0.0:"+port); + } + + public Server(Dispatcher dispatcher, IoAdaptor serverAdaptor, String address){ + this.dispatcher = dispatcher; + registerAdaptor(address, serverAdaptor); + } + + public void registerAdaptor(int port, IoAdaptor ioAdaptor){ + registerAdaptor("0.0.0.0:"+port, ioAdaptor, null); + } + + public void registerAdaptor(int port, IoAdaptor ioAdaptor, String name){ + registerAdaptor("0.0.0.0:"+port, ioAdaptor, name); + } + + public void registerAdaptor(String address, IoAdaptor ioAdaptor){ + registerAdaptor(address, ioAdaptor, null); + } public void registerAdaptor(String address, IoAdaptor ioAdaptor, String name) { IoAdaptorInfo adaptor = new IoAdaptorInfo(); @@ -88,15 +89,10 @@ public class Server implements Closeable { adaptor.adaptorAddr = address; adaptor.serverAdaptor = ioAdaptor; - if (adaptors.isEmpty()) { - this.serverAddr = address; - String host = blocks[0]; - int port = Integer.valueOf(blocks[1]); - if ("0.0.0.0".equals(host)) { - this.serverAddr = String.format("%s:%d", NetKit.getLocalIp(), port); - } - } - + if(adaptors.isEmpty()){ //the first + this.serverAddr = address; + } + adaptors.put(address, adaptor); } @@ -109,15 +105,34 @@ public class Server implements Closeable { for (Entry e : adaptors.entrySet()) { IoAdaptorInfo adaptor = e.getValue(); if (adaptor.serverChannel != null) continue; - - adaptor.serverChannel = dispatcher.registerServerChannel(adaptor.adaptorAddr, adaptor.serverAdaptor); - String info = String.format("%s-%s listening [%s]", this.serverName, adaptor.adaptorName, adaptor.adaptorAddr); - if (adaptor.adaptorName == null) { - info = String.format("%s listening [%s]", this.serverName, adaptor.adaptorAddr); - } - log.info(info); - } - } + + String address = adaptor.adaptorAddr; + String[] bb = address.split("[:]"); + if(bb.length !=2 ) continue; + String host = bb[0]; + String port = bb[1]; + + adaptor.serverChannel = dispatcher.registerServerChannel(adaptor.adaptorAddr, adaptor.serverAdaptor); + + ServerSocket ss = adaptor.serverChannel.socket(); + if(address.equals(serverAddr)){ + String localHost = host; + if("0.0.0.0".equals(host)){ + localHost = NetKit.getLocalIp(); + } + serverAddr = String.format("%s:%d", localHost, ss.getLocalPort()); + } + if("0".equals(port)){ + adaptor.adaptorAddr = String.format("%s:%d", host, ss.getLocalPort()); + } + + String info = String.format("%s-%s listening [%s]", this.serverName, adaptor.adaptorName, adaptor.adaptorAddr); + if(adaptor.adaptorName == null){ + info = String.format("%s listening [%s]", this.serverName, adaptor.adaptorAddr); + } + log.info(info); + } + } @Override public void close() throws IOException { diff --git a/src/main/java/org/zbus/net/Sync.java b/src/main/java/org/zbus/net/Sync.java index 92ae8354..0dc060da 100644 --- a/src/main/java/org/zbus/net/Sync.java +++ b/src/main/java/org/zbus/net/Sync.java @@ -151,6 +151,13 @@ public class Sync { return tickets.remove(id); } + public void clearTicket(){ + for(Ticket ticket : tickets.values()){ + ticket.countDown(); + } + tickets.clear(); + } + public static interface Id { void setId(String id); diff --git a/src/main/java/org/zbus/net/core/Dispatcher.java b/src/main/java/org/zbus/net/core/Dispatcher.java index 9bdd41d2..2cd66c21 100644 --- a/src/main/java/org/zbus/net/core/Dispatcher.java +++ b/src/main/java/org/zbus/net/core/Dispatcher.java @@ -42,12 +42,14 @@ import org.zbus.kit.log.Logger; public class Dispatcher implements Closeable { + public static final int DEFAULT_EXECUTOR_COUNT = 64; + private static final Logger log = Logger.getLogger(Dispatcher.class); private ExecutorService executor; - private int selectorCount = 1; - private int executorCount = 32; + private int selectorCount = defaultSelectorCount(); + private int executorCount = DEFAULT_EXECUTOR_COUNT; private SelectorThread[] selectors; private AtomicInteger selectorIndex = new AtomicInteger(0); private String dispatcherName = "Dispatcher"; @@ -166,12 +168,26 @@ public class Dispatcher implements Closeable { } public Dispatcher selectorCount(int count){ - this.selectorCount = count; + if(count <= 0){ + this.selectorCount = defaultSelectorCount(); + } else { + this.selectorCount = count; + } return this; } + public static int defaultSelectorCount(){ + int c = Runtime.getRuntime().availableProcessors()/2; + if(c <= 0) c = 1; + return c; + } + public Dispatcher executorCount(int count){ - this.executorCount = count; + if(count <= 0){ + this.executorCount = DEFAULT_EXECUTOR_COUNT; + } else { + this.executorCount = count; + } return this; } diff --git a/src/main/java/org/zbus/net/core/SelectorThread.java b/src/main/java/org/zbus/net/core/SelectorThread.java index aac99b0c..1b1da25e 100644 --- a/src/main/java/org/zbus/net/core/SelectorThread.java +++ b/src/main/java/org/zbus/net/core/SelectorThread.java @@ -217,11 +217,10 @@ public class SelectorThread extends Thread { SocketChannel channel = server.accept(); channel.configureBlocking(false); - if(log.isDebugEnabled()){ - log.debug("ACCEPT: server(%s) %s=>%s", NetKit.remoteAddress(channel), NetKit.localAddress(channel)); - } - SocketAddress serverAddress = server.socket().getLocalSocketAddress(); + if(log.isDebugEnabled()){ + log.debug("ACCEPT: server(%s) %s=>%s", serverAddress, NetKit.remoteAddress(channel), NetKit.localAddress(channel)); + } IoAdaptor ioAdaptor = dispatcher.ioAdaptor(serverAddress); if(ioAdaptor == null){ diff --git a/src/main/java/org/zbus/net/http/Message.java b/src/main/java/org/zbus/net/http/Message.java index d802d434..2f590240 100644 --- a/src/main/java/org/zbus/net/http/Message.java +++ b/src/main/java/org/zbus/net/http/Message.java @@ -58,11 +58,12 @@ import org.zbus.net.core.IoBuffer; */ public class Message implements Id { private static final Logger log = Logger.getLogger(Message.class); + private static final String DEFAULT_ENCODING = "UTF-8"; + public static final String HEARTBEAT = "heartbeat"; //心跳消息 //使用到的标准HTTP头部 public static final String REMOTE_ADDR = "remote-addr"; - public static final String CONTENT_ENCODING = "content-encoding"; public static final String CONTENT_LENGTH = "content-length"; public static final String CONTENT_TYPE = "content-type"; @@ -78,6 +79,7 @@ public class Message implements Id { public static final String TOPIC = "topic"; //使用,分隔 public static final String ACK = "ack"; public static final String WINDOW = "window"; + public static final String ENCODING = "encoding"; //HTTP协议第一行(请求串或者返回状态码) @@ -89,14 +91,17 @@ public class Message implements Id { public Message(){ setBody((byte[])null); + setHead("connection", "Keep-Alive"); //since 6.3.0/6.2.8 } public Message(String body){ setBody(body); + setHead("connection", "Keep-Alive"); } public Message(byte[] body){ setBody(body); + setHead("connection", "Keep-Alive"); } public static Message copyWithoutBody(Message msg){ @@ -216,7 +221,16 @@ public class Message implements Id { } public Message setBody(String body){ - return setBody(body.getBytes()); + if (this.getBody() == null) return null; + String encoding = this.getEncoding(); + if(encoding == null){ + encoding = DEFAULT_ENCODING; + } + try { + return setBody(body.getBytes(encoding)); + } catch (UnsupportedEncodingException e) { //just ignore + return setBody(body.getBytes()); + } } public Message setBody(String format, Object ...args) { @@ -236,7 +250,11 @@ public class Message implements Id { public String getBodyString() { if (this.getBody() == null) return null; - return new String(this.getBody()); + String encoding = this.getEncoding(); + if(encoding == null){ + encoding = DEFAULT_ENCODING; + } + return getBodyString(encoding); } public String getBodyString(String encoding) { @@ -340,10 +358,10 @@ public class Message implements Id { public String getEncoding() { - return this.getHead(CONTENT_ENCODING); + return this.getHead(ENCODING); } public Message setEncoding(String encoding) { - this.setHead(CONTENT_ENCODING, encoding); + this.setHead(ENCODING, encoding); return this; } diff --git a/src/main/java/org/zbus/proxy/TcpProxyServer.java b/src/main/java/org/zbus/proxy/TcpProxyServer.java index 8bedb27a..4dcfbde1 100644 --- a/src/main/java/org/zbus/proxy/TcpProxyServer.java +++ b/src/main/java/org/zbus/proxy/TcpProxyServer.java @@ -23,9 +23,13 @@ package org.zbus.proxy; import java.io.IOException; +import java.io.InputStream; import java.nio.channels.SelectionKey; +import java.util.Properties; import org.zbus.kit.ConfigKit; +import org.zbus.kit.FileKit; +import org.zbus.kit.NetKit; import org.zbus.kit.log.Logger; import org.zbus.net.Server; import org.zbus.net.core.Dispatcher; @@ -62,14 +66,35 @@ public class TcpProxyServer extends BindingAdaptor{ dispatcher.registerSession(SelectionKey.OP_CONNECT, target); } - public static void main(String[] args) throws Exception { - int serverPort = ConfigKit.option(args, "-server", 3306); - String target = ConfigKit.option(args, "-target", "10.17.2.30:3306"); - Dispatcher dispatcher = new Dispatcher(); + public static void main(String[] args) throws Exception { + String conf = ConfigKit.option(args, "-conf", "proxy.properties"); - IoAdaptor ioAdaptor = new TcpProxyServer(target); - - final Server server = new Server(dispatcher, ioAdaptor, serverPort); + InputStream inputStream = FileKit.loadFile(conf); + if(inputStream == null){ + log.error("Missing configure file(%s)", conf); + return; + } + Properties props = new Properties(); + props.load(inputStream); + + Dispatcher dispatcher = new Dispatcher(); + final Server server = new Server(dispatcher); + for(Object key : props.keySet()){ + String sKey = (String)key; + if(!sKey.startsWith("tcp.")) continue; + String listenPort = sKey.substring(4); + int port; + try{ + port = Integer.valueOf(listenPort); + }catch(Exception ex){ + continue; + } + String target = props.getProperty(sKey); + IoAdaptor ioAdaptor = new TcpProxyServer(target); + server.registerAdaptor(port, ioAdaptor); + log.info("%s:%d====>%s", NetKit.getLocalIp(), port, target); + } + server.setServerName("TcpProxyServer"); server.start(); diff --git a/src/main/java/org/zbus/rpc/RpcFactory.java b/src/main/java/org/zbus/rpc/RpcFactory.java index 9b3db440..ea20717b 100644 --- a/src/main/java/org/zbus/rpc/RpcFactory.java +++ b/src/main/java/org/zbus/rpc/RpcFactory.java @@ -98,21 +98,15 @@ public class RpcFactory { config.setModule(val); } else if ("encoding".equals(key)) { config.setEncoding(val); - } else if ("timeout".equals(key)) { + } else if("timeout".equals(key)){ int timeout = 2500;//default - try { - timeout = Integer.valueOf(val); - } catch (Exception e) { - } + try{ timeout = Integer.valueOf(val); }catch(Exception e){} config.setTimeout(timeout); - } else if ("verbose".equals(key)) { + } else if("verbose".equals(key)){ boolean verbose = false; - try { - verbose = Boolean.valueOf(val); - } catch (Exception e) { - } + try{ verbose = Boolean.valueOf(val); }catch(Exception e){} config.setVerbose(verbose); - } + } } return config; } diff --git a/src/main/java/org/zbus/rpc/RpcInvoker.java b/src/main/java/org/zbus/rpc/RpcInvoker.java index da7f4b4c..52631e7e 100644 --- a/src/main/java/org/zbus/rpc/RpcInvoker.java +++ b/src/main/java/org/zbus/rpc/RpcInvoker.java @@ -113,6 +113,14 @@ public class RpcInvoker{ return invokeSync(this.module, method, types, args); } + public Object invokeSync(String method, Object... args) { + return invokeSync(this.module, method, null, args); + } + + public Object invokeSync(String module, String method, Object... args){ + return invokeSync(module, method, null, args); + } + public Object invokeSync(String module, String method, Class[] types, Object... args) { Request req = new Request() .module(module) diff --git a/src/main/java/org/zbus/rpc/RpcMethod.java b/src/main/java/org/zbus/rpc/RpcMethod.java new file mode 100644 index 00000000..35dac5f2 --- /dev/null +++ b/src/main/java/org/zbus/rpc/RpcMethod.java @@ -0,0 +1,37 @@ +package org.zbus.rpc; + +import java.util.ArrayList; +import java.util.List; + + +public class RpcMethod { + private List modules = new ArrayList(); + private String name; + private List paramTypes = new ArrayList(); + private String returnType; + + public List getModules() { + return modules; + } + public void setModules(List modules) { + this.modules = modules; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public List getParamTypes() { + return paramTypes; + } + public void setParamTypes(List paramTypes) { + this.paramTypes = paramTypes; + } + public String getReturnType() { + return returnType; + } + public void setReturnType(String returnType) { + this.returnType = returnType; + } +} diff --git a/src/main/java/org/zbus/rpc/RpcProcessor.java b/src/main/java/org/zbus/rpc/RpcProcessor.java index b439204e..081b5a77 100644 --- a/src/main/java/org/zbus/rpc/RpcProcessor.java +++ b/src/main/java/org/zbus/rpc/RpcProcessor.java @@ -43,6 +43,12 @@ public class RpcProcessor implements MessageProcessor{ private RpcCodec codec = new JsonRpcCodec(); private Map methods = new HashMap(); + private Map> object2Methods = new HashMap>(); + + public RpcProcessor(){ + + } + public RpcProcessor(Object... services){ addModule(services); } @@ -69,7 +75,7 @@ public class RpcProcessor implements MessageProcessor{ addModule("", obj); addModule(obj.getClass().getSimpleName(), obj); addModule(obj.getClass().getCanonicalName(), obj); - } + } } public void addModule(String module, Object... services){ @@ -78,10 +84,77 @@ public class RpcProcessor implements MessageProcessor{ } } + private void addMoudleInfo(Object service){ + String serviceKey = service.getClass().getCanonicalName(); + if(object2Methods.containsKey(serviceKey)){ + return; + } + List modules = new ArrayList(); + modules.add(""); + for(Class intf : getAllInterfaces(service.getClass())){ + modules.add(intf.getSimpleName()); + modules.add(intf.getCanonicalName()); + } + modules.add(service.getClass().getSimpleName()); + modules.add(service.getClass().getCanonicalName()); + + Method [] methods = service.getClass().getMethods(); + List rpcMethods = new ArrayList(); + object2Methods.put(serviceKey,rpcMethods); + for (Method m : methods) { + String method = m.getName(); + Remote cmd = m.getAnnotation(Remote.class); + if(cmd != null){ + method = cmd.id(); + if(cmd.exclude()) continue; + if("".equals(method)){ + method = m.getName(); + } + } + RpcMethod rpcm = new RpcMethod(); + rpcm.setModules(modules); + rpcm.setName(method); + rpcm.setReturnType(m.getReturnType().getCanonicalName()); + List paramTypes = new ArrayList(); + for(Class t : m.getParameterTypes()){ + paramTypes.add(t.getCanonicalName()); + } + rpcm.setParamTypes(paramTypes); + rpcMethods.add(rpcm); + } + } + + private void removeMoudleInfo(Object service){ + String serviceKey = service.getClass().getCanonicalName(); + object2Methods.remove(serviceKey); + } + + public void removeModule(Object... services){ + for(Object obj : services){ + for(Class intf : getAllInterfaces(obj.getClass())){ + removeModule(intf.getSimpleName(), obj); + removeModule(intf.getCanonicalName(), obj); + } + removeModule("", obj); + removeModule(obj.getClass().getSimpleName(), obj); + removeModule(obj.getClass().getCanonicalName(), obj); + } + } + + public void removeModule(String module, Object... services){ + for(Object service: services){ + this.removeCommandTable(module, service); + } + } + private void initCommandTable(String module, Object service){ + addMoudleInfo(service); + try { Method [] methods = service.getClass().getMethods(); for (Method m : methods) { + if(m.getDeclaringClass() == Object.class) continue; + String method = m.getName(); Remote cmd = m.getAnnotation(Remote.class); if(cmd != null){ @@ -117,18 +190,44 @@ public class RpcProcessor implements MessageProcessor{ } } + private void removeCommandTable(String module, Object service){ + removeMoudleInfo(service); + + try { + Method [] methods = service.getClass().getMethods(); + for (Method m : methods) { + String method = m.getName(); + Remote cmd = m.getAnnotation(Remote.class); + if(cmd != null){ + method = cmd.id(); + if(cmd.exclude()) continue; + if("".equals(method)){ + method = m.getName(); + } + } + + String paramMD5 = ""; + Class[] paramTypes = m.getParameterTypes(); + StringBuilder sb = new StringBuilder(); + for(int i=0;i[] targetParamTypes = target.method.getParameterTypes(); - Object[] invokeParams = new Object[targetParamTypes.length]; - Object[] reqParams = req.getParams(); - for(int i=0; i[] targetParamTypes = target.method.getParameterTypes(); + Object[] invokeParams = new Object[targetParamTypes.length]; + Object[] reqParams = req.getParams(); + for(int i=0; i 0) { setBroker(brokers[0]); } - mode = MqMode.intValue(MqMode.MQ, MqMode.Memory); + mode = MqMode.intValue(MqMode.MQ, MqMode.RPC); } public void setBrokers(Broker[] brokers) { diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 00000000..c47f9015 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,20 @@ + + + + + + + %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/proxy.properties b/src/main/resources/proxy.properties new file mode 100644 index 00000000..cb66b583 --- /dev/null +++ b/src/main/resources/proxy.properties @@ -0,0 +1,2 @@ +tcp.80=127.0.0.1:15555 +tcp.8080=127.0.0.1:15555 \ No newline at end of file diff --git a/src/main/resources/zbus.htm b/src/main/resources/zbus.htm index 11b4c7af..489668ce 100644 --- a/src/main/resources/zbus.htm +++ b/src/main/resources/zbus.htm @@ -2,8 +2,8 @@ -ZBUS Admin Console - +ZBUS Monitor +