├── LICENSE ├── README.md ├── doc ├── DiskQueue.md ├── MqProtocol.md ├── RpcProtocol.md └── zbus-archit.svg ├── pom.xml ├── src ├── main │ ├── java │ │ └── io │ │ │ └── zbus │ │ │ ├── auth │ │ │ ├── ApiKeyProvider.java │ │ │ ├── AuthResult.java │ │ │ ├── DefaultAuth.java │ │ │ ├── DefaultSign.java │ │ │ ├── RequestAuth.java │ │ │ ├── RequestSign.java │ │ │ └── XmlApiKeyProvider.java │ │ │ ├── kit │ │ │ ├── ClassKit.java │ │ │ ├── ConfigKit.java │ │ │ ├── CryptoKit.java │ │ │ ├── FileKit.java │ │ │ ├── HttpKit.java │ │ │ ├── JsonKit.java │ │ │ ├── NetKit.java │ │ │ └── StrKit.java │ │ │ ├── mq │ │ │ ├── MessageDispatcher.java │ │ │ ├── MessageQueueManager.java │ │ │ ├── MonitorServerAdaptor.java │ │ │ ├── MqClient.java │ │ │ ├── MqException.java │ │ │ ├── MqServer.java │ │ │ ├── MqServerAdaptor.java │ │ │ ├── MqServerConfig.java │ │ │ ├── Protocol.java │ │ │ ├── SubscriptionManager.java │ │ │ ├── db │ │ │ │ └── DbQueue.java │ │ │ ├── disk │ │ │ │ ├── DiskChannelReader.java │ │ │ │ ├── DiskQueue.java │ │ │ │ └── support │ │ │ │ │ ├── Block.java │ │ │ │ │ ├── BlockReadBuffer.java │ │ │ │ │ ├── DiskMessage.java │ │ │ │ │ ├── Index.java │ │ │ │ │ ├── MappedFile.java │ │ │ │ │ ├── QueueNak.java │ │ │ │ │ ├── QueueReader.java │ │ │ │ │ └── QueueWriter.java │ │ │ ├── memory │ │ │ │ ├── CircularArray.java │ │ │ │ ├── MemoryChannelReader.java │ │ │ │ └── MemoryQueue.java │ │ │ ├── model │ │ │ │ ├── Channel.java │ │ │ │ ├── ChannelReader.java │ │ │ │ ├── MessageQueue.java │ │ │ │ └── Subscription.java │ │ │ └── plugin │ │ │ │ ├── DefaultUrlFilter.java │ │ │ │ ├── UrlEntry.java │ │ │ │ ├── UrlFilter.java │ │ │ │ └── UrlMapping.java │ │ │ ├── rpc │ │ │ ├── MethodInvoker.java │ │ │ ├── Protocol.java │ │ │ ├── RpcAuthFilter.java │ │ │ ├── RpcClient.java │ │ │ ├── RpcException.java │ │ │ ├── RpcFilter.java │ │ │ ├── RpcMethod.java │ │ │ ├── RpcProcessor.java │ │ │ ├── RpcServer.java │ │ │ ├── RpcStartInterceptor.java │ │ │ ├── StaticResource.java │ │ │ ├── annotation │ │ │ │ ├── Auth.java │ │ │ │ ├── Param.java │ │ │ │ └── RequestMapping.java │ │ │ ├── doc │ │ │ │ └── DocRender.java │ │ │ └── server │ │ │ │ ├── HttpRpcServerAdaptor.java │ │ │ │ └── MqRpcServer.java │ │ │ └── transport │ │ │ ├── AbastractClient.java │ │ │ ├── Client.java │ │ │ ├── DataHandler.java │ │ │ ├── ErrorHandler.java │ │ │ ├── EventHandler.java │ │ │ ├── IoAdaptor.java │ │ │ ├── Message.java │ │ │ ├── MessageInterceptor.java │ │ │ ├── Server.java │ │ │ ├── ServerAdaptor.java │ │ │ ├── Session.java │ │ │ ├── Ssl.java │ │ │ ├── http │ │ │ ├── Http.java │ │ │ ├── HttpWsServer.java │ │ │ └── WebsocketClient.java │ │ │ ├── inproc │ │ │ └── InProcClient.java │ │ │ └── ipc │ │ │ └── IpcClient.java │ └── resources │ │ └── static │ │ ├── base.css │ │ ├── base.js │ │ ├── bootstrap.css │ │ ├── bootstrap.js │ │ ├── favicon.ico │ │ ├── home.htm │ │ ├── jquery-ui.js │ │ ├── jquery.js │ │ ├── logo.svg │ │ ├── rpc.htm │ │ └── zbus.min.js └── test │ ├── java │ └── io │ │ └── zbus │ │ ├── auth │ │ └── SignAuthExample.java │ │ ├── kit │ │ └── JsonKitExample.java │ │ ├── mq │ │ ├── Pub.java │ │ ├── Sub.java │ │ ├── Take.java │ │ ├── Zbus.java │ │ └── inproc │ │ │ ├── Pub.java │ │ │ └── Sub.java │ │ ├── net │ │ ├── http │ │ │ ├── HttpClient.java │ │ │ ├── HttpClientExample.java │ │ │ └── HttpServerExample.java │ │ ├── ssl │ │ │ └── SslServerExample.java │ │ └── ws │ │ │ └── WebSocketExample.java │ │ └── rpc │ │ ├── GenericService.java │ │ ├── MyRegisterInterceptor.java │ │ ├── RpcClientDirect.java │ │ ├── RpcClientInproc.java │ │ ├── RpcClientMQ.java │ │ ├── RpcServerDirectHttp.java │ │ ├── RpcServerDynamicMethod.java │ │ ├── RpcServerMQ.java │ │ ├── RpcServerMQInproc.java │ │ ├── RpcServerSpring.java │ │ ├── TestCases.java │ │ ├── WebsocketClientExample.java │ │ └── biz │ │ ├── DbExample.java │ │ ├── DbInterface.java │ │ ├── HelpTopic.java │ │ ├── InterfaceExample.java │ │ ├── InterfaceExampleImpl.java │ │ ├── MyEnum.java │ │ ├── Order.java │ │ ├── User.java │ │ ├── UserException.java │ │ ├── generic │ │ ├── GenericMethod.java │ │ └── GenericMethodImpl.java │ │ └── inheritance │ │ ├── BaseService.java │ │ ├── BaseServiceImpl.java │ │ ├── SubService1.java │ │ ├── SubService2.java │ │ ├── SubServiceInterface1.java │ │ └── SubServiceInterface2.java │ └── resources │ ├── conf │ └── zbus.xml │ ├── log4j.properties │ ├── page │ ├── style.css │ └── upload.html │ ├── rpc │ ├── auth.xml │ ├── context.xml │ ├── mapper │ │ └── db.xml │ ├── mybatis.xml │ └── mysql.xml │ └── ssl │ ├── zbus.crt │ └── zbus.key └── zbus-dist ├── bin ├── zbus.bat └── zbus.sh ├── conf ├── log4j.properties ├── ssl │ ├── zbus.crt │ └── zbus.key └── zbus.xml └── lib ├── fastjson-1.2.46.jar ├── log4j-1.2.16.jar ├── netty-all-4.1.22.Final.jar ├── slf4j-api-1.7.21.jar ├── slf4j-log4j12-1.7.21.jar └── zbus-1.0.0-SNAPSHOT.jar /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 rushmore 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | /\\\ 2 | \/\\\ 3 | \/\\\ 4 | /\\\\\\\\\\\ \/\\\ /\\\ /\\\ /\\\\\\\\\\ 5 | \///////\\\/ \/\\\\\\\\\ \/\\\ \/\\\ \/\\\////// 6 | /\\\/ \/\\\////\\\ \/\\\ \/\\\ \/\\\\\\\\\\ 7 | /\\\/ \/\\\ \/\\\ \/\\\ \/\\\ \////////\\\ 8 | /\\\\\\\\\\\ \/\\\\\\\\\ \//\\\\\\\\\ /\\\\\\\\\\ 9 | \/////////// \///////// \///////// \////////// 10 | 11 | # ZBUS = MQ + RPC 12 | zbus strives to make Message Queue and Remote Procedure Call fast, light-weighted and easy to build your own service-oriented architecture for many different platforms. Simply put, zbus = mq + rpc. 13 | 14 | zbus carefully designed on its protocol and components to embrace KISS(Keep It Simple and Stupid) principle, but in all it delivers power and elasticity. 15 | 16 | 17 | 18 | ## Features 19 | - Fast MQ of disk|memory|db, capable of unicast, multicast and broadcast messaging models 20 | - Easy RPC support out of box 21 | - HTTP/WebSocket/InProc + JSON simple format, multiple languages support 22 | - SSL + API Auth secured 23 | - Extremely light-weighted (z---bus) 24 | 25 | 26 | ## Offical Clients 27 | 28 | [zbus-js](https://github.com/rushmore/zbus-js) 29 | 30 | [zbus-python](https://github.com/rushmore/zbus-python) 31 | 32 | [zbus-java](https://github.com/rushmore/zbus) 33 | 34 | [zbus-dotnet](https://github.com/rushmore/zbus-dotnet) 35 | 36 | ## How to start zbus server 37 | In zbus-dist directory, just run zbus.bat/sh, JDK8+ required. 38 | 39 | Maven 40 | 41 | 42 | io.zbus 43 | zbus 44 | 1.0.0-SNAPSHOT 45 | 46 | 47 | ## Tutorials 48 | 49 | ### MQ Tutorial 50 | [js](https://github.com/rushmore/zbus-js) 51 | 52 | [python](https://github.com/rushmore/zbus-python) 53 | 54 | [java](https://github.com/rushmore/zbus) 55 | 56 | [dotnet](https://github.com/rushmore/zbus-dotnet) 57 | 58 | 59 | ### RPC Tutorial 60 | [js](https://github.com/rushmore/zbus-js) 61 | 62 | [python](https://github.com/rushmore/zbus-python) 63 | 64 | [java](https://github.com/rushmore/zbus) 65 | 66 | [dotnet](https://github.com/rushmore/zbus-dotnet) 67 | 68 | 69 | ## High Level Diagram 70 | 71 | ![Archit](./doc/zbus-archit.svg) 72 | 73 | ## Protocol 74 | 75 | [MQ Protocol](./doc/MqProtocol.md) 76 | 77 | [RPC Protocol](./doc/RpcProtocol.md) 78 | -------------------------------------------------------------------------------- /doc/MqProtocol.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # MQ Protocol 4 | 5 | zbus MQ protocol is pretty simple, by following HTTP format, with zbus control syntax inside of the HTTP headers. 6 | 7 | Websocket by default embbeded in the transport stack sharing same TCP port, zbus automatically detect the transport protocol. 8 | The rule is straightforward, when websocket step in, HTTP message is translated to JSON format, which is handy to stringify back to 9 | standard HTTP message. 10 | 11 | 12 | ## Common format [HTTP JSON Format] 13 | 14 | { 15 | headers: { 16 | cmd: pub|sub|create|remove|query|ping 17 | id: , 18 | apiKey: , 19 | signature: 20 | }, 21 | 22 | status: 200|400|404|403|500 ... //[required], standsfor response 23 | 24 | url: , //[optional] 25 | method: , //[optional] 26 | 27 | body: //[optional] 28 | } 29 | 30 | All requests to zbus should have id field in headers (optional), when auth required, both apiKey and signature are required. 31 | 32 | Signature generation algorithm 33 | 34 | 1) sort key ascending in request (recursively on both key and value), and generate json string 35 | 2) Init HmacSHA256 with secretKey, do encrypt on 1)'s json string to generate bytes 36 | 3) signature = Hex format in upper case on the 2)'s bytes 37 | 38 | ## Publish Message Headers 39 | 40 | Request 41 | 42 | { 43 | headers: { 44 | cmd: pub, //required 45 | mq: , //required 46 | }, 47 | body: 48 | } 49 | 50 | Response 51 | 52 | { 53 | status: 200|400|403|500...., 54 | body: 55 | } 56 | 57 | ## Subscribe Message 58 | 59 | Request 60 | 61 | { 62 | headers: { 63 | cmd: sub, //required 64 | mq: , //required 65 | channel: //required 66 | window: 67 | } 68 | } 69 | 70 | Response 71 | 72 | First message: indicates subscribe success or failure 73 | { 74 | status: 200|400|403|500, 75 | body: 76 | } 77 | 78 | Following messages: 79 | { 80 | headers: { 81 | mq: , //required 82 | channel: //required 83 | sender: 84 | id: 85 | }, 86 | body: 87 | } 88 | 89 | ## Take Message 90 | 91 | Request 92 | 93 | { 94 | headers: { 95 | cmd: take, //required 96 | mq: , //required 97 | channel: //required 98 | window: 99 | } 100 | } 101 | 102 | Response 103 | 104 | { 105 | status: 200|400|403|500|604, //604 stands for NO data 106 | body: 107 | } 108 | 109 | 110 | ## Create MQ/Channel 111 | 112 | Request 113 | 114 | { 115 | headers: { 116 | cmd: create, //required 117 | mq: , //required 118 | 119 | mqType: memory|disk|db, //default to memory 120 | mqMask: , 121 | channel: , 122 | channelMask: , 123 | offset: , 124 | checksum: 125 | topic: , 126 | } 127 | } 128 | 129 | Response 130 | 131 | { 132 | status: 200|400|403|500, 133 | body: 134 | } 135 | 136 | ## Remove MQ/Channel 137 | 138 | Request 139 | 140 | { 141 | headers: { 142 | cmd: remove, //required 143 | mq: , //required 144 | channel: 145 | } 146 | } 147 | 148 | Response 149 | 150 | { 151 | status: 200|400|403|500, 152 | body: 153 | } 154 | 155 | 156 | ## Query MQ/Channel 157 | 158 | Request 159 | 160 | { 161 | headers: { 162 | cmd: query, //required 163 | mq: , //required 164 | channel: 165 | } 166 | } 167 | 168 | Response 169 | 170 | { 171 | status: 200|400|403|500, 172 | body: 173 | } 174 | 175 | Example 176 | { 177 | body: { 178 | channels: [ ], 179 | mask: 0, 180 | name: "DiskQ", 181 | size: 200000, 182 | type: "disk" 183 | }, 184 | status: 200 185 | } 186 | -------------------------------------------------------------------------------- /doc/RpcProtocol.md: -------------------------------------------------------------------------------- 1 | 2 | # RPC Protocol 3 | 4 | ## Request 5 | 6 | { 7 | headers: { 8 | id: , 9 | apiKey: , 10 | signature: 11 | }, 12 | url: //[required] 13 | method: , //[optional] 14 | body: //[optional] 15 | } 16 | 17 | function url can be any format of HTTP URL, if no configuration, following the simple mapping rules: 18 | 19 | */${module}/${language_method_name}[/${param1}/${param2}/.....]* 20 | 21 | If body is populated in request, the params list in URL is ignored 22 | 23 | If RPC is based on MQ, add MQ prefix in url, 24 | 25 | */${mq}*/${module}/${language_method_name}[/${param1}/${param2}/.....] 26 | 27 | or, add 3 key-value pairs in headers 28 | 29 | { 30 | cmd: 'pub', 31 | mq: , //which MQ is the RPC based 32 | ack: false //No ACK from zbus for RPC 33 | } 34 | 35 | ## Response 36 | 37 | { 38 | status: 200|400|403|404|500 //required 39 | body: , 40 | id: 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/auth/ApiKeyProvider.java: -------------------------------------------------------------------------------- 1 | package io.zbus.auth; 2 | /** 3 | * apiKey and secretKey mapping provider, main functionality 4 | * 5 | * 1) query secretKey by apiKey 6 | * 2) check whether apiKey exists 7 | * 8 | * @author leiming.hong 9 | * 10 | */ 11 | public interface ApiKeyProvider { 12 | /** 13 | * Query secretKey by apiKey 14 | * 15 | * @param apiKey public key 16 | * @return private secretKey 17 | */ 18 | String secretKey(String apiKey); 19 | 20 | /** 21 | * Check whether an apiKey exists 22 | * 23 | * @param apiKey public key 24 | * @return true if exists, false otherwise 25 | */ 26 | boolean apiKeyExists(String apiKey); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/auth/AuthResult.java: -------------------------------------------------------------------------------- 1 | package io.zbus.auth; 2 | 3 | public class AuthResult { 4 | public boolean success; 5 | public String message; 6 | 7 | public AuthResult(){} 8 | public AuthResult(boolean success) { 9 | this.success = success; 10 | } 11 | 12 | public AuthResult(boolean success, String message) { 13 | this.success = success; 14 | this.message = message; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/auth/DefaultAuth.java: -------------------------------------------------------------------------------- 1 | package io.zbus.auth; 2 | 3 | import io.zbus.transport.Message; 4 | 5 | public class DefaultAuth implements RequestAuth { 6 | private ApiKeyProvider apiKeyProvider; 7 | private RequestSign requestSign = new DefaultSign(); 8 | 9 | public DefaultAuth(ApiKeyProvider apiKeyProvider) { 10 | this.apiKeyProvider = apiKeyProvider; 11 | } 12 | 13 | public void setRequestSign(RequestSign requestSign) { 14 | this.requestSign = requestSign; 15 | } 16 | 17 | @Override 18 | public AuthResult auth(Message request) { 19 | String apiKey = (String)request.getHeader(APIKEY); 20 | if(apiKey == null) return new AuthResult(false, "missing apiKey in request"); 21 | String sign = (String)request.getHeader(SIGNATURE); 22 | if(sign == null) return new AuthResult(false, "missing signature in request"); 23 | 24 | if(!apiKeyProvider.apiKeyExists(apiKey)) return new AuthResult(false, "apiKey not exists"); 25 | String secretKey = apiKeyProvider.secretKey(apiKey); 26 | if(secretKey == null) return new AuthResult(false, "secretKey not exists"); 27 | 28 | Message copy = new Message(request); 29 | copy.removeHeader(SIGNATURE); 30 | 31 | String sign2 = requestSign.calcSignature(copy, apiKey, secretKey); 32 | if(sign.equals(sign2)) { 33 | return new AuthResult(true); 34 | } else { 35 | return new AuthResult(false, "signature mismatched"); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/auth/DefaultSign.java: -------------------------------------------------------------------------------- 1 | package io.zbus.auth; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.serializer.SerializerFeature; 5 | 6 | import io.zbus.kit.CryptoKit; 7 | import io.zbus.transport.Message; 8 | 9 | public class DefaultSign implements RequestSign { 10 | 11 | public String calcSignature(Message request, String apiKey, String secret) { 12 | Message copy = new Message(request); 13 | copy.setHeader(APIKEY, apiKey); 14 | copy.removeHeader(SIGNATURE); 15 | String message = JSON.toJSONString(copy, SerializerFeature.MapSortField); //Sort map by key 16 | String sign = CryptoKit.hmacSign(message, secret); 17 | return sign; 18 | } 19 | 20 | public void sign(Message request, String apiKey, String secret) { 21 | String sign = calcSignature(request, apiKey, secret); 22 | request.setHeader(APIKEY, apiKey); 23 | request.setHeader(SIGNATURE, sign); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/auth/RequestAuth.java: -------------------------------------------------------------------------------- 1 | package io.zbus.auth; 2 | 3 | import io.zbus.transport.Message; 4 | 5 | 6 | /** 7 | * Do authentication check for request of JSON type 8 | * 9 | * @author leiming.hong 10 | * 11 | */ 12 | public interface RequestAuth { 13 | public static final String APIKEY = "apiKey"; 14 | public static final String SIGNATURE = "signature"; 15 | 16 | public static final RequestAuth ALLOW_ALL = (request)->{ return new AuthResult(true); }; 17 | public static final RequestAuth DENY_ANY = (request)->{ return new AuthResult(false); }; 18 | 19 | /** 20 | * Do authentication check for request of JSON type 21 | * 22 | * @param request JSON typed request object 23 | * @return authentication result, success set to true of false with failure message 24 | */ 25 | AuthResult auth(Message request); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/auth/RequestSign.java: -------------------------------------------------------------------------------- 1 | package io.zbus.auth; 2 | 3 | import io.zbus.transport.Message; 4 | 5 | /** 6 | * Digital signature for JSON typed request 7 | * 8 | * @author leiming.hong 9 | * 10 | */ 11 | public interface RequestSign { 12 | public static final String APIKEY = "apiKey"; 13 | public static final String SIGNATURE = "signature"; 14 | 15 | /** 16 | * Calculate digital signature value of JSON request based on apiKey and secret key 17 | * The request object remains unchanged 18 | * 19 | * @param request JSON typed request object 20 | * @param apiKey public key for signature 21 | * @param secret private key for signature 22 | * @return signed string value of request 23 | */ 24 | String calcSignature(Message request, String apiKey, String secret); 25 | 26 | /** 27 | * Calculate digital signature value of JSON request based on apiKey and secret key, and 28 | * set apiKey and signature key-value to request object, request object gets updated! 29 | * 30 | * @param request JSON typed request object 31 | * @param apiKey public key for signature 32 | * @param secret private key for signature 33 | */ 34 | void sign(Message request, String apiKey, String secret); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/auth/XmlApiKeyProvider.java: -------------------------------------------------------------------------------- 1 | package io.zbus.auth; 2 | 3 | import static io.zbus.kit.ConfigKit.valueOf; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import javax.xml.xpath.XPath; 9 | import javax.xml.xpath.XPathConstants; 10 | import javax.xml.xpath.XPathFactory; 11 | 12 | import org.w3c.dom.Document; 13 | import org.w3c.dom.Node; 14 | import org.w3c.dom.NodeList; 15 | 16 | import io.zbus.kit.ConfigKit.XmlConfig; 17 | 18 | public class XmlApiKeyProvider extends XmlConfig implements ApiKeyProvider { 19 | private Map table = new HashMap<>(); 20 | private String authXPath = "/zbus/auth"; 21 | 22 | public void setAuthXPath(String authXPath) { 23 | this.authXPath = authXPath; 24 | } 25 | 26 | public XmlApiKeyProvider() { 27 | } 28 | 29 | public XmlApiKeyProvider(String configXmlFile) { 30 | loadFromXml(configXmlFile); 31 | } 32 | 33 | @Override 34 | public void loadFromXml(Document doc) throws Exception { 35 | XPath xpath = XPathFactory.newInstance().newXPath(); 36 | NodeList list = (NodeList) xpath.compile(authXPath+"/*").evaluate(doc, XPathConstants.NODESET); 37 | if (list == null || list.getLength() <= 0) 38 | return; 39 | for (int i = 0; i < list.getLength(); i++) { 40 | Node node = list.item(i); 41 | String apiKey = valueOf(xpath.evaluate("apiKey", node), null); 42 | String secretKey = valueOf(xpath.evaluate("secretKey", node), null); 43 | if(apiKey == null || secretKey == null) continue; 44 | 45 | table.put(apiKey, secretKey); 46 | } 47 | } 48 | 49 | @Override 50 | public String secretKey(String apiKey) { 51 | return table.get(apiKey); 52 | } 53 | 54 | @Override 55 | public boolean apiKeyExists(String apiKey) { 56 | return table.containsKey(apiKey); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/kit/ClassKit.java: -------------------------------------------------------------------------------- 1 | 2 | package io.zbus.kit; 3 | 4 | import java.io.File; 5 | import java.lang.annotation.Annotation; 6 | import java.net.URL; 7 | import java.net.URLClassLoader; 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | public class ClassKit { 12 | 13 | @SuppressWarnings("unchecked") 14 | public static T newInstance(String className) throws Exception{ 15 | Class clazz = Class.forName(className); 16 | return (T)clazz.newInstance(); 17 | } 18 | 19 | 20 | public static Set> scan(Class annotation){ 21 | Set> result = new HashSet>(); 22 | ClassLoader cl = ClassLoader.getSystemClassLoader(); 23 | URL[] urls = ((URLClassLoader) cl).getURLs(); 24 | for (URL url : urls) { 25 | File root = new File(url.getFile()); 26 | list(root, root, result, annotation); 27 | } 28 | return result; 29 | } 30 | 31 | public static Set> scan(File packagePath, Class annotation){ 32 | Set> result = new HashSet>(); 33 | list(packagePath, packagePath, result, annotation); 34 | return result; 35 | } 36 | 37 | private static void list(File root, File current, Set> result, Class annotation){ 38 | File[] files = current.listFiles(); 39 | if(files == null) return; 40 | for(File file : files){ 41 | if (file.isFile()) { 42 | String fileName = file.getAbsolutePath(); 43 | if(!fileName.endsWith(".class")) continue; 44 | String className = fileName.substring(root.getAbsolutePath().length()+1, fileName.lastIndexOf('.')); 45 | className = className.replace('\\', '.'); 46 | try { 47 | Class clazz = Class.forName(className); 48 | if(annotation == null){ 49 | result.add(clazz); 50 | continue; 51 | } 52 | Annotation ann = clazz.getAnnotation(annotation); 53 | if(ann != null){ 54 | result.add(clazz); 55 | } 56 | } catch (ClassNotFoundException e) { 57 | //ignore 58 | } 59 | 60 | } else if (file.isDirectory()) { 61 | list(root, file, result, annotation); 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/kit/ConfigKit.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2009-2015 HONG LEIMING 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package io.zbus.kit; 24 | 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | import java.util.HashSet; 28 | import java.util.Properties; 29 | import java.util.Set; 30 | 31 | import javax.xml.parsers.DocumentBuilder; 32 | import javax.xml.parsers.DocumentBuilderFactory; 33 | 34 | import org.w3c.dom.Document; 35 | import org.xml.sax.InputSource; 36 | 37 | public class ConfigKit { 38 | 39 | public static String option(Properties props, String opt, String defaultValue){ 40 | String value = props.getProperty(opt, defaultValue); 41 | return value == null? null : value.trim(); 42 | } 43 | 44 | public static int option(Properties props, String opt, int defaultValue){ 45 | String value = option(props, opt, null); 46 | if(value == null) return defaultValue; 47 | return Integer.valueOf(value); 48 | } 49 | 50 | public static String option(String[] args, String opt, String defaultValue){ 51 | for(int i=0; i split(String value){ 73 | Set res = new HashSet(); 74 | String[] blocks = value.split("[,]"); 75 | for(String b : blocks){ 76 | b = b.trim(); 77 | if("".equals(b)) continue; 78 | res.add(b); 79 | } 80 | return res; 81 | } 82 | 83 | public static String value(Properties props, String name, String defaultValue){ 84 | return props.getProperty(name, defaultValue).trim(); 85 | } 86 | public static int value(Properties props, String name, int defaultValue){ 87 | String value = value(props, name, ""); 88 | if("".equals(value)) return defaultValue; 89 | return Integer.valueOf(value); 90 | } 91 | 92 | public static boolean value(Properties props, String name, boolean defaultValue){ 93 | String value = value(props, name, ""); 94 | if("".equals(value)) return defaultValue; 95 | return Boolean.valueOf(value); 96 | } 97 | public static String value(Properties props, String name){ 98 | return value(props, name, ""); 99 | } 100 | 101 | public static Set valueSet(Properties props, String name){ 102 | return split(value(props, name)); 103 | } 104 | 105 | public static String valueOf(String value, String defaultValue){ 106 | if(StrKit.isEmpty(value)) return defaultValue; 107 | return value.trim(); 108 | } 109 | 110 | public static int valueOf(String value, int defaultValue){ 111 | if(StrKit.isEmpty(value)) return defaultValue; 112 | return Integer.valueOf(value); 113 | } 114 | 115 | public static boolean valueOf(String value, boolean defaultValue){ 116 | if(StrKit.isEmpty(value)) return defaultValue; 117 | return Boolean.valueOf(value); 118 | } 119 | 120 | 121 | public static abstract class XmlConfig { 122 | 123 | public abstract void loadFromXml(Document doc) throws Exception; 124 | 125 | public void loadFromXml(InputStream stream) throws Exception { 126 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 127 | DocumentBuilder db = dbf.newDocumentBuilder(); 128 | InputSource source = new InputSource(stream); 129 | Document doc = db.parse(source); 130 | loadFromXml(doc); 131 | } 132 | 133 | public void loadFromXml(String configFile) { 134 | InputStream stream = FileKit.inputStream(configFile); 135 | if(stream == null){ 136 | throw new IllegalArgumentException(configFile + " not found"); 137 | } 138 | try { 139 | loadFromXml(stream); 140 | } catch (Exception e) { 141 | throw new IllegalArgumentException(configFile + " load error", e); 142 | } finally { 143 | if(stream != null){ 144 | try { 145 | stream.close(); 146 | } catch (IOException e) { 147 | //ignore 148 | } 149 | } 150 | } 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/kit/CryptoKit.java: -------------------------------------------------------------------------------- 1 | package io.zbus.kit; 2 | 3 | import javax.crypto.Mac; 4 | import javax.crypto.spec.SecretKeySpec; 5 | 6 | 7 | public class CryptoKit { 8 | private static final char[] DIGITS_LOWER = 9 | {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 10 | private static final char[] DIGITS_UPPER = 11 | {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 12 | 13 | public static String hmacSign(String message, String secret) { 14 | try { 15 | Mac sha256HMAC = Mac.getInstance("HmacSHA256"); 16 | SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(), "HmacSHA256"); 17 | sha256HMAC.init(secretKeySpec); 18 | return new String(encodeHex(sha256HMAC.doFinal(message.getBytes()), true)); 19 | } catch (Exception e) { 20 | throw new RuntimeException("Unable to sign message.", e); 21 | } 22 | } 23 | 24 | static char[] encodeHex(final byte[] data, final boolean toLowerCase) { 25 | return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); 26 | } 27 | 28 | static char[] encodeHex(final byte[] data, final char[] toDigits) { 29 | final int l = data.length; 30 | final char[] out = new char[l << 1]; 31 | // two characters form the hex value. 32 | for (int i = 0, j = 0; i < l; i++) { 33 | out[j++] = toDigits[(0xF0 & data[i]) >>> 4]; 34 | out[j++] = toDigits[0x0F & data[i]]; 35 | } 36 | return out; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/kit/HttpKit.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2009-2015 HONG LEIMING 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package io.zbus.kit; 24 | 25 | import java.util.ArrayList; 26 | import java.util.HashMap; 27 | import java.util.List; 28 | import java.util.Map; 29 | 30 | public class HttpKit { 31 | private final static Map MIME_TYPES = new HashMap<>(); 32 | 33 | public static class UrlInfo { 34 | public List pathList = new ArrayList(); 35 | public Map queryParamMap = new HashMap(); 36 | 37 | public String urlPath; 38 | public String queryParamString; 39 | } 40 | 41 | public static String joinPath(String... paths) { 42 | String url = "/"; 43 | for(String p : paths) { 44 | if(p == null) continue; 45 | url += "/"+p; 46 | } 47 | url = url.replaceAll("[/]+", "/"); 48 | if(url.endsWith("/") && url.length()>1) { 49 | url = url.substring(0, url.length()-1); 50 | } 51 | return url; 52 | } 53 | 54 | public static UrlInfo parseUrl(String url){ 55 | UrlInfo info = new UrlInfo(); 56 | if("/".equals(url) || StrKit.isEmpty(url)){ 57 | return info; 58 | } 59 | String path = url; 60 | String params = null; 61 | int idx = url.indexOf('?'); 62 | info.urlPath = url; 63 | if(idx >= 0){ 64 | info.urlPath = path = url.substring(0, idx); 65 | info.queryParamString = params = url.substring(idx+1); 66 | } 67 | String[] bb = path.split("/"); 68 | for(String b : bb){ 69 | if(StrKit.isEmpty(b)) continue; 70 | info.pathList.add(b); 71 | } 72 | 73 | if(params != null){ 74 | info.queryParamMap = StrKit.kvp(params, "&"); 75 | } 76 | return info; 77 | } 78 | 79 | public static String contentType(String resource){ 80 | int idx = resource.lastIndexOf('.'); 81 | if(idx < 0) { 82 | return null; 83 | } 84 | String mimeType = resource.substring(idx+1); 85 | return MIME_TYPES.get(mimeType); 86 | } 87 | 88 | static { 89 | MIME_TYPES.put("js", "application/javascript"); 90 | MIME_TYPES.put("css", "text/css"); 91 | MIME_TYPES.put("htm", "text/html"); 92 | MIME_TYPES.put("html", "text/html"); 93 | MIME_TYPES.put("svg", "image/svg+xml"); 94 | MIME_TYPES.put("gif", "image/gif"); 95 | MIME_TYPES.put("jpeg", "image/jpeg"); 96 | MIME_TYPES.put("jpg", "image/jpg"); 97 | MIME_TYPES.put("ico", "image/x-icon"); 98 | MIME_TYPES.put("png", "image/png"); 99 | MIME_TYPES.put("pdf", "application/pdf"); 100 | MIME_TYPES.put("zip", "application/zip"); 101 | MIME_TYPES.put("ttf", "application/x-font-ttf"); 102 | MIME_TYPES.put("eot", "font/opentype"); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/kit/JsonKit.java: -------------------------------------------------------------------------------- 1 | package io.zbus.kit; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import com.alibaba.fastjson.JSON; 9 | import com.alibaba.fastjson.JSONException; 10 | import com.alibaba.fastjson.JSONObject; 11 | import com.alibaba.fastjson.serializer.JSONSerializer; 12 | import com.alibaba.fastjson.serializer.SerializeWriter; 13 | import com.alibaba.fastjson.serializer.SerializerFeature; 14 | 15 | public class JsonKit { 16 | private static final String DEFAULT_ENCODING = "UTF-8"; 17 | 18 | public static Map parseObject(String jsonString) { 19 | return JSON.parseObject(jsonString); 20 | } 21 | 22 | public static Map parseObject(byte[] bytes) { 23 | String string; 24 | try { 25 | string = new String(bytes, DEFAULT_ENCODING); 26 | } catch (UnsupportedEncodingException e) { 27 | string = new String(bytes); 28 | } 29 | return JSON.parseObject(string); 30 | } 31 | 32 | public static T parseObject(byte[] bytes, Class clazz) { 33 | String string; 34 | try { 35 | string = new String(bytes, DEFAULT_ENCODING); 36 | } catch (UnsupportedEncodingException e) { 37 | string = new String(bytes); 38 | } 39 | return JSON.parseObject(string, clazz); 40 | } 41 | 42 | public static T parseObject(String jsonString, Class clazz) { 43 | try{ 44 | return JSON.parseObject(jsonString, clazz); 45 | } catch (JSONException e) { 46 | jsonString = jsonString.replace("@type", "@typeUnknown"); 47 | return JSON.parseObject(jsonString, clazz); 48 | } 49 | } 50 | 51 | @SuppressWarnings("unchecked") 52 | public static T convert(Object json, Class clazz) { 53 | if(json == null){ 54 | return null; 55 | } 56 | if(clazz.isAssignableFrom(json.getClass())){ 57 | return (T)json; 58 | } 59 | String jsonString = null; 60 | if(json instanceof String) { 61 | jsonString = (String)json; 62 | } else if (json instanceof byte[]) { 63 | return parseObject((byte[])json, clazz); 64 | } else { 65 | jsonString = JSON.toJSONString(json); 66 | } 67 | try { 68 | return parseObject(jsonString, clazz); 69 | } catch (JSONException e) { 70 | return parseObject(fixJson(jsonString), clazz); 71 | } 72 | } 73 | 74 | @SuppressWarnings("unchecked") 75 | public static List convertList(Object json, Class clazz) { 76 | List list = convert(json, List.class); 77 | List res = new ArrayList<>(); 78 | for(Object obj : list) { 79 | res.add(convert(obj, clazz)); 80 | } 81 | return res; 82 | } 83 | 84 | public static T get(JSONObject json, String key, Class clazz) { 85 | Object object = json.get(key); 86 | return convert(object, clazz); 87 | } 88 | 89 | public static String toJSONString(Object value) { 90 | return toJSONString(value,DEFAULT_ENCODING); 91 | } 92 | 93 | public static String toJSONString(Object value, String encoding) { 94 | byte[] data = toJSONBytes(value, encoding); 95 | try { 96 | return new String(data, encoding); 97 | } catch (UnsupportedEncodingException e) { 98 | return new String(data); 99 | } 100 | } 101 | 102 | public static byte[] toJSONBytes(Object value) { 103 | return toJSONBytes(value, "utf8"); 104 | } 105 | 106 | 107 | public static byte[] toJSONBytes(Object value, String encoding) { 108 | return toJSONBytes(value, encoding, 109 | SerializerFeature.DisableCircularReferenceDetect); 110 | } 111 | 112 | 113 | private static final byte[] toJSONBytes(Object object, String charsetName, 114 | SerializerFeature... features) { 115 | 116 | if(charsetName == null){ 117 | charsetName = DEFAULT_ENCODING; 118 | } 119 | 120 | SerializeWriter out = new SerializeWriter(); 121 | try { 122 | JSONSerializer serializer = new JSONSerializer(out); 123 | for (SerializerFeature feature : features) { 124 | serializer.config(feature, true); 125 | } 126 | 127 | serializer.write(object); 128 | 129 | return out.toBytes(charsetName); 130 | } finally { 131 | out.close(); 132 | } 133 | } 134 | 135 | public static String fixJson(String str){ 136 | if(!str.startsWith("{")) { 137 | str = "{" + str + "}"; 138 | } 139 | str = str.replace(" ", ""); 140 | str = str.replace(":", "':'"); 141 | str = str.replace(",", "','"); 142 | str = str.replace("{", "{'"); 143 | str = str.replace("}", "'}"); 144 | str = str.replace("[", "['"); 145 | str = str.replace("]", "']"); 146 | str = str.replace("'[", "["); 147 | str = str.replace("]'", "]"); 148 | str = str.replace("'{", "{"); 149 | str = str.replace("}'", "}"); 150 | return str; 151 | } 152 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/kit/NetKit.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2009-2015 HONG LEIMING 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package io.zbus.kit; 24 | 25 | import java.net.InetAddress; 26 | import java.net.NetworkInterface; 27 | import java.net.SocketAddress; 28 | import java.net.UnknownHostException; 29 | import java.nio.channels.SocketChannel; 30 | import java.util.Enumeration; 31 | import java.util.regex.Matcher; 32 | import java.util.regex.Pattern; 33 | 34 | public class NetKit { 35 | 36 | public static String normalizeAddress(String address) { 37 | String[] blocks = address.split("[:]"); 38 | if (blocks.length > 2) { 39 | throw new IllegalArgumentException(address + " is invalid"); 40 | } 41 | String host = blocks[0]; 42 | int port = 80; 43 | if (blocks.length > 1) { 44 | port = Integer.valueOf(blocks[1]); 45 | } else { 46 | address += ":" + port; // use default 80 47 | } 48 | String serverAddr = String.format("%s:%d", host, port); 49 | return serverAddr; 50 | } 51 | 52 | public static String getLocalAddress(String address) { 53 | String[] blocks = address.split("[:]"); 54 | if (blocks.length != 2) { 55 | throw new IllegalArgumentException(address + " is invalid address"); 56 | } 57 | String host = blocks[0]; 58 | int port = Integer.valueOf(blocks[1]); 59 | 60 | if ("0.0.0.0".equals(host)) { 61 | return String.format("%s:%d", NetKit.getLocalIp(), port); 62 | } 63 | return address; 64 | } 65 | 66 | public static boolean isPublicAddress(String ip){ 67 | if (ip.startsWith("127.") || ip.startsWith("10.") || ip.startsWith("172.") || ip.startsWith("192.")) { 68 | return false; 69 | } 70 | return true; 71 | } 72 | 73 | private static int matchedIndex(String ip, String[] prefix) { 74 | for (int i = 0; i < prefix.length; i++) { 75 | String p = prefix[i]; 76 | if ("*".equals(p)) { 77 | if (!isPublicAddress(ip)) { 78 | continue; 79 | } 80 | return i; 81 | } else { 82 | if (ip.startsWith(p)) { 83 | return i; 84 | } 85 | } 86 | } 87 | 88 | return -1; 89 | } 90 | 91 | public static String getLocalIp(String ipPreference) { 92 | if (ipPreference == null || "".equals(ipPreference.trim())) { 93 | ipPreference = "*>10>172>192>127"; 94 | } 95 | String[] prefix = ipPreference.split("[> ]+"); 96 | try { 97 | Pattern pattern = Pattern.compile("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"); 98 | Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); 99 | String matchedIp = null; 100 | int matchedIdx = -1; 101 | while (interfaces.hasMoreElements()) { 102 | NetworkInterface ni = interfaces.nextElement(); 103 | Enumeration en = ni.getInetAddresses(); 104 | while (en.hasMoreElements()) { 105 | InetAddress addr = en.nextElement(); 106 | String ip = addr.getHostAddress(); 107 | Matcher matcher = pattern.matcher(ip); 108 | if (matcher.matches()) { 109 | int idx = matchedIndex(ip, prefix); 110 | if (idx == -1) 111 | continue; 112 | if (matchedIdx == -1) { 113 | matchedIdx = idx; 114 | matchedIp = ip; 115 | } else { 116 | if (matchedIdx > idx) { 117 | matchedIdx = idx; 118 | matchedIp = ip; 119 | } 120 | } 121 | } 122 | } 123 | } 124 | if (matchedIp != null) 125 | return matchedIp; 126 | return "127.0.0.1"; 127 | } catch (Throwable e) { 128 | return "127.0.0.1"; 129 | } 130 | } 131 | 132 | public static String getLocalIp() { 133 | try { 134 | return InetAddress.getLocalHost().getHostAddress().toString(); 135 | } catch (UnknownHostException e) { 136 | return getLocalIp("*>10>172>192>127"); 137 | } 138 | } 139 | 140 | public static String remoteAddress(SocketChannel channel) { 141 | SocketAddress addr = channel.socket().getRemoteSocketAddress(); 142 | String res = String.format("%s", addr); 143 | return res; 144 | } 145 | 146 | public static String localAddress(SocketChannel channel) { 147 | SocketAddress addr = channel.socket().getLocalSocketAddress(); 148 | String res = String.format("%s", addr); 149 | return addr == null ? res : res.substring(1); 150 | } 151 | 152 | public static Object[] hostPort(String address){ 153 | return hostPort(address, 80); 154 | } 155 | public static Object[] hostPort(String address, int defaultPort){ 156 | Object[] res = new Object[2]; 157 | String[] bb = address.split("[:]",2); 158 | if(bb.length > 0){ 159 | res[0] = bb[0].trim(); 160 | } 161 | res[1] = defaultPort; 162 | if(bb.length>1){ 163 | res[1] = Integer.valueOf(bb[1]); 164 | } 165 | return res; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/kit/StrKit.java: -------------------------------------------------------------------------------- 1 | package io.zbus.kit; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.UUID; 6 | 7 | public class StrKit { 8 | 9 | public static String uuid(){ 10 | return UUID.randomUUID().toString(); 11 | } 12 | 13 | public static boolean isEmpty(String str) { 14 | return str == null || str.trim().equals(""); 15 | } 16 | 17 | public static Map kvp(String value){ 18 | return StrKit.kvp(value, "&"); 19 | } 20 | 21 | public static Map kvp(String value, String delim){ 22 | if(isEmpty(delim)) { 23 | delim = "[ ;]"; 24 | } 25 | 26 | Map res = new HashMap(); 27 | if(isEmpty(value)) return res; 28 | 29 | 30 | String[] kvs = value.split(delim); 31 | for(String kv : kvs){ 32 | kv = kv.trim(); 33 | if(kv.equals("")) continue; 34 | String[] bb = kv.split("="); 35 | String k="",v=""; 36 | if(bb.length > 0){ 37 | k = bb[0].trim(); 38 | } 39 | if(bb.length > 1){ 40 | v = bb[1].trim(); 41 | } 42 | res.put(k, v); 43 | } 44 | return res; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/MessageDispatcher.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq; 2 | 3 | import java.io.IOException; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | import java.util.concurrent.ExecutorService; 9 | import java.util.concurrent.Executors; 10 | 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import io.zbus.mq.model.MessageQueue; 15 | import io.zbus.mq.model.Subscription; 16 | import io.zbus.transport.Message; 17 | import io.zbus.transport.Session; 18 | 19 | public class MessageDispatcher { 20 | private static final Logger logger = LoggerFactory.getLogger(MessageDispatcher.class); 21 | 22 | private SubscriptionManager subscriptionManager; 23 | private Map sessionTable; 24 | private Map loadbalanceTable = new ConcurrentHashMap(); // channel => index 25 | 26 | //private int batchReadSize = 10; 27 | private ExecutorService dispatchRunner = Executors.newFixedThreadPool(64); 28 | 29 | public MessageDispatcher(SubscriptionManager subscriptionManager, Map sessionTable) { 30 | this.subscriptionManager = subscriptionManager; 31 | this.sessionTable = sessionTable; 32 | } 33 | 34 | public void dispatch(MessageQueue mq, String channel) { 35 | dispatchRunner.submit(() -> { 36 | dispatch0(mq, channel); 37 | }); 38 | } 39 | 40 | protected void dispatch0(MessageQueue mq, String channel) { 41 | List subs = subscriptionManager.getSubscriptionList(mq.name(), channel); 42 | if (subs == null || subs.size() == 0) 43 | return; 44 | 45 | synchronized (subs) { 46 | Long index = loadbalanceTable.get(channel); 47 | if (index == null) { 48 | index = 0L; 49 | } 50 | 51 | while(true) { 52 | Message message = null; 53 | int N = subs.size(); 54 | long max = index + N; 55 | if(max < 0) { 56 | index = 0L; 57 | max = index + N; 58 | } 59 | boolean windowOpen = false; 60 | while (index < max) { 61 | Subscription sub = subs.get((int) (index % N)); 62 | 63 | if(sub.window != null && sub.window <= 0) { 64 | loadbalanceTable.put(channel, ++index); 65 | continue; 66 | } 67 | windowOpen = true; 68 | 69 | if(message == null) { 70 | try { 71 | message = mq.read(channel); 72 | } catch (IOException e) { 73 | logger.error(e.getMessage(), e); 74 | break; 75 | } 76 | } 77 | if(message == null) return; 78 | 79 | loadbalanceTable.put(channel, ++index); 80 | String filter = (String) message.getHeader(Protocol.TAG); 81 | if (sub.filters.isEmpty() || sub.filters.contains(filter)) { 82 | Session sess = sessionTable.get(sub.clientId); 83 | if (sess == null) continue; 84 | 85 | message.setHeader(Protocol.CHANNEL, channel); 86 | if(sub.window != null) { 87 | message.setHeader(Protocol.WINDOW, --sub.window); 88 | } 89 | sess.write(message); 90 | message = null; 91 | } 92 | } 93 | if(!windowOpen) break; 94 | } 95 | } 96 | } 97 | 98 | public void dispatch(MessageQueue mq) { 99 | Iterator iter = mq.channelIterator(); 100 | while(iter.hasNext()) { 101 | String channel = iter.next(); 102 | dispatch(mq, channel); 103 | } 104 | } 105 | 106 | public void take(MessageQueue mq, String channel, int count, String reqMsgId, Session sess) throws IOException { 107 | List data = mq.read(channel, count); 108 | Message message = new Message(); 109 | int status = data.size()>0? 200 : 604;//Special status code, no DATA 110 | message.setStatus(status); 111 | message.setHeader(Protocol.ID, reqMsgId); 112 | message.setHeader(Protocol.MQ, mq.name()); 113 | message.setHeader(Protocol.CHANNEL, channel); 114 | message.setBody(data); 115 | 116 | 117 | sess.write(message); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/MessageQueueManager.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq; 2 | 3 | import java.io.File; 4 | import java.io.FileFilter; 5 | import java.io.IOException; 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import io.zbus.mq.db.DbQueue; 13 | import io.zbus.mq.disk.DiskQueue; 14 | import io.zbus.mq.memory.MemoryQueue; 15 | import io.zbus.mq.model.Channel; 16 | import io.zbus.mq.model.MessageQueue; 17 | 18 | public class MessageQueueManager { 19 | private static final Logger logger = LoggerFactory.getLogger(MessageQueueManager.class); 20 | public String mqDir = "/tmp/zbus"; 21 | public String dbConnectionString; 22 | 23 | private Map mqTable = new ConcurrentHashMap<>(); 24 | 25 | public void loadQueueTable() { 26 | logger.info("Loading MQ from disk ..."); 27 | File[] mqDirs = new File(this.mqDir).listFiles(new FileFilter() { 28 | @Override 29 | public boolean accept(File pathname) { 30 | return pathname.isDirectory(); 31 | } 32 | }); 33 | 34 | if (mqDirs != null && mqDirs.length > 0) { 35 | for (File dir : mqDirs) { 36 | try { 37 | MessageQueue mq = new DiskQueue(dir.getName(), new File(this.mqDir)); 38 | mqTable.put(dir.getName(), mq); 39 | logger.info("MQ({}) loaded", dir.getName()); 40 | } catch (IOException e) { 41 | logger.error(e.getMessage(), e); 42 | continue; 43 | } 44 | } 45 | } 46 | } 47 | 48 | public MessageQueue get(String mqName) { 49 | if(mqName == null) mqName = ""; 50 | return mqTable.get(mqName); 51 | } 52 | 53 | public MessageQueue saveQueue(String mqName, String channel) throws IOException { 54 | return saveQueue(mqName, Protocol.MEMORY, null, channel, null, null); 55 | } 56 | 57 | /** 58 | * 59 | * Create MQ or Channel of MQ 60 | * 61 | * @param mqName name of message queue 62 | * @param mqType type of mq 63 | * @param channel channel name of mq 64 | * @return created/updated mq 65 | * @throws IOException 66 | */ 67 | public MessageQueue saveQueue( 68 | String mqName, String mqType, Integer mqMask, 69 | String channel, Long channelOffset, Integer channelMask) throws IOException { 70 | 71 | if(mqName == null) { 72 | throw new IllegalArgumentException("Missing mqName"); 73 | } 74 | if(mqType == null) { 75 | mqType = Protocol.MEMORY; 76 | } 77 | 78 | MessageQueue mq = mqTable.get(mqName); 79 | if(mq == null) { 80 | if(Protocol.MEMORY.equals(mqType)) { 81 | mq = new MemoryQueue(mqName); 82 | } else if (Protocol.DISK.equals(mqType)) { 83 | mq = new DiskQueue(mqName, new File(mqDir)); 84 | } else if(Protocol.DB.equals(mqName)) { 85 | mq = new DbQueue(mqName); 86 | } else { 87 | throw new IllegalArgumentException("mqType(" + mqType + ") Not Support"); 88 | } 89 | mqTable.put(mqName, mq); 90 | } 91 | 92 | mq.setMask(mqMask); 93 | 94 | if(channel != null) { 95 | Channel ch = new Channel(channel, channelOffset); 96 | ch.mask = channelMask; 97 | mq.saveChannel(ch); 98 | } 99 | 100 | return mq; 101 | } 102 | 103 | /** 104 | * Remove MQ or Channel of MQ 105 | * 106 | * @param mq name of mq 107 | * @param channel channel of mq 108 | */ 109 | public void removeQueue(String mq, String channel) throws IOException { 110 | if(channel == null) { 111 | MessageQueue q = mqTable.remove(mq); 112 | if(q != null) { 113 | q.destroy(); 114 | } 115 | return; 116 | } 117 | 118 | MessageQueue q = mqTable.get(mq); 119 | if(q != null) { 120 | q.removeChannel(channel); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/MonitorServerAdaptor.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq; 2 | 3 | import io.zbus.kit.FileKit; 4 | import io.zbus.rpc.RpcAuthFilter; 5 | import io.zbus.rpc.RpcProcessor; 6 | import io.zbus.rpc.StaticResource; 7 | import io.zbus.rpc.annotation.RequestMapping; 8 | import io.zbus.rpc.server.HttpRpcServerAdaptor; 9 | import io.zbus.transport.Message; 10 | 11 | public class MonitorServerAdaptor extends HttpRpcServerAdaptor { 12 | public MonitorServerAdaptor(MqServerConfig config) { 13 | super(new RpcProcessor()); 14 | if(config.monitorServer != null && config.monitorServer.auth != null) { 15 | RpcAuthFilter authFilter = new RpcAuthFilter(config.monitorServer.auth); 16 | processor.setAuthFilter(authFilter); 17 | } 18 | processor.mount("", new MonitorService()); 19 | StaticResource staticResource = new StaticResource(); 20 | staticResource.setCacheEnabled(false); //TODO turn if off in production 21 | processor.mount("static", staticResource, false); 22 | } 23 | } 24 | 25 | 26 | class MonitorService { 27 | private FileKit fileKit = new FileKit(); 28 | 29 | @RequestMapping("/") 30 | public Message home() { 31 | return fileKit.loadResource("static/home.htm"); 32 | } 33 | 34 | @RequestMapping(path="/favicon.ico", docEnabled=false) 35 | public Message favicon() { 36 | return fileKit.loadResource("static/favicon.ico"); 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/MqClient.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import io.zbus.kit.JsonKit; 11 | import io.zbus.transport.Client; 12 | import io.zbus.transport.DataHandler; 13 | import io.zbus.transport.Message; 14 | 15 | public class MqClient extends Client{ 16 | private static final Logger logger = LoggerFactory.getLogger(MqClient.class); 17 | 18 | private List handlers = new ArrayList<>(); 19 | 20 | public static class MqHandler{ 21 | public String mq; 22 | public String channel; 23 | public Integer window; 24 | public DataHandler handler; 25 | } 26 | 27 | public MqClient(String address) { 28 | super(address); 29 | onMessage(msg->{ 30 | handleMessage(msg); 31 | }); 32 | } 33 | 34 | public MqClient(MqServer server) { 35 | super(server.getServerAdaptor()); 36 | onMessage(msg->{ 37 | handleMessage(msg); 38 | }); 39 | } 40 | 41 | private void handleMessage(Message response) throws Exception { 42 | boolean handled = handleInvokeResponse(response); 43 | if(handled) return; 44 | 45 | //Subscribed message pushing 46 | String mq = (String)response.getHeader(Protocol.MQ); 47 | String channel = (String)response.getHeader(Protocol.CHANNEL); 48 | if(mq == null || channel == null) { 49 | logger.warn("MQ/Channel both required in reponse: " + JsonKit.toJSONString(response)); 50 | return; 51 | } 52 | MqHandler mqHandler = getHandler(mq, channel); 53 | if(mqHandler == null) { 54 | logger.warn(String.format("Missing handler for mq=%s,channel=%s",mq, channel)); 55 | return; 56 | } 57 | try { 58 | mqHandler.handler.handle(response); 59 | } catch (Exception e) { 60 | logger.error(e.getMessage(), e); 61 | } 62 | //increase window if required 63 | Integer window = response.getHeaderInt(Protocol.WINDOW); 64 | if(window != null) { 65 | if(window <= mqHandler.window/2) { 66 | try { 67 | Message sub = new Message(); 68 | sub.setHeader(Protocol.CMD, Protocol.SUB); 69 | sub.setHeader(Protocol.MQ, mq); 70 | sub.setHeader(Protocol.CHANNEL, channel); 71 | sub.setHeader(Protocol.WINDOW, mqHandler.window); 72 | sub.setHeader(Protocol.ACK, false); 73 | 74 | this.sendMessage(sub); 75 | } catch (Exception e) { 76 | logger.error(e.getMessage(), e); 77 | } 78 | } 79 | } 80 | } 81 | 82 | public synchronized void heartbeat(long interval, TimeUnit timeUnit) { 83 | heartbeat(interval, timeUnit, ()->{ 84 | Message msg = new Message(); 85 | msg.setHeader(Protocol.CMD, Protocol.PING); 86 | return msg; 87 | }); 88 | } 89 | 90 | private MqHandler getHandler(String mq, String channel) { 91 | for(MqHandler handler : handlers) { 92 | if(mq.equals(handler.mq) && channel.equals(handler.channel)) { 93 | return handler; 94 | } 95 | } 96 | return null; 97 | } 98 | 99 | public void addMqHandler(String mq, String channel, DataHandler dataHandler) { 100 | addMqHandler(mq, channel, 1, dataHandler); 101 | } 102 | 103 | public void addMqHandler(String mq, String channel, Integer window, DataHandler dataHandler) { 104 | for(MqHandler handler : handlers) { 105 | if(mq.equals(handler.mq) && channel.equals(handler.channel)) { 106 | handler.window = window; 107 | handler.handler = dataHandler; 108 | return; 109 | } 110 | } 111 | 112 | MqHandler mqHandler = new MqHandler(); 113 | mqHandler.mq = mq; 114 | mqHandler.channel = channel; 115 | mqHandler.window = window; 116 | mqHandler.handler = dataHandler; 117 | 118 | handlers.add(mqHandler); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/MqException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2009-2015 HONG LEIMING 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package io.zbus.mq; 24 | 25 | 26 | public class MqException extends RuntimeException { 27 | private static final long serialVersionUID = -5389901914827020159L; 28 | 29 | public MqException(String message) { 30 | super(message); 31 | } 32 | 33 | public MqException() { 34 | } 35 | 36 | public MqException(String message, Throwable cause) { 37 | super(message, cause); 38 | } 39 | 40 | public MqException(Throwable cause) { 41 | super(cause); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/MqServer.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq; 2 | 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import io.netty.handler.ssl.SslContext; 8 | import io.zbus.kit.ConfigKit; 9 | import io.zbus.mq.MqServerConfig.ServerConfig; 10 | import io.zbus.transport.Ssl; 11 | import io.zbus.transport.http.HttpWsServer; 12 | 13 | public class MqServer extends HttpWsServer { 14 | private static final Logger logger = LoggerFactory.getLogger(MqServer.class); 15 | 16 | private ServerConfig publicServerConfig; 17 | private ServerConfig privateServerConfig; 18 | private ServerConfig monitorServerConfig; 19 | 20 | private MqServerAdaptor publicServerAdaptor; 21 | private MqServerAdaptor privateServerAdaptor; 22 | private MonitorServerAdaptor monitorServerAdaptor; 23 | 24 | private final MqServerConfig config; 25 | 26 | public MqServer(MqServerConfig config) { 27 | this.config = config; 28 | this.maxSocketCount = config.maxSocketCount; 29 | 30 | publicServerConfig = config.publicServer; 31 | if(publicServerConfig != null) { 32 | publicServerAdaptor = new MqServerAdaptor(this.config); 33 | if(publicServerConfig.auth != null) { 34 | publicServerAdaptor.setRequestAuth(publicServerConfig.auth); 35 | } 36 | } 37 | 38 | privateServerConfig = config.privateServer; 39 | if(privateServerConfig != null) { 40 | if(publicServerAdaptor != null) { 41 | privateServerAdaptor = publicServerAdaptor.duplicate(); //share internal state 42 | } else { 43 | privateServerAdaptor = new MqServerAdaptor(this.config); 44 | } 45 | privateServerAdaptor.setRequestAuth(null);//clear auth by default 46 | if(privateServerConfig.auth != null) { 47 | privateServerAdaptor.setRequestAuth(privateServerConfig.auth); 48 | } 49 | } 50 | 51 | monitorServerConfig = config.monitorServer; 52 | if(monitorServerConfig != null) { 53 | monitorServerAdaptor = new MonitorServerAdaptor(this.config); 54 | } 55 | } 56 | public MqServer(String configFile){ 57 | this(new MqServerConfig(configFile)); 58 | } 59 | 60 | public MqServerAdaptor getServerAdaptor() { 61 | return publicServerAdaptor; 62 | } 63 | 64 | public void start() { 65 | if(publicServerAdaptor != null) { 66 | SslContext sslContext = null; 67 | if (publicServerConfig.sslEnabled){ 68 | try{ 69 | sslContext = Ssl.buildServerSsl(publicServerConfig.sslCertFile, publicServerConfig.sslKeyFile); 70 | } catch (Exception e) { 71 | logger.error("SSL init error: " + e.getMessage()); 72 | throw new IllegalStateException(e.getMessage(), e.getCause()); 73 | } 74 | } 75 | logger.info("Starting public server @" + publicServerConfig.address); 76 | this.start(publicServerConfig.address, publicServerAdaptor, sslContext); 77 | } 78 | 79 | if(privateServerAdaptor != null) { 80 | SslContext sslContext = null; 81 | if (privateServerConfig.sslEnabled){ 82 | try{ 83 | sslContext = Ssl.buildServerSsl(privateServerConfig.sslCertFile, privateServerConfig.sslKeyFile); 84 | } catch (Exception e) { 85 | logger.error("SSL init error: " + e.getMessage()); 86 | throw new IllegalStateException(e.getMessage(), e.getCause()); 87 | } 88 | } 89 | logger.info("Starting private server @" + privateServerConfig.address); 90 | this.start(privateServerConfig.address, privateServerAdaptor, sslContext); 91 | } 92 | 93 | if(monitorServerAdaptor != null) { 94 | SslContext sslContext = null; 95 | if (monitorServerConfig.sslEnabled){ 96 | try{ 97 | sslContext = Ssl.buildServerSsl(monitorServerConfig.sslCertFile, monitorServerConfig.sslKeyFile); 98 | } catch (Exception e) { 99 | logger.error("SSL init error: " + e.getMessage()); 100 | throw new IllegalStateException(e.getMessage(), e.getCause()); 101 | } 102 | } 103 | logger.info("Starting mointor server @" + monitorServerConfig.address); 104 | this.start(monitorServerConfig.address, monitorServerAdaptor, sslContext); 105 | } 106 | } 107 | 108 | 109 | public static void main(String[] args) { 110 | String configFile = ConfigKit.option(args, "-conf", "conf/zbus.xml"); 111 | 112 | final MqServer server; 113 | try{ 114 | server = new MqServer(configFile); 115 | server.start(); 116 | } catch (Exception e) { 117 | e.printStackTrace(System.err); 118 | logger.warn(e.getMessage(), e); 119 | return; 120 | } 121 | 122 | Runtime.getRuntime().addShutdownHook(new Thread(){ 123 | public void run() { 124 | try { 125 | server.close(); 126 | logger.info("MqServer shutdown completed"); 127 | } catch (Exception e) { 128 | logger.error(e.getMessage(), e); 129 | } 130 | } 131 | }); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/Protocol.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq; 2 | 3 | import java.util.List; 4 | 5 | public interface Protocol { 6 | //Parameter keys(Message main key-value pairs) 7 | public static final String CMD = "cmd"; // Request message command 8 | public static final String STATUS = "status"; // Response message status 9 | public static final String ID = "id"; // Message ID 10 | public static final String BODY = "body"; // Message body 11 | public static final String API_KEY = "apiKey"; // Authentication public Key 12 | public static final String SIGNATURE = "signature"; // Authentication signature generated 13 | 14 | //Command values(key=cmd) 15 | public static final String PUB = "pub"; //Publish message 16 | public static final String SUB = "sub"; //Subscribe message stream 17 | public static final String TAKE = "take"; //One-time read message from MQ 18 | public static final String ROUTE = "route"; //Route message to specified sender client 19 | public static final String CREATE = "create"; //Create or Update 20 | public static final String REMOVE = "remove"; //Remove MQ/Channel 21 | public static final String QUERY = "query"; //Query MQ/Channel 22 | public static final String BIND = "bind"; //Bind URL mapping to MQ message(Make browser friendly) 23 | public static final String PING = "ping"; //Heartbeat ping 24 | 25 | //Parameter keys(for commands) 26 | public static final String MQ = "mq"; 27 | public static final String CHANNEL = "channel"; 28 | public static final String FILTER = "filter"; //Filter on message's tag 29 | public static final String TAG = "tag"; //Tag of message, if filter applied 30 | public static final String OFFSET = "offset"; 31 | public static final String CHECKSUM = "checksum"; //Offset checksum 32 | public static final String SOURCE = "source"; //message's source id(socket) 33 | public static final String TARGET = "target"; //route message's target id(socket) 34 | public static final String MQ_TYPE = "mqType"; 35 | public static final String MQ_MASK = "mqMask"; 36 | public static final String CHANNEL_MASK = "channelMask"; 37 | public static final String WINDOW = "window"; 38 | public static final String ACK = "ack"; 39 | public static final String CLEAR_BIND = "clearBind"; 40 | 41 | //Parameter mqType values 42 | public static final String MEMORY = "memory"; 43 | public static final String DISK = "disk"; 44 | public static final String DB = "db"; 45 | 46 | public static class MqInfo { 47 | public String name; 48 | public Integer mask; 49 | public long size; 50 | public String type; 51 | public List channels; 52 | } 53 | 54 | public static class ChannelInfo { 55 | public String name; 56 | public Integer mask; 57 | public String filter; 58 | public long offset; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/SubscriptionManager.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Map.Entry; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | import io.zbus.mq.model.Subscription; 11 | 12 | public class SubscriptionManager { 13 | private Map clientId2Subscription = new ConcurrentHashMap<>(); 14 | private Map> channel2Subscription = new ConcurrentHashMap<>(); 15 | 16 | public synchronized Subscription get(String clientId) { 17 | return clientId2Subscription.get(clientId); 18 | } 19 | 20 | public synchronized void add(Subscription subscription) { 21 | clientId2Subscription.put(subscription.clientId, subscription); 22 | String channelKey = key(subscription.mq, subscription.channel); 23 | List subs = channel2Subscription.get(channelKey); 24 | if(subs == null) { 25 | subs = new ArrayList<>(); 26 | channel2Subscription.put(channelKey, subs); 27 | } 28 | subs.add(subscription); 29 | } 30 | 31 | 32 | public synchronized List getSubscriptionList(String mq, String channel){ 33 | String channelKey = key(mq, channel); 34 | return channel2Subscription.get(channelKey); 35 | } 36 | 37 | public synchronized void removeByClientId(String clientId) { 38 | Subscription sub = clientId2Subscription.remove(clientId); 39 | if(sub == null) return; 40 | for(List subs : channel2Subscription.values()) { 41 | subs.remove(sub); 42 | } 43 | } 44 | 45 | public synchronized void removeByChannel(String mq, String channel) { 46 | String channelKey = key(mq, channel); 47 | List subs = channel2Subscription.remove(channelKey); 48 | if(subs == null) return; 49 | 50 | for(Subscription sub : subs) { 51 | clientId2Subscription.remove(sub.clientId); 52 | } 53 | } 54 | 55 | 56 | public synchronized void removeByMq(String mq) { 57 | Iterator> iter = clientId2Subscription.entrySet().iterator(); 58 | while(iter.hasNext()) { 59 | Entry entry = iter.next(); 60 | if(mq.equals(entry.getValue().mq)) { 61 | iter.remove(); 62 | } 63 | } 64 | 65 | Iterator>> it = channel2Subscription.entrySet().iterator(); 66 | while(it.hasNext()) { 67 | Entry> entry = it.next(); 68 | for(Subscription sub : entry.getValue()) { 69 | if(mq.equals(sub.mq)) { 70 | it.remove(); 71 | break; 72 | } 73 | } 74 | } 75 | } 76 | 77 | private String key(String mq, String channel) { 78 | if(mq == null) mq = ""; 79 | if(channel == null) channel = ""; 80 | String channelKey = mq + "." + channel; 81 | return channelKey; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/db/DbQueue.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.db; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | 6 | import io.zbus.mq.Protocol; 7 | import io.zbus.mq.model.ChannelReader; 8 | import io.zbus.mq.model.MessageQueue.AbstractMessageQueue; 9 | import io.zbus.transport.Message; 10 | 11 | public class DbQueue extends AbstractMessageQueue{ 12 | 13 | public DbQueue(String mqName) { 14 | super(mqName); 15 | } 16 | 17 | @Override 18 | public String type() { 19 | return Protocol.DB; 20 | } 21 | 22 | @Override 23 | public long size() { 24 | return 0; 25 | } 26 | 27 | @Override 28 | public void write(Message message) { 29 | // TODO Auto-generated method stub 30 | 31 | } 32 | 33 | @Override 34 | public void write(List messages) { 35 | // TODO Auto-generated method stub 36 | 37 | } 38 | 39 | @Override 40 | public Integer getMask() { 41 | // TODO Auto-generated method stub 42 | return null; 43 | } 44 | 45 | @Override 46 | public void setMask(Integer mask) { 47 | // TODO Auto-generated method stub 48 | 49 | } 50 | 51 | @Override 52 | public void destroy() { 53 | // TODO Auto-generated method stub 54 | 55 | } 56 | 57 | @Override 58 | protected ChannelReader buildChannelReader(String channelId) throws IOException { 59 | // TODO Auto-generated method stub 60 | return null; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/disk/DiskChannelReader.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.disk; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import io.zbus.kit.JsonKit; 11 | import io.zbus.mq.Protocol; 12 | import io.zbus.mq.Protocol.ChannelInfo; 13 | import io.zbus.mq.disk.support.DiskMessage; 14 | import io.zbus.mq.disk.support.QueueReader; 15 | import io.zbus.mq.model.ChannelReader; 16 | import io.zbus.transport.Message; 17 | 18 | public class DiskChannelReader implements ChannelReader { 19 | private static final Logger logger = LoggerFactory.getLogger(DiskChannelReader.class); 20 | 21 | private final QueueReader reader; 22 | private final String name; 23 | 24 | public DiskChannelReader(String channel, DiskQueue diskQueue) throws IOException { 25 | this.name = channel; 26 | reader = new QueueReader(diskQueue.index, channel); 27 | } 28 | 29 | public boolean isEnd() { 30 | try { 31 | return reader.isEOF(); 32 | } catch (IOException e) { 33 | return true; 34 | } 35 | } 36 | 37 | public Message read() throws IOException { 38 | DiskMessage data = reader.read(); 39 | if (data == null) { 40 | return null; 41 | } 42 | Message res = JsonKit.parseObject(data.body, Message.class); 43 | res.setHeader(Protocol.OFFSET, data.offset); 44 | return res; 45 | } 46 | 47 | @Override 48 | public List read(int count) throws IOException { 49 | List res = new ArrayList<>(); 50 | for (int i = 0; i < count; i++) { 51 | Message data = read(); 52 | if(data == null) break; 53 | res.add(data); 54 | } 55 | return res; 56 | } 57 | 58 | public boolean seek(Long offset, String checksum) throws IOException { 59 | return reader.seek(offset, checksum); 60 | } 61 | 62 | @Override 63 | public String getFilter() { 64 | return reader.getFilter(); 65 | } 66 | 67 | public void setFilter(String filter) { 68 | reader.setFilter(filter); 69 | } 70 | 71 | @Override 72 | public void close() throws IOException { 73 | reader.close(); 74 | } 75 | 76 | public Integer getMask() { 77 | return reader.getMask(); 78 | } 79 | 80 | public void setMask(Integer mask) { 81 | reader.setMask(mask); 82 | } 83 | 84 | @Override 85 | public ChannelInfo info() { 86 | ChannelInfo info = new ChannelInfo(); 87 | info.name = name; 88 | info.mask = getMask(); 89 | info.filter = getFilter(); 90 | info.offset = reader.getTotalOffset(); 91 | return info; 92 | } 93 | 94 | @Override 95 | public void destroy() { 96 | try { 97 | reader.delete(); 98 | } catch (IOException e) { 99 | logger.error(e.getMessage(), e); 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/disk/DiskQueue.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.disk; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.List; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import io.zbus.kit.JsonKit; 11 | import io.zbus.mq.Protocol; 12 | import io.zbus.mq.disk.support.DiskMessage; 13 | import io.zbus.mq.disk.support.Index; 14 | import io.zbus.mq.disk.support.QueueWriter; 15 | import io.zbus.mq.model.ChannelReader; 16 | import io.zbus.mq.model.MessageQueue.AbstractMessageQueue; 17 | import io.zbus.transport.Message; 18 | 19 | public class DiskQueue extends AbstractMessageQueue { 20 | private static final Logger logger = LoggerFactory.getLogger(DiskQueue.class); 21 | final Index index; 22 | private final QueueWriter writer; 23 | 24 | public DiskQueue(String mqName, File baseDir) throws IOException { 25 | super(mqName); 26 | File mqDir = new File(baseDir, mqName); 27 | index = new Index(mqDir); 28 | writer = new QueueWriter(index); 29 | 30 | loadChannels(); 31 | } 32 | 33 | @Override 34 | public String type() { 35 | return Protocol.DISK; 36 | } 37 | 38 | @Override 39 | public long size() { 40 | return index.getMessageCount(); 41 | } 42 | 43 | @Override 44 | protected ChannelReader buildChannelReader(String channelId) throws IOException { 45 | return new DiskChannelReader(channelId, this); 46 | } 47 | 48 | private void loadChannels() { 49 | File[] channelFiles = index.getReaderDir().listFiles( pathname-> { 50 | return Index.isReaderFile(pathname); 51 | }); 52 | if (channelFiles != null && channelFiles.length> 0) { 53 | for (File channelFile : channelFiles) { 54 | String channelName = channelFile.getName(); 55 | channelName = channelName.substring(0, channelName.lastIndexOf('.')); 56 | try { 57 | ChannelReader reader = buildChannelReader(channelName); 58 | channelTable.put(channelName, reader); 59 | } catch (IOException e) { 60 | logger.error(e.getMessage(), e); 61 | } 62 | } 63 | } 64 | } 65 | 66 | private DiskMessage diskMessage(Message message) { 67 | DiskMessage diskMsg = new DiskMessage(); 68 | diskMsg.id = (String)message.getHeader(Protocol.ID); 69 | diskMsg.tag = (String)message.getHeader(Protocol.FILTER); 70 | diskMsg.body = JsonKit.toJSONBytes(message, "UTF8"); 71 | return diskMsg; 72 | } 73 | @Override 74 | public void write(Message message) { 75 | try { 76 | writer.write(diskMessage(message)); 77 | } catch (IOException e) { 78 | logger.error(e.getMessage(), e); 79 | } 80 | } 81 | 82 | @Override 83 | public void write(List messages) { 84 | try { 85 | DiskMessage[] diskMsgs = new DiskMessage[messages.size()]; 86 | for(int i=0;i= (this.pos + this.bufferLen)){ 37 | //reset buffer 38 | this.pos = pos; 39 | loadBuffer(); 40 | return; 41 | } 42 | 43 | this.offset = (int)(pos - this.pos); 44 | } 45 | 46 | public int skipBytes(int n) throws IOException { 47 | if(n <= 0) return 0; 48 | this.offset += n; 49 | if(this.offset > bufferLen){ 50 | this.pos += this.offset; 51 | loadBuffer(); 52 | } 53 | 54 | return n; 55 | } 56 | 57 | public boolean checksum(int size, long checksum){ 58 | byte[] data = new byte[size]; 59 | try { 60 | int n = peek(data); 61 | if(n <= 0){ 62 | return false; 63 | } 64 | } catch (IOException e) { 65 | return false; 66 | } 67 | 68 | Checksum crc = new CRC32(); 69 | crc.update(data, 0, size); 70 | return checksum == crc.getValue(); 71 | } 72 | 73 | public static long calcChecksum(byte[] data){ 74 | Checksum crc = new CRC32(); 75 | crc.update(data, 0, data.length); 76 | return crc.getValue(); 77 | } 78 | 79 | public int read(byte[] data) throws IOException{ 80 | int required = data.length; 81 | if(required <= remaining()){ 82 | System.arraycopy(this.buffer, offset, data, 0, required); 83 | offset += required; 84 | return required; 85 | } 86 | 87 | int dst = 0; 88 | while(required > 0){ 89 | if(remaining() <= 0){ 90 | this.pos += bufferLen; 91 | this.loadBuffer(); 92 | if(bufferLen <= 0) return dst; //EOF 93 | } 94 | 95 | int bufRemaining = remaining(); 96 | int n = required>=bufRemaining? bufRemaining : required; 97 | System.arraycopy(this.buffer, offset, data, dst, n); 98 | offset += n; 99 | dst += n; 100 | required -= n; 101 | } 102 | return dst; 103 | } 104 | 105 | public int peek(byte[] data) throws IOException{ 106 | int required = data.length; 107 | if(required <= remaining()){ 108 | System.arraycopy(this.buffer, offset, data, 0, required); 109 | return required; 110 | } 111 | 112 | 113 | long peekPos = this.pos + offset; 114 | this.file.seek(peekPos); 115 | int n = this.file.read(data); 116 | return n; 117 | } 118 | 119 | 120 | public int readInt() throws IOException{ 121 | byte[] data = new byte[4]; 122 | int n = read(data); 123 | if(n != 4){ 124 | throw new IllegalStateException("Not enought data"); 125 | } 126 | int ch1 = data[0]&0XFF; 127 | int ch2 = data[1]&0XFF; 128 | int ch3 = data[2]&0XFF; 129 | int ch4 = data[3]&0XFF; 130 | return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); 131 | } 132 | 133 | 134 | public long readLong() throws IOException{ 135 | return ((long)(readInt()) << 32) + (readInt() & 0xFFFFFFFFL); 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/disk/support/DiskMessage.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.disk.support; 2 | 3 | public class DiskMessage { 4 | public Long offset; // 8, write ignore 5 | public Long checksum; // 8 6 | public String id; // 1 + id(max 39) 7 | public Long timestamp; // 8 8 | public Long messageNumber; // 8, write ignore 9 | public String tag; // 1 + tag(max 127) 10 | public byte[] body; // 4 + len 11 | 12 | public int size(){ 13 | int bodySize = 0; 14 | if(body != null) bodySize = body.length; 15 | return 4 + bodySize + BODY_POS; 16 | } 17 | 18 | public boolean valid = true; //default to valid, when tag not found after reading to the end of block 19 | public int bytesScanned; //when tagging applied, bytesScanned >= size() 20 | 21 | public static final int ID_MAX_LEN = 39; 22 | public static final int TAG_MAX_LEN = 127; 23 | public static final int BODY_POS = 8 + 8 + 40 + 8 + 8 + 128; //200 24 | public static final int CHECKSUM_SIZE = 40 + 8 + 8 + 128; 25 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/disk/support/QueueWriter.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.disk.support; 2 | 3 | import java.io.Closeable; 4 | import java.io.IOException; 5 | import java.util.concurrent.locks.Lock; 6 | import java.util.concurrent.locks.ReentrantLock; 7 | 8 | public class QueueWriter implements Closeable{ 9 | private final Index index; 10 | private Block writeBlock; 11 | private final Lock writeLock = new ReentrantLock(); 12 | 13 | public QueueWriter(Index index) throws IOException { 14 | this.index = index; 15 | writeBlock = index.createWriteBlock(); 16 | } 17 | 18 | public void write(DiskMessage... data) throws IOException{ 19 | if(data.length == 0) return; 20 | 21 | writeLock.lock(); 22 | try{ 23 | int count = writeBlock.write(data); 24 | if(count <= 0){ 25 | writeBlock.close(); 26 | writeBlock = index.createWriteBlock(); 27 | writeBlock.write(data); 28 | } 29 | } 30 | finally { 31 | writeLock.unlock(); 32 | } 33 | } 34 | 35 | @Override 36 | public void close() throws IOException { 37 | if(writeBlock != null){ 38 | writeBlock.close(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/memory/CircularArray.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.memory; 2 | 3 | public class CircularArray { 4 | final int maxSize; 5 | long start = 0; // readable entry 6 | long end = 0; // first entry to write 7 | Object[] array; 8 | 9 | public CircularArray(int maxSize) { 10 | this.maxSize = maxSize; 11 | array = new Object[this.maxSize]; 12 | } 13 | 14 | public CircularArray() { 15 | this(10000); 16 | } 17 | 18 | public int size() { 19 | synchronized (array) { 20 | return (int) (end - start); 21 | } 22 | } 23 | 24 | private int forwardIndex() { 25 | if (end - start >= maxSize) { 26 | start++; 27 | } 28 | end++; 29 | return (int) (end % maxSize); 30 | } 31 | 32 | public void write(Object... data) { 33 | synchronized (array) { 34 | for (Object obj : data) { 35 | int i = (int) (end % maxSize); 36 | array[i] = obj; 37 | forwardIndex(); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/memory/MemoryChannelReader.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.memory; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import io.zbus.mq.Protocol; 8 | import io.zbus.mq.Protocol.ChannelInfo; 9 | import io.zbus.mq.model.Channel; 10 | import io.zbus.mq.model.ChannelReader; 11 | import io.zbus.transport.Message; 12 | 13 | public class MemoryChannelReader implements ChannelReader { 14 | private final CircularArray queue; 15 | private final Channel channel; 16 | private String filter; 17 | private Integer mask; 18 | 19 | public MemoryChannelReader(CircularArray circularArray, Channel channel) { 20 | queue = circularArray; 21 | this.channel = channel.clone(); 22 | if (this.channel.offset == null || this.channel.offset < queue.start) { 23 | this.channel.offset = queue.end; 24 | } 25 | if (this.channel.offset > queue.end) { 26 | this.channel.offset = queue.end; 27 | } 28 | } 29 | 30 | public int size() { 31 | synchronized (queue.array) { 32 | if (channel.offset < queue.start) { 33 | channel.offset = queue.start; 34 | } 35 | return (int) (queue.end - channel.offset); 36 | } 37 | } 38 | 39 | @Override 40 | public void close() throws IOException { 41 | 42 | } 43 | 44 | public List read(int count) throws IOException { 45 | synchronized (queue.array) { 46 | List res = new ArrayList<>(); 47 | if (channel.offset < queue.start) { 48 | channel.offset = queue.start; 49 | } 50 | int c = 0; 51 | while (channel.offset < queue.end) { 52 | int idx = (int) (channel.offset % queue.maxSize); 53 | Message data = (Message)queue.array[idx]; 54 | data.setHeader(Protocol.OFFSET, channel.offset); //Add offset 55 | res.add(data); 56 | channel.offset++; 57 | c++; 58 | if(c >= count) break; 59 | } 60 | return res; 61 | } 62 | } 63 | 64 | @Override 65 | public Message read() throws IOException { 66 | synchronized (queue.array) { 67 | if (channel.offset < queue.start) { 68 | channel.offset = queue.start; 69 | } 70 | Message res = null; 71 | if (channel.offset < queue.end) { 72 | int idx = (int) (channel.offset % queue.maxSize); 73 | res = (Message)queue.array[idx]; 74 | res.setHeader(Protocol.OFFSET, channel.offset); //Add offset 75 | channel.offset++; 76 | } 77 | return res; 78 | } 79 | } 80 | 81 | @Override 82 | public boolean seek(Long offset, String msgid) throws IOException { 83 | if(offset == null) return false; 84 | this.channel.offset = offset; 85 | if (this.channel.offset < queue.start) { 86 | this.channel.offset = queue.start; 87 | } 88 | return true; 89 | } 90 | 91 | @Override 92 | public void destroy() { 93 | 94 | } 95 | 96 | @Override 97 | public boolean isEnd() { 98 | return size() <= 0; 99 | } 100 | 101 | @Override 102 | public void setFilter(String filter) { 103 | this.filter = filter; 104 | } 105 | 106 | public String getFilter() { 107 | return filter; 108 | } 109 | 110 | @Override 111 | public Integer getMask() { 112 | return mask; 113 | } 114 | 115 | @Override 116 | public void setMask(Integer mask) { 117 | this.mask = mask; 118 | } 119 | 120 | @Override 121 | public ChannelInfo info() { 122 | ChannelInfo info = new ChannelInfo(); 123 | info.name = channel.name; 124 | info.filter = channel.filter; 125 | info.mask = channel.mask; 126 | return info; 127 | } 128 | 129 | 130 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/memory/MemoryQueue.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.memory; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | 6 | import io.zbus.mq.Protocol; 7 | import io.zbus.mq.model.Channel; 8 | import io.zbus.mq.model.ChannelReader; 9 | import io.zbus.mq.model.MessageQueue.AbstractMessageQueue; 10 | import io.zbus.transport.Message; 11 | 12 | public class MemoryQueue extends AbstractMessageQueue{ 13 | private CircularArray data; 14 | private Integer mask = 0; 15 | 16 | public MemoryQueue(String name, int maxSize) { 17 | super(name); 18 | this.data = new CircularArray(maxSize); 19 | } 20 | 21 | public MemoryQueue(String name) { 22 | this(name, 1000); 23 | } 24 | 25 | @Override 26 | public String type() { 27 | return Protocol.MEMORY; 28 | } 29 | 30 | @Override 31 | public long size() { 32 | return data.size(); 33 | } 34 | 35 | @Override 36 | protected ChannelReader buildChannelReader(String channelId) throws IOException { 37 | Channel channel = new Channel(channelId); 38 | return new MemoryChannelReader(data, channel); 39 | } 40 | 41 | @Override 42 | public void write(Message message) { 43 | data.write(message); 44 | } 45 | 46 | @Override 47 | public void write(List messages) { 48 | data.write(messages.toArray()); 49 | } 50 | 51 | @Override 52 | public Integer getMask() { 53 | return mask; 54 | } 55 | 56 | @Override 57 | public void setMask(Integer mask) { 58 | this.mask = mask; 59 | } 60 | 61 | @Override 62 | public void flush() { 63 | 64 | } 65 | 66 | @Override 67 | public void destroy() { 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/model/Channel.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.model; 2 | 3 | /** 4 | * 5 | * Channel represents an isolated MQ's data reader. 6 | * It controls offset from MQ's start position. 7 | * 8 | * @author leiming.hong 9 | * 10 | */ 11 | public class Channel implements Cloneable { 12 | public final String name; 13 | public Long offset; 14 | public Integer mask; 15 | public String filter; 16 | public String offsetChecksum; //MsgId 17 | 18 | public Channel(String name, Long offset) { 19 | this.name = name; 20 | this.offset = offset; 21 | } 22 | public Channel(String name) { 23 | this(name, null); 24 | } 25 | 26 | @Override 27 | public Channel clone() { 28 | try { 29 | Channel channel = (Channel)super.clone(); 30 | return channel; 31 | } catch (CloneNotSupportedException e) { 32 | throw new IllegalStateException(e.getMessage(), e.getCause()); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/model/ChannelReader.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.model; 2 | 3 | import java.io.Closeable; 4 | import java.io.IOException; 5 | import java.util.List; 6 | 7 | import io.zbus.mq.Protocol.ChannelInfo; 8 | import io.zbus.transport.Message; 9 | 10 | public interface ChannelReader extends Closeable { 11 | 12 | Message read() throws IOException; 13 | 14 | List read(int count) throws IOException; 15 | 16 | boolean seek(Long offset, String msgid) throws IOException; 17 | 18 | void destroy(); 19 | 20 | boolean isEnd(); 21 | 22 | void setFilter(String filter); 23 | 24 | String getFilter(); 25 | 26 | Integer getMask(); 27 | 28 | void setMask(Integer mask); 29 | 30 | ChannelInfo info(); 31 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/model/Subscription.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.model; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | public class Subscription { 7 | public Set filters = new HashSet<>(); 8 | public String mq; 9 | public String channel; 10 | public String clientId; 11 | public Integer window; 12 | 13 | public void setFilter(String filter) { 14 | this.filters.clear(); 15 | this.filters.add(filter); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/plugin/DefaultUrlFilter.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.plugin; 2 | 3 | import java.util.List; 4 | import java.util.Map.Entry; 5 | 6 | import io.zbus.kit.HttpKit; 7 | import io.zbus.kit.HttpKit.UrlInfo; 8 | import io.zbus.mq.MessageQueueManager; 9 | import io.zbus.mq.Protocol; 10 | import io.zbus.transport.Message; 11 | import io.zbus.transport.http.Http; 12 | 13 | public class DefaultUrlFilter implements UrlFilter { 14 | private UrlMapping urlMapping = new UrlMapping(); 15 | private MessageQueueManager mqManager; 16 | 17 | public DefaultUrlFilter(MessageQueueManager mqManager) { 18 | this.mqManager = mqManager; 19 | } 20 | 21 | @Override 22 | public Message doFilter(Message req) { 23 | String url = req.getUrl(); 24 | if(url == null) return null; 25 | 26 | //CMD or MQ populated in header, use header control, no need parse URL 27 | if(req.getHeader(Protocol.CMD) != null || req.getHeader(Protocol.MQ) != null) { 28 | return null; 29 | } 30 | 31 | String mq = urlMapping.match(url); 32 | 33 | UrlInfo info = HttpKit.parseUrl(url); 34 | 35 | if(info.pathList.size()==0) { 36 | if(mq != null) { 37 | req.setHeader(Protocol.MQ, mq); 38 | } 39 | 40 | for(Entry e : info.queryParamMap.entrySet()) { 41 | String key = e.getKey(); 42 | Object value = e.getValue(); 43 | if(key.equals("body")) { 44 | req.setBody(value); 45 | continue; 46 | } 47 | req.setHeader(key.toLowerCase(), value); 48 | } 49 | if(mq == null) { 50 | return null; 51 | } 52 | } 53 | 54 | if(mq == null) { 55 | if(info.pathList.size() > 0) { 56 | mq = info.pathList.get(0); 57 | } 58 | } 59 | 60 | if(mqManager.get(mq) == null) { 61 | Message res = new Message(); 62 | res.setStatus(404); 63 | res.setHeader(Http.CONTENT_TYPE, "text/html; charset=utf8"); 64 | res.setBody(String.format("%s Not Found", url)); 65 | return res; 66 | } 67 | 68 | //Assumed to be RPC 69 | if(req.getHeader(Protocol.CMD) == null) { // RPC assumed 70 | req.setHeader(Protocol.CMD, Protocol.PUB); 71 | req.setHeader(Protocol.ACK, false); //ACK should be disabled 72 | } 73 | 74 | if(mq != null) { 75 | req.setHeader(Protocol.MQ, mq); 76 | } 77 | return null; 78 | } 79 | 80 | @Override 81 | public void updateUrlEntry(String mq, List entries, boolean clear) { 82 | for(UrlEntry e : entries) { 83 | if(!mq.equals(e.mq)) { 84 | throw new IllegalArgumentException("UrlEntry's mq should be same"); 85 | } 86 | } 87 | 88 | if(clear) urlMapping.clear(mq); 89 | urlMapping.addMapping(entries); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/plugin/UrlEntry.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.plugin; 2 | 3 | public class UrlEntry{ 4 | public String url; //url path 5 | public String mq; 6 | @Override 7 | public int hashCode() { 8 | final int prime = 31; 9 | int result = 1; 10 | result = prime * result + ((mq == null) ? 0 : mq.hashCode()); 11 | result = prime * result + ((url == null) ? 0 : url.hashCode()); 12 | return result; 13 | } 14 | @Override 15 | public boolean equals(Object obj) { 16 | if (this == obj) 17 | return true; 18 | if (obj == null) 19 | return false; 20 | if (getClass() != obj.getClass()) 21 | return false; 22 | UrlEntry other = (UrlEntry) obj; 23 | if (mq == null) { 24 | if (other.mq != null) 25 | return false; 26 | } else if (!mq.equals(other.mq)) 27 | return false; 28 | if (url == null) { 29 | if (other.url != null) 30 | return false; 31 | } else if (!url.equals(other.url)) 32 | return false; 33 | return true; 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/plugin/UrlFilter.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.plugin; 2 | 3 | import java.util.List; 4 | 5 | import io.zbus.transport.Message; 6 | 7 | /** 8 | * 9 | * Message URL filter 10 | * 11 | * return response message if not null, and it will stop handle the request message further. 12 | * 13 | * 14 | * @author leiming.hong Jul 4, 2018 15 | * 16 | */ 17 | public interface UrlFilter { 18 | /** 19 | * Filter on Message 20 | * 21 | * @param req request Message 22 | * @return Message to reply if not null 23 | */ 24 | Message doFilter(Message req); 25 | 26 | /** 27 | * Update entries for URL filtering 28 | * 29 | * @param entries UrlEntry list 30 | * @param clear clear entries for same MQ to fully update if set true, do delta updates otherwise. 31 | */ 32 | void updateUrlEntry(String mq, List entries, boolean clear); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/mq/plugin/UrlMapping.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.plugin; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Map.Entry; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | /** 11 | * URL mapping to MQ, when mq is missing in request message. 12 | * 13 | * If no mapping is provided, /{mq}/xx/... format of url is assume, and the first part of url is 14 | * assumed to be mq 15 | * 16 | * @author leiming.hong Jul 3, 2018 17 | * 18 | */ 19 | 20 | public class UrlMapping { 21 | private Map> mq2urlList = new ConcurrentHashMap<>(); 22 | private Map url2mq = new ConcurrentHashMap<>(); 23 | 24 | public String match(String url) { //TODO speed up url 25 | int length = 0; 26 | String mq = null; 27 | Iterator> iter = url2mq.entrySet().iterator(); 28 | while(iter.hasNext()) { 29 | Entry e = iter.next(); 30 | String key = e.getKey(); 31 | if(url.startsWith(key)) { 32 | if(key.length() > length) { 33 | length = key.length(); 34 | mq = e.getValue(); 35 | } 36 | } 37 | } 38 | return mq; 39 | } 40 | 41 | public void clear(String mq) { 42 | List urlEntries = mq2urlList.remove(mq); 43 | if(urlEntries == null) return; 44 | 45 | for(UrlEntry e : urlEntries) { 46 | url2mq.remove(e.url); 47 | } 48 | } 49 | 50 | public void addMapping(UrlEntry entry) { 51 | url2mq.put(entry.url, entry.mq); 52 | List entryList = mq2urlList.get(entry.mq); 53 | if(entryList == null) { 54 | entryList = new ArrayList<>(); 55 | mq2urlList.put(entry.mq, entryList); 56 | } 57 | 58 | if(!entryList.contains(entry)) { 59 | entryList.add(entry); 60 | } 61 | } 62 | 63 | public void addMapping(List entryList) { 64 | for(UrlEntry entry : entryList) { 65 | addMapping(entry); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/MethodInvoker.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 7 | * Generic method invocation bridge 8 | * 9 | * @author leiming.hong 10 | * 11 | */ 12 | public interface MethodInvoker { 13 | public Object invoke(String funcName, Map params); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/Protocol.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | 4 | public interface Protocol { 5 | //Compatible to HTTP 6 | public static final String STATUS = "status"; // Response message status 7 | public static final String URL = "url"; // Message URL(compatible to HTTP) 8 | public static final String BODY = "body"; // Message body 9 | public static final String ID = "id"; // Message ID 10 | 11 | public static final String API_KEY = "apiKey"; 12 | public static final String SIGNATURE = "signature"; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/RpcAuthFilter.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import io.zbus.auth.ApiKeyProvider; 4 | import io.zbus.auth.AuthResult; 5 | import io.zbus.auth.DefaultAuth; 6 | import io.zbus.auth.RequestAuth; 7 | import io.zbus.transport.Message; 8 | 9 | public class RpcAuthFilter implements RpcFilter { 10 | private RequestAuth auth; 11 | 12 | public RpcAuthFilter(ApiKeyProvider apiKeyProvider) { 13 | this.auth = new DefaultAuth(apiKeyProvider); 14 | } 15 | 16 | public RpcAuthFilter(RequestAuth auth) { 17 | this.auth = auth; 18 | } 19 | 20 | @Override 21 | public boolean doFilter(Message request, Message response) { 22 | AuthResult res = auth.auth(request); 23 | if(res.success) return true; 24 | 25 | response.setStatus(403); 26 | response.setBody(res.message); 27 | 28 | return false; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/RpcClient.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.lang.reflect.InvocationHandler; 5 | import java.lang.reflect.Method; 6 | import java.lang.reflect.Proxy; 7 | 8 | import io.zbus.kit.HttpKit; 9 | import io.zbus.kit.JsonKit; 10 | import io.zbus.transport.Client; 11 | import io.zbus.transport.IoAdaptor; 12 | import io.zbus.transport.Message; 13 | 14 | public class RpcClient extends Client { 15 | private String urlPrefix = ""; 16 | 17 | public RpcClient(String address) { 18 | this(address, null); 19 | } 20 | public RpcClient(String address, String urlPrefix) { 21 | super(address); 22 | this.urlPrefix = urlPrefix; 23 | } 24 | 25 | public RpcClient(IoAdaptor ioAdaptor) { 26 | super(ioAdaptor); 27 | } 28 | 29 | public void setUrlPrefix(String urlPrefix) { 30 | this.urlPrefix = urlPrefix; 31 | } 32 | 33 | private static T parseResult(Message resp, Class clazz) { 34 | Object data = resp.getBody(); 35 | Integer status = resp.getStatus(); 36 | if(status != null && status != 200){ 37 | if(data instanceof RuntimeException){ 38 | throw (RuntimeException)data; 39 | } else { 40 | throw new RpcException(data.toString()); 41 | } 42 | } 43 | try { 44 | return (T) JsonKit.convert(data, clazz); 45 | } catch (Exception e) { 46 | throw new RpcException(e.getMessage(), e.getCause()); 47 | } 48 | } 49 | 50 | @SuppressWarnings("unchecked") 51 | public T createProxy(String module, Class clazz){ 52 | String urlPrefix = HttpKit.joinPath(this.urlPrefix, module); 53 | Constructor rpcInvokerCtor; 54 | try { 55 | rpcInvokerCtor = RpcInvocationHandler.class.getConstructor(new Class[] {RpcClient.class, String.class }); 56 | RpcInvocationHandler rpcInvokerHandler = rpcInvokerCtor.newInstance(this, urlPrefix); 57 | Class[] interfaces = new Class[] { clazz }; 58 | ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 59 | return (T) Proxy.newProxyInstance(classLoader, interfaces, rpcInvokerHandler); 60 | } catch (Exception e) { 61 | throw new RpcException(e); 62 | } 63 | } 64 | 65 | 66 | public static class RpcInvocationHandler implements InvocationHandler { 67 | private RpcClient rpc; 68 | private String urlPrefix; 69 | private static final Object REMOTE_METHOD_CALL = new Object(); 70 | 71 | public RpcInvocationHandler(RpcClient rpc, String urlPrefix) { 72 | this.rpc = rpc; 73 | this.urlPrefix = urlPrefix; 74 | } 75 | 76 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 77 | if(args == null){ 78 | args = new Object[0]; 79 | } 80 | Object value = handleLocalMethod(proxy, method, args); 81 | if (value != REMOTE_METHOD_CALL) return value; 82 | 83 | 84 | String urlPath = HttpKit.joinPath(urlPrefix, method.getName()); 85 | Message request = new Message(); 86 | request.setUrl(urlPath); 87 | request.setBody(args); //use body 88 | 89 | Message resp = rpc.invoke(request); 90 | return parseResult(resp, method.getReturnType()); 91 | } 92 | 93 | protected Object handleLocalMethod(Object proxy, Method method, 94 | Object[] args) throws Throwable { 95 | String methodName = method.getName(); 96 | Class[] params = method.getParameterTypes(); 97 | 98 | if (methodName.equals("equals") && params.length == 1 99 | && params[0].equals(Object.class)) { 100 | Object value0 = args[0]; 101 | if (value0 == null || !Proxy.isProxyClass(value0.getClass())) 102 | return new Boolean(false); 103 | RpcInvocationHandler handler = (RpcInvocationHandler) Proxy.getInvocationHandler(value0); 104 | return new Boolean(this.rpc.equals(handler.rpc)); 105 | } else if (methodName.equals("hashCode") && params.length == 0) { 106 | return new Integer(this.rpc.hashCode()); 107 | } else if (methodName.equals("toString") && params.length == 0) { 108 | return "RpcInvocationHandler[" + this.rpc + "]"; 109 | } 110 | return REMOTE_METHOD_CALL; 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/RpcException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2009-2015 HONG LEIMING 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package io.zbus.rpc; 24 | 25 | 26 | public class RpcException extends RuntimeException { 27 | private static final long serialVersionUID = 8445590420018236422L; 28 | 29 | public RpcException(String message) { 30 | super(message); 31 | } 32 | 33 | public RpcException() { 34 | } 35 | 36 | public RpcException(String message, Throwable cause) { 37 | super(message, cause); 38 | } 39 | 40 | public RpcException(Throwable cause) { 41 | super(cause); 42 | } 43 | 44 | public RpcException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 45 | super(message, cause, enableSuppression, writableStackTrace); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/RpcFilter.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import io.zbus.transport.Message; 4 | 5 | public interface RpcFilter { 6 | /** 7 | * 8 | * @param request 9 | * @param response 10 | * @return true if continue to handle request response 11 | */ 12 | boolean doFilter(Message request, Message response); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/RpcMethod.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import io.zbus.kit.HttpKit; 7 | import io.zbus.rpc.annotation.RequestMapping; 8 | 9 | public class RpcMethod { 10 | public String urlPath; // java method's url path 11 | public String method; // java method 12 | public List paramTypes = new ArrayList<>(); 13 | public List paramNames = new ArrayList<>(); 14 | public String returnType; 15 | public boolean authRequired; 16 | public boolean docEnabled = true; 17 | public RequestMapping urlAnnotation; 18 | 19 | public RpcMethod() { 20 | 21 | } 22 | 23 | public RpcMethod(RpcMethod m) { 24 | this.method = m.method; 25 | this.paramTypes = new ArrayList<>(m.paramTypes); 26 | this.paramNames = new ArrayList<>(m.paramNames); 27 | this.returnType = m.returnType; 28 | this.authRequired = m.authRequired; 29 | } 30 | 31 | public String getUrlPath() { 32 | if(urlPath == null) return HttpKit.joinPath(method); 33 | return urlPath; 34 | } 35 | 36 | public void setUrlPath(String module, String method) { 37 | this.urlPath = HttpKit.joinPath(module, method); 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/RpcStartInterceptor.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | public interface RpcStartInterceptor { 4 | void onStart(RpcProcessor processor); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/StaticResource.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import io.zbus.kit.FileKit; 7 | import io.zbus.kit.HttpKit; 8 | import io.zbus.kit.HttpKit.UrlInfo; 9 | import io.zbus.rpc.annotation.RequestMapping; 10 | import io.zbus.transport.Message; 11 | import io.zbus.transport.http.Http; 12 | 13 | public class StaticResource { 14 | private String basePath = ""; 15 | private FileKit fileKit = new FileKit(); 16 | 17 | @RequestMapping(exclude=true) 18 | public void setBasePath(String basePath) { 19 | this.basePath = basePath; 20 | } 21 | @RequestMapping(exclude=true) 22 | public void setCacheEnabled(boolean cacheEnabled) { 23 | this.fileKit.setCache(cacheEnabled); 24 | } 25 | 26 | @RequestMapping("/") 27 | public Message file(Message req) { 28 | Message res = new Message(); 29 | 30 | UrlInfo info = HttpKit.parseUrl(req.getUrl()); 31 | String file = HttpKit.joinPath(basePath ,info.urlPath ); 32 | if(!new File(basePath).isAbsolute()) { 33 | file = file.substring(1); //remove first / 34 | } 35 | 36 | String contentType = HttpKit.contentType(file); 37 | if(contentType == null) { 38 | contentType = "application/octet-stream"; 39 | } 40 | 41 | res.setHeader(Http.CONTENT_TYPE, contentType); 42 | res.setStatus(200); 43 | try { 44 | byte[] data = fileKit.loadFileBytes(file); 45 | res.setBody(data); 46 | } catch (IOException e) { 47 | res.setStatus(404); 48 | res.setHeader(Http.CONTENT_TYPE, "text/plain; charset=utf8"); 49 | res.setBody(info.urlPath + " Not Found"); 50 | } 51 | return res; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/annotation/Auth.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2009-2015 HONG LEIMING 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package io.zbus.rpc.annotation; 24 | 25 | import java.lang.annotation.Retention; 26 | import java.lang.annotation.RetentionPolicy; 27 | 28 | @Retention(RetentionPolicy.RUNTIME) 29 | public @interface Auth { 30 | boolean exclude() default false; //exclude the method out if set true 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/annotation/Param.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Documented 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Target(ElementType.PARAMETER) 12 | public @interface Param { 13 | String value() default ""; //Name of parameter 14 | String defaultValue() default ""; //Default value of parameter 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/annotation/RequestMapping.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Target({ElementType.METHOD, ElementType.TYPE}) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Documented 12 | public @interface RequestMapping { 13 | String value() default ""; //Alias of path 14 | String path() default ""; 15 | String[] method() default { }; 16 | boolean exclude() default false; 17 | boolean docEnabled() default true; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/doc/DocRender.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.doc; 2 | 3 | import java.io.IOException; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import io.zbus.kit.FileKit; 9 | import io.zbus.kit.HttpKit; 10 | import io.zbus.rpc.RpcMethod; 11 | import io.zbus.rpc.RpcProcessor; 12 | import io.zbus.rpc.annotation.RequestMapping; 13 | import io.zbus.transport.Message; 14 | import io.zbus.transport.http.Http; 15 | 16 | public class DocRender { 17 | private FileKit fileKit = new FileKit(); 18 | private final RpcProcessor rpcProcessor; 19 | 20 | public DocRender(RpcProcessor rpcProcessor) { 21 | this.rpcProcessor = rpcProcessor; 22 | } 23 | 24 | @RequestMapping(path="/", docEnabled=false) 25 | public Message index() throws IOException { 26 | Message result = new Message(); 27 | Map model = new HashMap(); 28 | 29 | List methods = this.rpcProcessor.rpcMethodList(); 30 | String doc = "
"; 31 | int rowIdx = 0; 32 | for(RpcMethod m : methods) { 33 | if(!m.docEnabled) continue; 34 | doc += rowDoc(m, rowIdx++); 35 | } 36 | doc += "
"; 37 | String js = fileKit.loadFile("static/zbus.min.js"); 38 | model.put("content", doc); 39 | model.put("zbusjs", js); 40 | String urlPrefix = this.rpcProcessor.getUrlPrefix(); 41 | if(urlPrefix.endsWith("/")) { 42 | urlPrefix = urlPrefix.substring(0, urlPrefix.length()-1); 43 | } 44 | model.put("urlPrefix", urlPrefix); 45 | 46 | String body = fileKit.loadFile("static/rpc.htm", model); 47 | result.setBody(body); 48 | result.setHeader(Http.CONTENT_TYPE, "text/html; charset=utf8"); 49 | return result; 50 | } 51 | 52 | private String rowDoc(RpcMethod m, int idx) { 53 | String fmt = 54 | "" + 55 | "%s" + 56 | "%s" + 57 | "%s(%s)" + 58 | "" + 59 | ""; 60 | String methodLink = HttpKit.joinPath(rpcProcessor.getUrlPrefix(), m.getUrlPath()); 61 | String method = m.method; 62 | String paramList = ""; 63 | int size = m.paramNames.size(); 64 | if(size < m.paramTypes.size()) { 65 | size = m.paramTypes.size(); 66 | } 67 | for(int i=0;i 0) { 78 | paramList = paramList.substring(0, paramList.length()-2); 79 | } 80 | 81 | return String.format(fmt, methodLink, methodLink, m.returnType, methodLink, method, 82 | paramList); 83 | } 84 | 85 | 86 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/rpc/server/HttpRpcServerAdaptor.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.server; 2 | 3 | import java.io.IOException; 4 | 5 | import io.zbus.mq.Protocol; 6 | import io.zbus.rpc.RpcProcessor; 7 | import io.zbus.transport.Message; 8 | import io.zbus.transport.ServerAdaptor; 9 | import io.zbus.transport.Session; 10 | 11 | public class HttpRpcServerAdaptor extends ServerAdaptor { 12 | protected RpcProcessor processor; 13 | 14 | public HttpRpcServerAdaptor(RpcProcessor processor) { 15 | this.processor = processor; 16 | } 17 | 18 | public void setProcessor(RpcProcessor processor) { 19 | this.processor = processor; 20 | } 21 | 22 | @Override 23 | public void onMessage(Object msg, Session sess) throws IOException { 24 | Message request = null; 25 | if (!(msg instanceof Message)) { 26 | throw new IllegalStateException("Not support message type"); 27 | } 28 | request = (Message) msg; 29 | 30 | if(Protocol.PING.equals(request.getHeader(Protocol.CMD))) { 31 | return; //ignore 32 | } 33 | Message response = new Message(); 34 | processor.process(request, response); 35 | if(response.getStatus() == null) { 36 | response.setStatus(200); 37 | } 38 | sess.write(response); 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/transport/Client.java: -------------------------------------------------------------------------------- 1 | package io.zbus.transport; 2 | 3 | import java.io.IOException; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | import io.zbus.auth.RequestSign; 7 | import io.zbus.transport.http.WebsocketClient; 8 | import io.zbus.transport.inproc.InprocClient; 9 | 10 | /** 11 | * 12 | * Decoration pattern on AbastractClient, making Client's sub class type adaptive to all real clients such as 13 | * WebsocketClient, InprocClient 14 | * 15 | * @author leiming.hong Jun 27, 2018 16 | * 17 | */ 18 | public class Client extends AbastractClient { 19 | protected AbastractClient support; 20 | 21 | public Client(String address) { 22 | support = new WebsocketClient(address); 23 | } 24 | 25 | public Client(IoAdaptor ioAdaptor) { 26 | support = new InprocClient(ioAdaptor); 27 | } 28 | 29 | @Override 30 | protected void sendMessage0(Message data) { 31 | support.sendMessage0(data); 32 | } 33 | 34 | public void sendMessage(Message data) { 35 | support.sendMessage(data); 36 | } 37 | 38 | public void connect() { 39 | support.connect(); 40 | } 41 | 42 | public synchronized void heartbeat(long interval, TimeUnit timeUnit, AbastractClient.MessageBuilder builder) { 43 | support.heartbeat(interval, timeUnit, builder); 44 | } 45 | 46 | @Override 47 | public void close() throws IOException { 48 | support.close(); 49 | } 50 | 51 | public void invoke(Message req, DataHandler dataHandler) { 52 | support.invoke(req, dataHandler); 53 | } 54 | 55 | public void invoke(Message req, DataHandler dataHandler, 56 | ErrorHandler errorHandler) { 57 | support.invoke(req, dataHandler, errorHandler); 58 | } 59 | 60 | public Message invoke(Message req) throws IOException, InterruptedException { 61 | return support.invoke(req); 62 | } 63 | 64 | public Message invoke(Message req, long timeout, TimeUnit timeUnit) 65 | throws IOException, InterruptedException { 66 | return support.invoke(req, timeout, timeUnit); 67 | } 68 | 69 | public boolean handleInvokeResponse(Message response) throws Exception { 70 | return support.handleInvokeResponse(response); 71 | }; 72 | 73 | public void setApiKey(String apiKey) { 74 | support.setApiKey(apiKey); 75 | } 76 | 77 | public void setSecretKey(String secretKey) { 78 | support.setSecretKey(secretKey); 79 | } 80 | 81 | public void setAuthEnabled(boolean authEnabled) { 82 | support.setAuthEnabled(authEnabled); 83 | } 84 | 85 | public void setRequestSign(RequestSign requestSign) { 86 | support.setRequestSign(requestSign); 87 | } 88 | 89 | public void onMessage(DataHandler onMessage) { 90 | support.onMessage(onMessage); 91 | } 92 | 93 | public void onClose(EventHandler onClose) { 94 | support.onClose(onClose); 95 | } 96 | 97 | public void onOpen(EventHandler onOpen) { 98 | support.onOpen(onOpen); 99 | } 100 | 101 | public void onError(ErrorHandler onError) { 102 | support.onError(onError); 103 | } 104 | 105 | public void setReconnectDelay(int reconnectDelay) { 106 | support.setReconnectDelay(reconnectDelay); 107 | } 108 | 109 | @Override 110 | public void setAfterReceived(MessageInterceptor afterReceived) { 111 | support.setAfterReceived(afterReceived); 112 | } 113 | 114 | @Override 115 | public void setBeforeSend(MessageInterceptor beforeSend) { 116 | support.setBeforeSend(beforeSend); 117 | } 118 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/transport/DataHandler.java: -------------------------------------------------------------------------------- 1 | package io.zbus.transport; 2 | 3 | /** 4 | * Message data callback in networking 5 | * 6 | * @author leiming.hong Jun 27, 2018 7 | * 8 | * @param Data type 9 | */ 10 | public interface DataHandler { 11 | /** 12 | * Handler entry 13 | * @param data callback message data 14 | * @throws Exception unhandled exception 15 | */ 16 | void handle(T data) throws Exception; 17 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/transport/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | package io.zbus.transport; 2 | 3 | /** 4 | * 5 | * Error callback in networking 6 | * 7 | * @author leiming.hong Jun 27, 2018 8 | * 9 | */ 10 | public interface ErrorHandler { 11 | /** 12 | * Handler entry, user should handle all exceptions 13 | * 14 | * @param e error throwed 15 | */ 16 | void handle(Throwable e); 17 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/transport/EventHandler.java: -------------------------------------------------------------------------------- 1 | package io.zbus.transport; 2 | 3 | /** 4 | * Event handler type, such as Connected/Open, Disconnected/Close event 5 | * 6 | * @author leiming.hong Jun 27, 2018 7 | * 8 | */ 9 | public interface EventHandler { 10 | /** 11 | * Handler entry 12 | * 13 | * @throws Exception if any exception unhandled 14 | */ 15 | void handle() throws Exception; 16 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/transport/IoAdaptor.java: -------------------------------------------------------------------------------- 1 | package io.zbus.transport; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * 7 | * IO event-driven extension points, handling server/client networking events 8 | * 9 | * @author leiming.hong Jun 27, 2018 10 | * 11 | */ 12 | public interface IoAdaptor{ 13 | /** 14 | * Triggered when session is created 15 | * 16 | * @param sess session object 17 | * @throws IOException if not handled well for IO 18 | */ 19 | void sessionCreated(Session sess) throws IOException; 20 | /** 21 | * Triggered when session is trying to close/disconnect 22 | * 23 | * @param sess session object 24 | * @throws IOException if not handled well for IO 25 | */ 26 | void sessionToDestroy(Session sess) throws IOException; 27 | /** 28 | * Triggered when underlying session received messages. 29 | * 30 | * Use Session to write message if write is required 31 | * 32 | * @param msg message decoded from wire 33 | * @param sess session object 34 | * @throws IOException if not handled well for IO 35 | */ 36 | void onMessage(Object msg, Session sess) throws IOException; 37 | /** 38 | * Triggered when underlying session encountered an error, such as disconnection violently from remote 39 | * 40 | * @param e exception throwed from underlying session 41 | * @param sess session object 42 | */ 43 | void onError(Throwable e, Session sess); 44 | /** 45 | * Triggered when session has been idled for a configured time span. 46 | * 47 | * @param sess session object 48 | * @throws IOException if not handled well for IO 49 | */ 50 | void onIdle(Session sess) throws IOException; 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/transport/Message.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2009-2015 HONG LEIMING 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package io.zbus.transport; 24 | 25 | 26 | import java.util.HashMap; 27 | import java.util.Map; 28 | import java.util.concurrent.ConcurrentHashMap; 29 | 30 | import com.alibaba.fastjson.JSON; 31 | /** 32 | * Message takes format of standard HTTP: 33 | *

key-value headers 34 | *

body of any time which way serialized is controlled in headers's 'content-type' value 35 | * 36 | *

When Message parsed as request, url and method are in use. 37 | *

When Message parsed as response, status of HTTP is in use, 38 | * 39 | * @author leiming.hong Jun 27, 2018 40 | * 41 | */ 42 | public class Message { 43 | public static final String ID = "id"; 44 | 45 | protected String url; 46 | protected String method; 47 | 48 | protected Integer status; //null: request, otherwise: response 49 | protected String statusText; 50 | 51 | protected Map headers = new ConcurrentHashMap(); 52 | protected Object body; 53 | 54 | public Message() { 55 | 56 | } 57 | 58 | public Message(Message msg) { 59 | replace(msg); 60 | this.headers = new HashMap<>(this.headers); //copy headers 61 | } 62 | 63 | public void replace(Message msg) { 64 | this.url = msg.url; 65 | this.method = msg.method; 66 | this.status = msg.status; 67 | this.statusText = msg.statusText; 68 | this.headers = msg.headers; 69 | this.body = msg.body; 70 | } 71 | 72 | public String getUrl(){ 73 | return this.url; 74 | } 75 | 76 | public void setUrl(String url) { 77 | this.url = url; 78 | } 79 | 80 | public void setStatus(Integer status) { 81 | this.status = status; 82 | } 83 | 84 | public Integer getStatus(){ 85 | return status; 86 | } 87 | 88 | public String getStatusText() { 89 | return statusText; 90 | } 91 | 92 | public void setStatusText(String statusText) { 93 | this.statusText = statusText; 94 | } 95 | 96 | public String getMethod(){ 97 | return this.method; 98 | } 99 | 100 | public void setMethod(String method){ 101 | this.method = method; 102 | } 103 | 104 | public Map getHeaders() { 105 | return headers; 106 | } 107 | 108 | public void setHeaders(Map headers) { 109 | this.headers = headers; 110 | } 111 | 112 | public String getHeader(String key){ 113 | return this.headers.get(key); 114 | } 115 | 116 | public Integer getHeaderInt(String key){ 117 | String value = this.headers.get(key); 118 | if(value == null) return null; 119 | return Integer.valueOf(value); 120 | } 121 | 122 | public Long getHeaderLong(String key){ 123 | String value = this.headers.get(key); 124 | if(value == null) return null; 125 | return Long.valueOf(value); 126 | } 127 | 128 | public Boolean getHeaderBool(String key){ 129 | String value = this.headers.get(key); 130 | if(value == null) return null; 131 | return Boolean.valueOf(value); 132 | } 133 | 134 | public void setHeader(String key, Object value){ 135 | if(value == null) return; 136 | this.headers.put(key, value.toString()); 137 | } 138 | 139 | public String removeHeader(String key){ 140 | return this.headers.remove(key); 141 | } 142 | 143 | public Object getBody() { 144 | return body; 145 | } 146 | 147 | public void setBody(Object body) { 148 | this.body = body; 149 | } 150 | 151 | @Override 152 | public String toString() { 153 | return JSON.toJSONString(this, true); 154 | } 155 | } -------------------------------------------------------------------------------- /src/main/java/io/zbus/transport/MessageInterceptor.java: -------------------------------------------------------------------------------- 1 | package io.zbus.transport; 2 | 3 | /** 4 | * 5 | * Provides an opportunity to adding/removing info of Message 6 | * 7 | * @author leiming.hong Jun 27, 2018 8 | * 9 | */ 10 | public interface MessageInterceptor { 11 | void intercept(Message message); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/transport/ServerAdaptor.java: -------------------------------------------------------------------------------- 1 | package io.zbus.transport; 2 | 3 | import java.io.IOException; 4 | import java.util.Map; 5 | import java.util.concurrent.ConcurrentHashMap; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | /** 11 | * Base server side IoAdaptor, handles all IO events except for onMessage. 12 | * 13 | * Subclass ServerAdaptor can take advantage of the sessionTable management in this base class 14 | * 15 | * @author leiming.hong Jun 27, 2018 16 | * 17 | */ 18 | public abstract class ServerAdaptor implements IoAdaptor{ 19 | private static final Logger logger = LoggerFactory.getLogger(ServerAdaptor.class); 20 | protected Map sessionTable; 21 | 22 | public ServerAdaptor(){ 23 | this(new ConcurrentHashMap()); 24 | } 25 | 26 | public ServerAdaptor(Map sessionTable){ 27 | if(sessionTable == null){ 28 | sessionTable = new ConcurrentHashMap(); 29 | } 30 | this.sessionTable = sessionTable; 31 | } 32 | 33 | @Override 34 | public void sessionCreated(Session sess) throws IOException { 35 | logger.info("Created: " + sess); 36 | sessionTable.put(sess.id(), sess); 37 | } 38 | 39 | @Override 40 | public void sessionToDestroy(Session sess) throws IOException { 41 | logger.info("Destroyed: " + sess); 42 | cleanSession(sess); 43 | } 44 | 45 | @Override 46 | public void onError(Throwable e, Session sess) { 47 | logger.info("Error: " + sess, e); 48 | try { 49 | cleanSession(sess); 50 | } catch (IOException ex) { 51 | logger.error(ex.getMessage(), ex); 52 | } 53 | } 54 | 55 | @Override 56 | public void onIdle(Session sess) throws IOException { 57 | logger.info("Idled: " + sess); 58 | cleanSession(sess); 59 | } 60 | 61 | protected void cleanSession(Session sess) throws IOException { 62 | try{ 63 | sess.close(); 64 | } finally { 65 | sessionTable.remove(sess.id()); 66 | } 67 | } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/transport/Session.java: -------------------------------------------------------------------------------- 1 | package io.zbus.transport; 2 | 3 | import java.io.Closeable; 4 | 5 | /** 6 | * 7 | * Session represents a connection between server and client 8 | * It's main function is to write message data to peer side of the session. 9 | * 10 | * Typical session types: TCP, InProc, IPC 11 | * 12 | * @author leiming.hong Jun 27, 2018 13 | * 14 | */ 15 | public interface Session extends Closeable { 16 | /** 17 | * @return Id of the session 18 | */ 19 | String id(); 20 | /** 21 | * @return remote address of the session 22 | */ 23 | String remoteAddress(); 24 | /** 25 | * @return local address of the session 26 | */ 27 | String localAddress(); 28 | 29 | /** 30 | * Write data into peer side of the session. 31 | * On the other hand, reading message from session is event-driven in IoAdaptor 32 | * @param msg message object before codec 33 | */ 34 | void write(Object msg); 35 | 36 | /** 37 | * @return true if session is active: connected 38 | */ 39 | boolean active(); 40 | 41 | /** 42 | * Get attached attribute value 43 | * @param key attribute key 44 | * @return attached attribute value 45 | */ 46 | V attr(String key); 47 | 48 | /** 49 | * Attach attribute key-value 50 | * @param key attribute key string 51 | * @param value any type of value attached to the session 52 | */ 53 | void attr(String key, V value); 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/transport/http/WebsocketClient.java: -------------------------------------------------------------------------------- 1 | package io.zbus.transport.http; 2 | 3 | import java.io.IOException; 4 | import java.nio.ByteBuffer; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import io.zbus.kit.JsonKit; 12 | import io.zbus.transport.AbastractClient; 13 | import io.zbus.transport.DataHandler; 14 | import io.zbus.transport.Message; 15 | import okhttp3.OkHttpClient; 16 | import okhttp3.Request; 17 | import okhttp3.Response; 18 | import okhttp3.WebSocket; 19 | import okhttp3.WebSocketListener; 20 | import okio.ByteString; 21 | 22 | /** 23 | * 24 | * Client of Websocket, via OkHttp3. 25 | * 26 | * @author leiming.hong Jun 27, 2018 27 | * 28 | */ 29 | public class WebsocketClient extends AbastractClient { 30 | private static final Logger logger = LoggerFactory.getLogger(WebsocketClient.class); 31 | 32 | public DataHandler onText; 33 | public DataHandler onBinary; 34 | 35 | public long lastActiveTime = System.currentTimeMillis(); 36 | 37 | private OkHttpClient client; 38 | private String address; 39 | private WebSocket ws; 40 | private Object wsLock = new Object(); 41 | 42 | private List cachedSendingMessages = new ArrayList(); 43 | 44 | public WebsocketClient(String address, OkHttpClient client) { 45 | super(); 46 | 47 | this.client = client; 48 | if(!address.startsWith("ws://") && !address.startsWith("wss://")) { 49 | address = "ws://" + address; 50 | } 51 | this.address = address; 52 | 53 | onText = msg-> { 54 | Message response = JsonKit.parseObject(msg, Message.class); 55 | if(onMessage != null) { 56 | onMessage.handle(response); 57 | } 58 | }; 59 | 60 | //TODO onBinary 61 | 62 | onClose = ()-> { 63 | synchronized (wsLock) { 64 | if(ws != null){ 65 | ws.close(1000, null); 66 | ws = null; 67 | } 68 | }; 69 | 70 | try { 71 | logger.info("Trying to reconnect " + WebsocketClient.this.address); 72 | Thread.sleep(reconnectDelay); 73 | } catch (InterruptedException e) { 74 | // ignore 75 | } 76 | connect(); 77 | }; 78 | 79 | onError = e -> {; 80 | if(onClose != null){ 81 | try { 82 | onClose.handle(); 83 | } catch (Exception ex) { 84 | logger.error(ex.getMessage(), ex); 85 | } 86 | } 87 | }; 88 | } 89 | 90 | public WebsocketClient(String address){ 91 | this(address, new OkHttpClient()); 92 | } 93 | 94 | @Override 95 | protected void sendMessage0(Message data) { 96 | sendMessage(JsonKit.toJSONString(data)); 97 | } 98 | 99 | @Override 100 | public void close() throws IOException { 101 | super.close(); 102 | 103 | synchronized (this.wsLock) { 104 | if(this.ws != null){ 105 | this.ws.close(1000, null); 106 | this.ws = null; 107 | } 108 | } 109 | } 110 | 111 | public void sendMessage(String command){ 112 | synchronized (wsLock) { 113 | if(this.ws == null){ 114 | this.cachedSendingMessages.add(command); 115 | this.connect(); 116 | return; 117 | } 118 | this.ws.send(command); 119 | } 120 | } 121 | 122 | public synchronized void connect(){ 123 | connectUnsafe(); 124 | } 125 | 126 | protected void connectUnsafe(){ 127 | lastActiveTime = System.currentTimeMillis(); 128 | Request request = new Request.Builder() 129 | .url(address) 130 | .build(); 131 | 132 | this.ws = client.newWebSocket(request, new WebSocketListener() { 133 | @Override 134 | public void onOpen(WebSocket webSocket, Response response) { 135 | String msg = String.format("Websocket(%s) connected", address); 136 | logger.info(msg); 137 | response.close(); 138 | 139 | if(cachedSendingMessages.size()>0){ 140 | for(String json : cachedSendingMessages){ 141 | sendMessage(json); 142 | } 143 | cachedSendingMessages.clear(); 144 | } 145 | if(onOpen != null){ 146 | runner.submit(()->{ 147 | try { 148 | onOpen.handle(); 149 | } catch (Exception e) { 150 | logger.error(e.getMessage(), e); 151 | } 152 | }); 153 | } 154 | } 155 | 156 | @Override 157 | public void onMessage(WebSocket webSocket, String text) { 158 | lastActiveTime = System.currentTimeMillis(); 159 | try { 160 | if(onText != null){ 161 | onText.handle(text); 162 | } 163 | } catch (Exception e) { 164 | logger.error(e.getMessage(), e); 165 | } 166 | } 167 | 168 | @Override 169 | public void onMessage(WebSocket webSocket, ByteString bytes) { 170 | lastActiveTime = System.currentTimeMillis(); 171 | try { 172 | if(onBinary != null){ 173 | onBinary.handle(bytes.asByteBuffer()); 174 | } 175 | } catch (Exception e) { 176 | logger.error(e.getMessage(), e); 177 | } 178 | } 179 | 180 | @Override 181 | public void onClosed(WebSocket webSocket, int code, String reason) { 182 | String msg = String.format("Websocket(%s) closed", address); 183 | logger.info(msg); 184 | if(onClose != null){ 185 | try { 186 | onClose.handle(); 187 | } catch (Exception e) { 188 | logger.error(e.getMessage(), e); 189 | } 190 | } 191 | } 192 | 193 | @Override 194 | public void onFailure(WebSocket webSocket, Throwable t, Response response) { 195 | String error = String.format("Websocket(%s) error: %s", address, t.getMessage()); 196 | logger.error(error); 197 | if(response != null) { 198 | response.close(); 199 | } 200 | if(onError != null){ 201 | onError.handle(t); 202 | } 203 | } 204 | }); 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/transport/inproc/InProcClient.java: -------------------------------------------------------------------------------- 1 | package io.zbus.transport.inproc; 2 | 3 | import java.io.IOException; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | import java.util.concurrent.ConcurrentMap; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import io.zbus.kit.StrKit; 11 | import io.zbus.transport.AbastractClient; 12 | import io.zbus.transport.IoAdaptor; 13 | import io.zbus.transport.Message; 14 | import io.zbus.transport.Session; 15 | 16 | /** 17 | * 18 | * Client of In-Process, optimized for speed. 19 | * 20 | * Crucial ideas: 21 | *

1) InprocClient is a Session type, can be plugged into IoAdaptor from server, which is event driven. 22 | *

2) write message in process means directly invoking onMessage of the client. 23 | *

3) send message to peer means directly invoking server's IoAdaptor's onMessage 24 | * 25 | * @author leiming.hong Jun 27, 2018 26 | * 27 | */ 28 | public class InprocClient extends AbastractClient implements Session { 29 | private static final Logger logger = LoggerFactory.getLogger(InprocClient.class); 30 | private ConcurrentMap attributes = null; 31 | 32 | private IoAdaptor ioAdaptor; 33 | private final String id = StrKit.uuid(); 34 | private boolean active = false; 35 | private Object lock = new Object(); 36 | 37 | public InprocClient(IoAdaptor ioAdaptor) { 38 | this.ioAdaptor = ioAdaptor; 39 | 40 | } 41 | 42 | @Override 43 | public void connect() { 44 | synchronized (lock) { 45 | if(active) return; 46 | } 47 | active = true; 48 | try { 49 | ioAdaptor.sessionCreated(this); 50 | if(onOpen != null) { 51 | runner.submit(()->{ 52 | try { 53 | onOpen.handle(); 54 | } catch (Exception e) { 55 | logger.error(e.getMessage(), e); 56 | } 57 | }); 58 | } 59 | } catch (Exception e) { 60 | logger.error(e.getMessage(), e); 61 | } 62 | } 63 | 64 | @Override 65 | public void close() throws IOException { 66 | super.close(); 67 | 68 | active = false; 69 | ioAdaptor.sessionToDestroy(this); 70 | } 71 | 72 | @Override 73 | public String id() { 74 | return id; 75 | } 76 | 77 | @Override 78 | public String remoteAddress() { 79 | return "InprocServer"; 80 | } 81 | 82 | @Override 83 | public String localAddress() { 84 | return "Inproc-"+id; 85 | } 86 | 87 | 88 | @Override 89 | public void write(Object msg) { //Session received message 90 | try { 91 | if(!(msg instanceof Message)) { 92 | logger.error("Message type required"); 93 | return; 94 | } 95 | Message data = (Message)msg; 96 | if(onMessage != null) { 97 | onMessage.handle(data); 98 | } 99 | } catch (Exception e) { 100 | logger.error(e.getMessage(), e); 101 | } 102 | } 103 | 104 | @Override 105 | protected void sendMessage0(Message data) { //Session send out message 106 | synchronized (lock) { 107 | if(!active) { 108 | connect(); 109 | } 110 | } 111 | 112 | try { 113 | ioAdaptor.onMessage(data, this); 114 | } catch (IOException e) { 115 | logger.error(e.getMessage(), e); 116 | } 117 | } 118 | 119 | @Override 120 | public boolean active() { 121 | return active; 122 | } 123 | 124 | @SuppressWarnings("unchecked") 125 | public V attr(String key) { 126 | if (this.attributes == null) { 127 | return null; 128 | } 129 | 130 | return (V) this.attributes.get(key); 131 | } 132 | 133 | public void attr(String key, V value) { 134 | if(value == null){ 135 | if(this.attributes != null){ 136 | this.attributes.remove(key); 137 | } 138 | return; 139 | } 140 | if (this.attributes == null) { 141 | synchronized (this) { 142 | if (this.attributes == null) { 143 | this.attributes = new ConcurrentHashMap(); 144 | } 145 | } 146 | } 147 | this.attributes.put(key, value); 148 | } 149 | 150 | @Override 151 | public String toString() { 152 | return localAddress(); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/io/zbus/transport/ipc/IpcClient.java: -------------------------------------------------------------------------------- 1 | package io.zbus.transport.ipc; 2 | 3 | /** 4 | * 5 | * Inter-Process-Communication client 6 | * 7 | * Not implemented yet 8 | * 9 | * @author leiming.hong Jun 27, 2018 10 | * 11 | */ 12 | public class IpcClient { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/static/base.css: -------------------------------------------------------------------------------- 1 | .navbar-brand { 2 | padding-top: 8px; 3 | } 4 | .navbar-brand > img { 5 | width: 36px; 6 | height: 36px; 7 | display: inline; 8 | } 9 | 10 | .navbar-brand > span { 11 | color: rgb(145, 220, 90); 12 | font-weight: bold; 13 | visibility: visible; 14 | display: inline-block; 15 | clear: both; 16 | font-size: 24px; 17 | line-height: 24px; 18 | white-space: nowrap; 19 | position: relative; 20 | padding: 0px; 21 | top: 4px; 22 | } 23 | .topic { 24 | margin: 3px; 25 | } 26 | 27 | 28 | .filter-box{ 29 | float: right; 30 | clear: right; 31 | padding-top: 1px; 32 | } 33 | textarea.log { 34 | border-style: none; 35 | border-color: Transparent; 36 | overflow: auto; 37 | resize: none; 38 | } 39 | 40 | .label-as-badge{ 41 | border-radius: 3em; 42 | padding-left: 6px; 43 | padding-right: 6px; 44 | } 45 | .topic-deactive{ 46 | color: black; 47 | background-color: white; 48 | } 49 | 50 | .badge-deactive{ 51 | color: black; 52 | background-color: #777; 53 | } 54 | .add-topic-modal{ 55 | width: 400px; 56 | } 57 | .add-topic-content{ 58 | margin-left: 32px; 59 | margin-right: 32px; 60 | margin-top: 8px; 61 | margin-bottom: 16px; 62 | } 63 | .add-topic-content div{ 64 | margin-top: 6px; 65 | } 66 | input.topic-item{ 67 | width: 220px; 68 | } 69 | .target{ 70 | margin-top: 0px; 71 | } 72 | .close-box{ 73 | float: right; 74 | clear: right; 75 | } 76 | 77 | .action { 78 | margin: 6px; 79 | padding: 6px; 80 | cursor: pointer; 81 | } 82 | .action-list { 83 | margin: 8px; 84 | } 85 | .modal-header{ 86 | padding: 10px; 87 | } 88 | .modal { 89 | text-align: center; 90 | } 91 | 92 | @media screen and (min-width: 768px) { 93 | .modal:before { 94 | display: inline-block; 95 | vertical-align: middle; 96 | content: " "; 97 | height: 100%; 98 | } 99 | } 100 | 101 | .modal-dialog { 102 | display: inline-block; 103 | text-align: left; 104 | vertical-align: middle; 105 | } 106 | 107 | 108 | .caption{ 109 | margin-left: 6px; 110 | display: inline; 111 | } 112 | .caption span{ 113 | font-weight: bolder; 114 | } 115 | 116 | .consumer-group-list { 117 | overflow-y: auto; 118 | } 119 | 120 | 121 | .table-outter{ 122 | border: 2px solid #ddd; 123 | margin: 0px; 124 | width: 100%; 125 | max-width: 100%; 126 | } 127 | .table-outter>tbody>tr{ 128 | border-bottom: 2px solid #ddd; 129 | } 130 | 131 | .table-outter>tbody>tr>td{ 132 | border-right: 2px solid #ddd; 133 | } 134 | 135 | 136 | .table-nested{ 137 | margin: 0px; 138 | width: 100%; 139 | max-width: 100%; 140 | } 141 | 142 | .table-nested>tbody>tr{ 143 | border-bottom: 1px solid #ddd; 144 | line-height: 24px; 145 | } 146 | .table-nested>tbody>tr:last-child{ 147 | border: none; 148 | } 149 | .table-nested>tbody>tr>td{ 150 | border-right: 1px solid #ddd; 151 | } 152 | .table-nested>tbody>tr>td:last-child{ 153 | border: none; 154 | } 155 | 156 | .table-nested>tbody>tr>td, 157 | .table-nested>tfoot>tr>td, 158 | .table-nested>tfoot>tr>th, 159 | .table-nested>thead>tr>td, 160 | .table-nested>thead>tr>th { 161 | padding: 0px; 162 | vertical-align: middle; 163 | } 164 | 165 | .tgroup tr>td:nth-child(1) { 166 | width: 12%; 167 | } 168 | .tgroup tr>td:nth-child(2) { 169 | width: 88%; 170 | } 171 | 172 | 173 | .sgroup tr>td:nth-child(2) { 174 | width: 40%; 175 | } 176 | .sgroup tr>td:nth-child(3) { 177 | width: 60%; 178 | } 179 | 180 | .sgroup td span { 181 | margin-right: 4px; 182 | } 183 | 184 | 185 | .cgroup tr>td:nth-child(1) { 186 | width: 30%; 187 | } 188 | .cgroup tr>td:nth-child(2) { 189 | width: 20%; 190 | } 191 | .cgroup tr>td:nth-child(3) { 192 | width: 10%; 193 | } 194 | .cgroup tr>td:nth-child(4) { 195 | width: 30%; 196 | } 197 | .header-ctrl{ 198 | font-weight: bold; 199 | background-color: #f5f5f5; 200 | line-height: 30px; 201 | border-bottom: none; 202 | } 203 | 204 | .op { 205 | float: right; 206 | margin-right: 10px; 207 | } 208 | 209 | .op div { 210 | float: left; 211 | margin-left: 6px; 212 | } 213 | 214 | .op-del { 215 | color: red; 216 | } 217 | 218 | .op2 { 219 | float: left; 220 | margin-left: 10px; 221 | font-weight: bold; 222 | } 223 | 224 | .cap { 225 | float: left; 226 | } 227 | 228 | td div.td { 229 | margin-left: 10px; 230 | float: left; 231 | } 232 | 233 | td div.num{ 234 | font-weight: bold; 235 | } 236 | 237 | .login input { 238 | font-size: 16px; 239 | } 240 | 241 | .login .token{ 242 | width: 300px; 243 | } 244 | 245 | .hide{ 246 | display: none; 247 | } -------------------------------------------------------------------------------- /src/main/resources/static/base.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushmore/zbus-server/b27bb689599066a8b81f3609a5ce4c903a413b99/src/main/resources/static/base.js -------------------------------------------------------------------------------- /src/main/resources/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushmore/zbus-server/b27bb689599066a8b81f3609a5ce4c903a413b99/src/main/resources/static/favicon.ico -------------------------------------------------------------------------------- /src/main/resources/static/home.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | zbus = mq + rpc 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 |

23 | 24 | 52 |
53 | 54 |
55 | 56 | 57 |
58 |
59 |
Message Queues
60 |
61 |
62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | 70 | 87 | 88 | 89 | 90 | 91 |
MQ Name
71 | 72 | 73 | 74 | 84 | 85 |
Message Depth
75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
Channel
Message Active
Consuming Clients
Filter Topic
83 |
86 |
92 |
93 |
94 | 95 | 96 | 97 |
98 | 99 | 100 | 126 | 127 | 128 | 149 | 150 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /src/main/resources/static/logo.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/resources/static/rpc.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{urlPrefix}} Java 6 | 7 | 32 | 33 | 34 | 35 | 42 | 43 |
44 |
45 | URL={{urlPrefix}}/[module]/[method]/[param1]/[param2]/... 46 |
47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | {{content}} 57 |
URL PathReturn TypeMethod and Params
58 | 59 |
60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/auth/SignAuthExample.java: -------------------------------------------------------------------------------- 1 | package io.zbus.auth; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | import io.zbus.kit.JsonKit; 6 | import io.zbus.transport.Message; 7 | 8 | public class SignAuthExample { 9 | public static void main(String[] args) { 10 | ApiKeyProvider apiKeyProvider = new XmlApiKeyProvider("rpc/auth.xml"); 11 | RequestAuth auth = new DefaultAuth(apiKeyProvider); 12 | 13 | RequestSign sign = new DefaultSign(); 14 | 15 | Message req = new Message(); 16 | req.setHeader("cmd", "pub"); 17 | req.setHeader("mq", "MyRpc"); 18 | req.setHeader("ack", false); 19 | 20 | req.setBody(new Object[] {1,2}); 21 | 22 | String apiKey = "2ba912a8-4a8d-49d2-1a22-198fd285cb06"; 23 | String secretKey = "461277322-943d-4b2f-b9b6-3f860d746ffd"; 24 | 25 | sign.sign(req, apiKey, secretKey); 26 | 27 | String wired = JsonKit.toJSONString(req); 28 | System.out.println(wired); 29 | Message req2 = JsonKit.parseObject(wired, Message.class); 30 | AuthResult res = auth.auth(req2); 31 | 32 | System.out.println(res.success); 33 | 34 | System.out.println(JSON.toJSONString(false)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/kit/JsonKitExample.java: -------------------------------------------------------------------------------- 1 | package io.zbus.kit; 2 | 3 | public class JsonKitExample { 4 | public static void main(String[] args) { 5 | String json = "select:[display_name,id],where:{id:1}"; 6 | json = JsonKit.fixJson(json); 7 | System.out.println(json); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/mq/Pub.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | import io.zbus.transport.Message; 7 | 8 | public class Pub { 9 | 10 | public static MqClient buildInproClient() { 11 | MqServer server = new MqServer(new MqServerConfig()); 12 | return new MqClient(server); 13 | } 14 | 15 | @SuppressWarnings("resource") 16 | public static void main(String[] args) throws Exception { 17 | MqClient client = new MqClient("wss://111.230.136.74"); 18 | 19 | //MqClient client = buildInproClient(); 20 | 21 | client.heartbeat(30, TimeUnit.SECONDS); 22 | final String mq = "MyMQ", mqType = Protocol.MEMORY; 23 | 24 | //1) Create MQ if necessary 25 | Message req = new Message(); 26 | req.setHeader("cmd", "create"); //Create 27 | req.setHeader("mq", mq); 28 | req.setHeader("mqType", mqType); //disk|memory|db 29 | 30 | client.invoke(req); 31 | 32 | AtomicInteger count = new AtomicInteger(0); 33 | for (int i = 0; i < 100; i++) { 34 | //2) Publish Message 35 | Message msg = new Message(); 36 | msg.setHeader("cmd", "pub"); //Publish 37 | msg.setHeader("mq", mq); 38 | msg.setBody(i); //set business data in body 39 | 40 | client.invoke(msg, res->{ //async call 41 | if(count.getAndIncrement() % 10000 == 0) { 42 | System.out.println(res); 43 | } 44 | }); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/mq/Sub.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import io.zbus.transport.Message; 6 | 7 | public class Sub { 8 | public static MqClient buildInproClient() { 9 | MqServer server = new MqServer(new MqServerConfig()); 10 | return new MqClient(server); 11 | } 12 | 13 | @SuppressWarnings("resource") 14 | public static void main(String[] args) throws Exception { 15 | MqClient client = new MqClient("localhost:15555"); 16 | //MqClient client = buildInproClient(); 17 | 18 | client.heartbeat(30, TimeUnit.SECONDS); 19 | 20 | final String mq = "MyMQ", channel = "MyChannel", mqType = Protocol.MEMORY; 21 | 22 | client.addMqHandler(mq, channel, 4, data->{ 23 | System.out.println(data); 24 | }); 25 | 26 | client.onOpen(()->{ 27 | Message req = new Message(); 28 | req.setHeader("cmd", "create"); //create MQ/Channel 29 | req.setHeader("mq", mq); 30 | req.setHeader("mqType", mqType); 31 | req.setHeader("channel", channel); 32 | Message res = client.invoke(req); 33 | System.out.println(res); 34 | 35 | Message sub = new Message(); 36 | sub.setHeader("cmd", "sub"); //Subscribe on MQ/Channel 37 | sub.setHeader("mq", mq); 38 | sub.setHeader("channel", channel); 39 | sub.setHeader("window", 1); 40 | sub.setHeader("filter", "abc"); 41 | 42 | client.invoke(sub, data->{ 43 | System.out.println(data); 44 | }); 45 | }); 46 | 47 | client.connect(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/mq/Take.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq; 2 | 3 | import io.zbus.transport.Message; 4 | 5 | public class Take { 6 | 7 | public static MqClient buildInproClient() { 8 | MqServer server = new MqServer(new MqServerConfig()); 9 | return new MqClient(server); 10 | } 11 | 12 | public static void main(String[] args) throws Exception { 13 | MqClient client = new MqClient("localhost:15555"); 14 | //MqClient client = buildInproClient(); 15 | 16 | final String mq = "MyMQ", channel = "MyChannel"; 17 | 18 | Message req = new Message(); 19 | req.setHeader("cmd", "take"); 20 | req.setHeader("mq", mq); 21 | req.setHeader("channel", channel); 22 | 23 | client.invoke(req, res->{ 24 | System.out.println(res); 25 | 26 | client.close(); 27 | }, e->{ 28 | e.printStackTrace(); 29 | try { client.close(); } catch (Exception ex) { } 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/mq/Zbus.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq; 2 | 3 | public class Zbus { 4 | public static void main(String[] args) { 5 | MqServer.main(args); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/mq/inproc/Pub.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.inproc; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | import io.zbus.mq.MqClient; 6 | import io.zbus.mq.MqServer; 7 | import io.zbus.mq.MqServerConfig; 8 | import io.zbus.transport.Message; 9 | 10 | public class Pub { 11 | 12 | @SuppressWarnings("resource") 13 | public static void main(String[] args) throws Exception { 14 | MqServer server = new MqServer(new MqServerConfig()); 15 | 16 | MqClient client = new MqClient(server); 17 | 18 | String mq = "MyMQ"; 19 | 20 | Message create = new Message(); 21 | create.setHeader("cmd", "create"); 22 | create.setHeader("mq", mq); 23 | create.setHeader("mqType", "disk"); 24 | client.invoke(create, res->{ 25 | System.out.println(res); 26 | }); 27 | Thread.sleep(100); 28 | 29 | AtomicInteger count = new AtomicInteger(0); 30 | for (int i = 0; i < 200000; i++) { 31 | Message msg = new Message(); 32 | msg.setHeader("cmd", "pub"); //Publish 33 | msg.setHeader("mq", mq); 34 | msg.setBody(i); 35 | 36 | client.invoke(msg, res->{ 37 | if(count.getAndIncrement() % 10000 == 0) { 38 | System.out.println(res); 39 | } 40 | }); 41 | } 42 | //ws.close(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/mq/inproc/Sub.java: -------------------------------------------------------------------------------- 1 | package io.zbus.mq.inproc; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | import io.zbus.mq.MqClient; 7 | import io.zbus.mq.MqServer; 8 | import io.zbus.mq.MqServerConfig; 9 | import io.zbus.transport.Message; 10 | 11 | public class Sub { 12 | 13 | @SuppressWarnings({ "resource" }) 14 | public static void main(String[] args) throws Exception { 15 | MqServer server = new MqServer(new MqServerConfig()); 16 | MqClient client = new MqClient(server); 17 | client.heartbeat(30, TimeUnit.SECONDS); 18 | 19 | final String mq = "MyMQ", channel = "MyChannel"; 20 | AtomicInteger count = new AtomicInteger(0); 21 | client.addMqHandler(mq, channel, data->{ 22 | if(count.getAndIncrement() % 10000 == 0) { 23 | System.out.println(data); 24 | } 25 | }); 26 | 27 | client.onOpen(()->{ 28 | Message req = new Message(); 29 | req.setHeader("cmd", "create"); //create MQ/Channel 30 | req.setHeader("mq", mq); 31 | req.setHeader("mqType", "disk"); //Set as Disk type 32 | req.setHeader("channel", channel); 33 | client.invoke(req, res->{ 34 | System.out.println(res); 35 | }); 36 | 37 | Message sub = new Message(); 38 | sub.setHeader("cmd", "sub"); //Subscribe on MQ/Channel 39 | sub.setHeader("mq", mq); 40 | sub.setHeader("channel", channel); 41 | client.invoke(sub, res->{ 42 | System.out.println(res); 43 | }); 44 | }); 45 | 46 | client.connect(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/net/http/HttpClientExample.java: -------------------------------------------------------------------------------- 1 | package io.zbus.net.http; 2 | 3 | import io.zbus.transport.Message; 4 | 5 | public class HttpClientExample { 6 | 7 | public static void main(String[] args) throws Exception { 8 | HttpClient client = new HttpClient(); 9 | Message message = new Message(); 10 | message.setUrl("https://test.io"); 11 | String res = client.string(message); 12 | System.out.println(res); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/net/http/HttpServerExample.java: -------------------------------------------------------------------------------- 1 | package io.zbus.net.http; 2 | 3 | import java.io.IOException; 4 | 5 | import io.zbus.transport.Message; 6 | import io.zbus.transport.Server; 7 | import io.zbus.transport.ServerAdaptor; 8 | import io.zbus.transport.Session; 9 | import io.zbus.transport.http.HttpWsServer; 10 | 11 | public class HttpServerExample { 12 | 13 | @SuppressWarnings("resource") 14 | public static void main(String[] args) { 15 | 16 | ServerAdaptor adaptor = new ServerAdaptor() { 17 | @Override 18 | public void onMessage(Object msg, Session sess) throws IOException { 19 | Message res = new Message(); 20 | res.setStatus(200); 21 | 22 | res.setHeader("id", res.getHeader("id")); 23 | res.setHeader("content-type", "text/plain; charset=utf8"); 24 | 25 | res.setBody("中文"+System.currentTimeMillis()); 26 | 27 | sess.write(res); 28 | } 29 | }; 30 | 31 | Server server = new HttpWsServer(); 32 | server.start(80, adaptor); 33 | //server.start(8080, adaptor); //You may start 80 and 8080 together! 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/net/ssl/SslServerExample.java: -------------------------------------------------------------------------------- 1 | package io.zbus.net.ssl; 2 | 3 | import java.io.IOException; 4 | 5 | import io.netty.handler.ssl.SslContext; 6 | import io.zbus.transport.Message; 7 | import io.zbus.transport.Server; 8 | import io.zbus.transport.ServerAdaptor; 9 | import io.zbus.transport.Session; 10 | import io.zbus.transport.Ssl; 11 | import io.zbus.transport.http.HttpWsServer; 12 | 13 | public class SslServerExample { 14 | 15 | @SuppressWarnings("resource") 16 | public static void main(String[] args) { 17 | 18 | SslContext context = Ssl.buildServerSsl("ssl/zbus.crt", "ssl/zbus.key"); 19 | 20 | Server server = new HttpWsServer(); 21 | ServerAdaptor adaptor = new ServerAdaptor() { 22 | @Override 23 | public void onMessage(Object msg, Session sess) throws IOException { 24 | Message res = new Message(); 25 | res.setStatus(200); 26 | res.setHeader("content-type", "text/html; charset=utf8"); 27 | res.setBody("

hello world

"); 28 | 29 | sess.write(res); 30 | } 31 | }; 32 | server.start(8080, adaptor, context); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/net/ws/WebSocketExample.java: -------------------------------------------------------------------------------- 1 | package io.zbus.net.ws; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import io.zbus.transport.Message; 7 | import io.zbus.transport.http.WebsocketClient; 8 | 9 | public class WebSocketExample { 10 | 11 | public static void main(String[] args) throws Exception { 12 | 13 | WebsocketClient ws = new WebsocketClient("wss://zbus.io"); 14 | ws.onText = data -> { 15 | System.out.println(data); 16 | ws.close(); 17 | }; 18 | 19 | ws.onOpen(()->{ 20 | Map command = new HashMap<>(); 21 | command.put("module", "example"); 22 | command.put("method", "echo"); 23 | command.put("params", new Object[] {"hong"}); 24 | 25 | Message message = new Message(); 26 | message.setBody(command); 27 | 28 | //for MQ 29 | message.setHeader("cmd", "pub"); 30 | message.setHeader("mq", "MyMQ"); 31 | message.setHeader("ack", false); 32 | 33 | ws.sendMessage(message); 34 | 35 | }); 36 | 37 | ws.connect(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/GenericService.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class GenericService implements MethodInvoker { 7 | 8 | @Override 9 | public Object invoke(String funcName, Map params) { 10 | Map res = new HashMap<>(); 11 | res.put("invokedFunc", funcName); 12 | res.put("invokedParams", params); 13 | return res; 14 | } 15 | } -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/MyRegisterInterceptor.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import java.util.Arrays; 4 | import java.util.Map; 5 | 6 | public class MyRegisterInterceptor implements RpcStartInterceptor { 7 | 8 | @Override 9 | public void onStart(RpcProcessor processor) { 10 | //注册方法 11 | GenericService service = new GenericService(); 12 | 13 | //抽象的服务调用,增加一个具体的方法 14 | RpcMethod spec = new RpcMethod(); 15 | spec.method = "func1"; 16 | spec.paramTypes = Arrays.asList(String.class.getName(), Integer.class.getName()); 17 | spec.paramNames = Arrays.asList("name", "age"); 18 | spec.returnType = Map.class.getName(); 19 | 20 | processor.mount(spec, service); 21 | } 22 | } -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/RpcClientDirect.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | public class RpcClientDirect { 4 | 5 | public static void main(String[] args) throws Exception { 6 | RpcClient rpc = new RpcClient("localhost:8080"); 7 | //rpc.setAuthEnabled(true); 8 | //rpc.setApiKey("2ba912a8-4a8d-49d2-1a22-198fd285cb06"); 9 | //rpc.setSecretKey("461277322-943d-4b2f-b9b6-3f860d746ffd"); 10 | 11 | TestCases.doTest(rpc, "/example"); 12 | 13 | rpc.close(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/RpcClientInproc.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | import io.zbus.rpc.biz.InterfaceExampleImpl; 6 | import io.zbus.transport.Message; 7 | import io.zbus.transport.inproc.InprocClient; 8 | 9 | public class RpcClientInproc { 10 | 11 | @SuppressWarnings("resource") 12 | public static void main(String[] args) throws Exception { 13 | RpcProcessor p = new RpcProcessor(); 14 | p.mount("example", InterfaceExampleImpl.class); 15 | 16 | RpcServer server = new RpcServer(p); 17 | server.start(); 18 | 19 | InprocClient rpc = new InprocClient(server.getServerAdaptor()); 20 | 21 | AtomicInteger count = new AtomicInteger(0); 22 | for (int i = 0; i < 1000000; i++) { 23 | Message req = new Message(); 24 | req.setUrl("/example/getOrder"); 25 | 26 | rpc.invoke(req, res->{ 27 | int c = count.getAndIncrement(); 28 | if(c % 10000 == 0) { 29 | System.out.println(c + ": " + res); 30 | } 31 | }); 32 | } 33 | //rpc.close(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/RpcClientMQ.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | public class RpcClientMQ { 4 | 5 | public static void main(String[] args) throws Exception { 6 | RpcClient rpc = new RpcClient("localhost:15555"); 7 | 8 | //rpc.setAuthEnabled(true); 9 | //rpc.setApiKey("2ba912a8-4a8d-49d2-1a22-198fd285cb06"); 10 | //rpc.setSecretKey("461277322-943d-4b2f-b9b6-3f860d746ffd"); 11 | 12 | 13 | TestCases.doTest(rpc, "/example"); 14 | 15 | rpc.close(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/RpcServerDirectHttp.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import io.zbus.kit.FileKit; 7 | import io.zbus.rpc.annotation.RequestMapping; 8 | import io.zbus.transport.Message; 9 | 10 | public class RpcServerDirectHttp { 11 | private FileKit fileKit = new FileKit(false); 12 | 13 | @RequestMapping("/") 14 | public Message home() { 15 | Message res = new Message(); 16 | res.setStatus(200); 17 | res.setHeader("content-type", "text/html; charset=utf8"); 18 | res.setBody("

home page

"); 19 | 20 | return res; 21 | } 22 | 23 | @RequestMapping("/showUpload") 24 | public Message showUpload() { 25 | return fileKit.loadResource("page/upload.html"); 26 | } 27 | 28 | @RequestMapping("/upload") 29 | public Message doUpload(Message req) { 30 | FileKit.saveUploadedFile(req, "/tmp/upload"); 31 | Message res = new Message(); 32 | 33 | res.setStatus(200); 34 | res.setHeader("content-type", "text/html; charset=utf8"); 35 | res.setBody("

Uploaded Success

"); 36 | 37 | return res; 38 | } 39 | 40 | @RequestMapping(path="/abc") 41 | public Object json() { 42 | Map value = new HashMap<>(); 43 | value.put("key", System.currentTimeMillis()); 44 | return value; 45 | } 46 | 47 | @RequestMapping(path="/favicon.ico", docEnabled=false) 48 | public Message favicon() { 49 | return fileKit.loadResource("static/favicon.ico"); 50 | } 51 | 52 | @SuppressWarnings("resource") 53 | public static void main(String[] args) throws Exception { 54 | 55 | RpcProcessor p = new RpcProcessor(); 56 | StaticResource resource = new StaticResource(); 57 | resource.setBasePath("\\tmp"); 58 | 59 | p.mount("", RpcServerDirectHttp.class); 60 | p.mount("static", resource); 61 | 62 | RpcServer server = new RpcServer(p); 63 | server.setPort(8080); 64 | server.start(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/RpcServerDynamicMethod.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import java.util.Arrays; 4 | import java.util.Map; 5 | 6 | 7 | public class RpcServerDynamicMethod { 8 | 9 | @SuppressWarnings("resource") 10 | public static void main(String[] args) throws Exception { 11 | GenericService service = new GenericService(); 12 | 13 | //抽象的服务调用,增加一个具体的方法 14 | RpcMethod spec = new RpcMethod(); 15 | spec.method = "func1"; 16 | spec.paramTypes = Arrays.asList(String.class.getName(), Integer.class.getName()); 17 | spec.paramNames = Arrays.asList("name", "age"); 18 | spec.returnType = Map.class.getName(); 19 | 20 | RpcProcessor p = new RpcProcessor(); 21 | p.mount(spec, service); 22 | 23 | 24 | RpcServer server = new RpcServer(p); 25 | server.setPort(8080); 26 | server.start(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/RpcServerMQ.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import io.zbus.rpc.biz.InterfaceExampleImpl; 4 | 5 | public class RpcServerMQ { 6 | 7 | @SuppressWarnings("resource") 8 | public static void main(String[] args) throws Exception { 9 | 10 | RpcProcessor p = new RpcProcessor(); 11 | p.setUrlPrefix("/test"); 12 | p.mount("/example", InterfaceExampleImpl.class); 13 | 14 | 15 | RpcServer server = new RpcServer(); 16 | //connect to zbus 17 | server.setProcessor(p); 18 | server.setMqServerAddress("localhost:15555"); 19 | server.setMq("MyRpc2"); //MQ entry, RPC client incognito 20 | //MQ authentication, no need to configure if use HTTP direct RPC 21 | //server.setAuthEnabled(true); 22 | //server.setApiKey("2ba912a8-4a8d-49d2-1a22-198fd285cb06"); 23 | //server.setSecretKey("461277322-943d-4b2f-b9b6-3f860d746ffd"); 24 | 25 | server.start(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/RpcServerMQInproc.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import io.zbus.mq.MqServer; 4 | import io.zbus.mq.MqServerConfig; 5 | import io.zbus.rpc.biz.InterfaceExampleImpl; 6 | 7 | public class RpcServerMQInproc { 8 | 9 | @SuppressWarnings("resource") 10 | public static void main(String[] args) throws Exception { 11 | 12 | RpcProcessor p = new RpcProcessor(); 13 | p.setUrlPrefix("/"); 14 | p.mount("/example", InterfaceExampleImpl.class); 15 | 16 | 17 | //Serve RPC via MQ Server InProc 18 | MqServerConfig config = new MqServerConfig("0.0.0.0", 15555); 19 | config.setVerbose(false); 20 | MqServer mqServer = new MqServer(config); 21 | 22 | RpcServer server = new RpcServer(p); 23 | server.setMqServer(mqServer); //InProc MqServer 24 | server.setMq("MyRpc"); //Choose MQ to group Service physically, RPC incognito 25 | 26 | //MQ authentication, no need to configure if use HTTP direct RPC 27 | //server.setAuthEnabled(true); 28 | //server.setApiKey("2ba912a8-4a8d-49d2-1a22-198fd285cb06"); 29 | //server.setSecretKey("461277322-943d-4b2f-b9b6-3f860d746ffd"); 30 | 31 | server.start(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/RpcServerSpring.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import org.springframework.context.support.ClassPathXmlApplicationContext; 4 | 5 | public class RpcServerSpring { 6 | 7 | @SuppressWarnings("resource") 8 | public static void main(String[] args) throws Exception { 9 | new ClassPathXmlApplicationContext("rpc/context.xml"); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/TestCases.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import io.zbus.rpc.biz.InterfaceExample; 4 | import io.zbus.transport.Message; 5 | 6 | public class TestCases { 7 | 8 | public static void doTest(RpcClient rpc, String urlPrefix) throws Exception { 9 | //1) 原始的方法调用中的数据格式 10 | Message req = new Message(); 11 | req.setUrl(urlPrefix+"/plus"); 12 | req.setBody(new Object[] {1,2}); //body as parameter array 13 | 14 | Message res = rpc.invoke(req); //同步调用 15 | System.out.println(res); 16 | 17 | //2)纯异步API 18 | rpc.invoke(req, resp -> { //异步调用 19 | System.out.println(resp); 20 | }); 21 | 22 | //3) 动态代理 23 | InterfaceExample example = rpc.createProxy(urlPrefix, InterfaceExample.class); 24 | int c = example.plus(1, 2); 25 | System.out.println(c); 26 | 27 | 28 | //4) 参数同时基于URL的调用格式 29 | req = new Message(); 30 | req.setUrl(urlPrefix + "/plus/1/2"); 31 | res = rpc.invoke(req); 32 | System.out.println("urlbased: " + res); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/WebsocketClientExample.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | import io.zbus.transport.Message; 6 | import io.zbus.transport.http.WebsocketClient; 7 | 8 | public class WebsocketClientExample { 9 | 10 | @SuppressWarnings("resource") 11 | public static void main(String[] args) throws Exception { 12 | WebsocketClient rpc = new WebsocketClient("localhost:8080"); 13 | 14 | AtomicInteger count = new AtomicInteger(0); 15 | for (int i = 0; i < 100000; i++) { 16 | Message req = new Message(); 17 | req.setHeader("method", "getOrder"); 18 | req.setHeader("module", "example"); 19 | 20 | 21 | rpc.invoke(req, res->{ 22 | int c = count.getAndIncrement(); 23 | if(c % 10000 == 0) { 24 | System.out.println(c + ": " + res); 25 | } 26 | }); 27 | } 28 | //rpc.close(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/DbExample.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.session.SqlSession; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | 8 | 9 | public class DbExample { 10 | 11 | @Autowired 12 | SqlSession sqlSession; 13 | 14 | public List test(){ 15 | return sqlSession.selectList("io.zbus.rpc.biz.db.test"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/DbInterface.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | import org.apache.ibatis.annotations.Param; 7 | import org.apache.ibatis.annotations.Select; 8 | 9 | 10 | public interface DbInterface { 11 | @Select("SELECT * FROM user WHERE User=#{userId}") 12 | Map getUser(@Param("userId") String userId); 13 | 14 | @Select("SELECT * FROM proc WHERE name = #{name}") 15 | Map getProc(@Param("name") String name); 16 | 17 | @Select("SELECT * FROM help_category") 18 | List> helpCate(); 19 | 20 | @Select("SELECT name, description FROM help_topic limit 10") 21 | List> helpTopic(); 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/HelpTopic.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz; 2 | 3 | public class HelpTopic { 4 | public String name; 5 | public String url; 6 | public String example; 7 | 8 | public String getName() { 9 | return name; 10 | } 11 | 12 | public void setName(String name) { 13 | this.name = name; 14 | } 15 | 16 | public String getUrl() { 17 | return url; 18 | } 19 | 20 | public void setUrl(String url) { 21 | this.url = url; 22 | } 23 | 24 | public String getExample() { 25 | return example; 26 | } 27 | 28 | public void setExample(String example) { 29 | this.example = example; 30 | } 31 | 32 | 33 | } -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/InterfaceExample.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | import io.zbus.transport.Message; 7 | 8 | public interface InterfaceExample{ 9 | 10 | int getUserScore(); 11 | 12 | String echo(String string); 13 | 14 | String getString(String name); 15 | 16 | String[] stringArray(); 17 | 18 | byte[] getBin(); 19 | 20 | int plus(int a, int b); 21 | 22 | MyEnum myEnum(MyEnum e); 23 | 24 | User getUser(String name); 25 | 26 | Order getOrder(); 27 | 28 | User[] getUsers(); 29 | 30 | List listUsers(); 31 | 32 | Object[] objectArray(String id); 33 | 34 | int saveObjectArray(Object[] array); 35 | 36 | int saveUserArray(User[] array); 37 | 38 | int saveUserList(List array); 39 | 40 | 41 | Map map(int value1); 42 | 43 | List> listMap(); 44 | 45 | String testEncoding(); 46 | 47 | Class classTest(Class inClass); 48 | 49 | void testTimeout(); 50 | 51 | void noReturn(); 52 | 53 | void throwNullPointerException(); 54 | 55 | void throwUserException() throws UserException; 56 | 57 | void throwException(); 58 | 59 | void throwUnkownException(); 60 | 61 | String nullParam(String nullStr); 62 | 63 | Message html(); 64 | } -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/InterfaceExampleImpl.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Random; 9 | 10 | import com.alibaba.fastjson.JSON; 11 | 12 | import io.zbus.rpc.annotation.Auth; 13 | import io.zbus.rpc.annotation.Param; 14 | import io.zbus.rpc.annotation.RequestMapping; 15 | import io.zbus.transport.Message; 16 | import io.zbus.transport.http.Http; 17 | 18 | @Auth(exclude=true) 19 | public class InterfaceExampleImpl implements InterfaceExample{ 20 | 21 | @Auth(exclude=false) 22 | public String echo(String string) { 23 | return string; 24 | } 25 | 26 | public String getString(@Param("name") String name) { 27 | if(name == null){ 28 | System.out.println("got null: "+ name); 29 | } 30 | return "Hello World ZBUS " + name; 31 | } 32 | 33 | public String testEncoding() { 34 | return "中文"; 35 | } 36 | 37 | public String[] stringArray() { 38 | return new String[]{"hong", "leiming"}; 39 | } 40 | 41 | public byte[] getBin() { 42 | return new byte[10]; 43 | } 44 | 45 | public Object[] objectArray(String id){ 46 | return new Object[]{id, getUser("rushmore"), "hong", true, 1, String.class}; 47 | } 48 | 49 | 50 | public int plus(int a, int b) { 51 | return a+b; 52 | } 53 | 54 | public MyEnum myEnum(MyEnum e) { 55 | return MyEnum.Sunday; 56 | } 57 | 58 | 59 | public User getUser(String name) { 60 | User user = new User(); 61 | user.setName(name); 62 | user.setPassword("password"+System.currentTimeMillis()); 63 | user.setAge(new Random().nextInt(100)); 64 | user.setItem("item_1"); 65 | user.setRoles(Arrays.asList("admin", "common")); 66 | user.getAttrs().put("extAttr1", "XAttr1"); 67 | user.getAttrs().put("extAttr2", "XAttr2"); 68 | return user; 69 | } 70 | 71 | 72 | public Order getOrder() { 73 | Order order = new Order(); 74 | order.setItem(Arrays.asList("item1","item2","item3")); 75 | order.setData("bin".getBytes()); 76 | return order; 77 | } 78 | 79 | 80 | public User[] getUsers() { 81 | return new User[]{getUser("hong"), getUser("leiming")}; 82 | } 83 | 84 | public List listUsers() { 85 | return Arrays.asList(getUser("hong"), getUser("leiming")); 86 | } 87 | 88 | @RequestMapping(path="/map") 89 | public List> listMap() { 90 | List> res = new ArrayList>(); 91 | res.add(map(1)); 92 | res.add(map(2)); 93 | res.add(map(3)); 94 | return res; 95 | } 96 | 97 | 98 | public int saveObjectArray(Object[] array) { 99 | return 0; 100 | } 101 | 102 | 103 | public int saveUserArray(User[] array) { 104 | return 0; 105 | } 106 | 107 | 108 | public int saveUserList(List array) { 109 | return 0; 110 | } 111 | 112 | public void throwException() { 113 | throw new RuntimeException("runtime exception from server"); 114 | } 115 | 116 | public void throwUserException() throws UserException { 117 | throw new UserException("user defined exception"); 118 | } 119 | 120 | public void throwNullPointerException(){ 121 | throw new NullPointerException("null pointer"); 122 | } 123 | 124 | public void throwUnkownException() { 125 | throw new PrivateRuntimeException("private runtime exeption"); 126 | } 127 | 128 | 129 | public void noReturn() { 130 | System.out.println("called noReturn"); 131 | } 132 | 133 | 134 | public Class classTest(Class inClass) { 135 | return Double.class; 136 | } 137 | 138 | public void testTimeout() { 139 | try { 140 | Thread.sleep(10000); 141 | } catch (InterruptedException e) { 142 | e.printStackTrace(); 143 | } 144 | } 145 | 146 | public int getUserScore() { 147 | Random r = new Random(System.currentTimeMillis()); 148 | int time = 10 + r.nextInt(100); 149 | return time; 150 | } 151 | 152 | public String nullParam(String nullStr) { 153 | return nullStr; 154 | } 155 | 156 | public Map map(int value1) { 157 | Map value = new HashMap<>(); 158 | value.put("key", value1); 159 | return value; 160 | } 161 | 162 | public Message html() { 163 | Message res = new Message(); 164 | res.setStatus(200); 165 | res.setHeader(Http.CONTENT_TYPE, "text/html; charset=utf8"); 166 | res.setBody("

html" + System.currentTimeMillis()+"

"); 167 | return res; 168 | } 169 | 170 | @RequestMapping("/test") 171 | public Message req(Message req) { 172 | System.out.println(JSON.toJSONString(req, true)); 173 | 174 | Message res = new Message(); 175 | res.setStatus(200); 176 | res.setHeader(Http.CONTENT_TYPE, "text/html; charset=utf8"); 177 | res.setBody("

request injected

"); 178 | return res; 179 | } 180 | } 181 | 182 | 183 | 184 | class PrivateRuntimeException extends RuntimeException{ 185 | private static final long serialVersionUID = 4587336984841564800L; 186 | 187 | public PrivateRuntimeException() { 188 | super(); 189 | } 190 | 191 | public PrivateRuntimeException(String message, Throwable cause) { 192 | super(message, cause); 193 | } 194 | 195 | public PrivateRuntimeException(String message) { 196 | super(message); 197 | } 198 | 199 | public PrivateRuntimeException(Throwable cause) { 200 | super(cause); 201 | } 202 | 203 | } -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/MyEnum.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz; 2 | 3 | public enum MyEnum { 4 | Monday, 5 | Sunday 6 | } 7 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/Order.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | 7 | public class Order{ 8 | private byte[] data; 9 | private List item; 10 | 11 | public List getItem() { 12 | return item; 13 | } 14 | 15 | public void setItem(List item) { 16 | this.item = item; 17 | } 18 | 19 | 20 | 21 | 22 | @Override 23 | public String toString() { 24 | return "Order [data=" + Arrays.toString(data) + ", item=" + item + "]"; 25 | } 26 | 27 | public byte[] getData() { 28 | return data; 29 | } 30 | 31 | public void setData(byte[] data) { 32 | this.data = data; 33 | } 34 | 35 | 36 | 37 | } -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/User.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | 8 | public class User{ 9 | private String name; 10 | private String password; 11 | private int age; 12 | private String item; 13 | private List roles; 14 | private Map attrs = new HashMap(); 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | public void setName(String name) { 20 | this.name = name; 21 | } 22 | public String getPassword() { 23 | return password; 24 | } 25 | public void setPassword(String password) { 26 | this.password = password; 27 | } 28 | public int getAge() { 29 | return age; 30 | } 31 | public void setAge(int age) { 32 | this.age = age; 33 | } 34 | public String getItem() { 35 | return item; 36 | } 37 | public void setItem(String item) { 38 | this.item = item; 39 | } 40 | public List getRoles() { 41 | return roles; 42 | } 43 | public void setRoles(List roles) { 44 | this.roles = roles; 45 | } 46 | 47 | public Map getAttrs() { 48 | return attrs; 49 | } 50 | 51 | public void setAttrs(Map attrs) { 52 | this.attrs = attrs; 53 | } 54 | @Override 55 | public String toString() { 56 | return "User [name=" + name + ", password=" + password + ", age=" + age + ", item=" + item + ", roles=" + roles 57 | + ", attrs=" + attrs + "]"; 58 | } 59 | 60 | 61 | } -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/UserException.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz; 2 | 3 | public class UserException extends Exception { 4 | private static final long serialVersionUID = -6135508809283998375L; 5 | 6 | public UserException() { 7 | } 8 | 9 | public UserException(String message, Throwable cause) { 10 | super(message, cause); 11 | } 12 | 13 | public UserException(String message) { 14 | super(message); 15 | } 16 | 17 | public UserException(Throwable cause) { 18 | super(cause); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/generic/GenericMethod.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz.generic; 2 | 3 | public interface GenericMethod { 4 | void test(T t); 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/generic/GenericMethodImpl.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz.generic; 2 | 3 | import io.zbus.rpc.annotation.RequestMapping; 4 | 5 | @RequestMapping 6 | public class GenericMethodImpl implements GenericMethod{ 7 | 8 | @Override 9 | public void test(T t) { 10 | System.out.println(t); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/inheritance/BaseService.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz.inheritance; 2 | 3 | public interface BaseService { 4 | boolean save(T t); 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/inheritance/BaseServiceImpl.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz.inheritance; 2 | 3 | public class BaseServiceImpl implements BaseService { 4 | @Override 5 | public boolean save(T t) { 6 | System.out.println(t); 7 | return false; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/inheritance/SubService1.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz.inheritance; 2 | 3 | import io.zbus.rpc.annotation.RequestMapping; 4 | 5 | @RequestMapping 6 | public class SubService1 extends BaseServiceImpl implements SubServiceInterface1{ 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/inheritance/SubService2.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz.inheritance; 2 | 3 | import io.zbus.rpc.annotation.RequestMapping; 4 | 5 | @RequestMapping 6 | public class SubService2 extends BaseServiceImpl implements SubServiceInterface2 { 7 | @Override 8 | public boolean save(String t) { 9 | System.out.println("override! " + t); 10 | return true; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/inheritance/SubServiceInterface1.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz.inheritance; 2 | 3 | public interface SubServiceInterface1 extends BaseService { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/io/zbus/rpc/biz/inheritance/SubServiceInterface2.java: -------------------------------------------------------------------------------- 1 | package io.zbus.rpc.biz.inheritance; 2 | 3 | public interface SubServiceInterface2 extends BaseService { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/test/resources/conf/zbus.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
0.0.0.0:80
7 | false 8 | 9 | 10 | 11 | 12 | 2ba912a8-4a8d-49d2-1a22-198fd285cb06 13 | 461277322-943d-4b2f-b9b6-3f860d746ffd 14 | 15 | 16 | 3ba912a6-4a8d-49d1-1a66-198ea285cb03 17 | 123475622-953d-4b2f-a7b6-4f860d126cce 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 |
0.0.0.0:15555
26 |
27 | 28 | 29 | 30 |
0.0.0.0:25555
31 | 43 |
44 | 45 | 46 | 47 | /tmp/zbus 48 | 49 | 102400 50 | 128M 51 | true 52 |
53 | 54 | -------------------------------------------------------------------------------- /src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, stdout 3 | 4 | # Direct log messages to stdout 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p %c:%L - %m%n 9 | 10 | 11 | log4j.appender.file=org.apache.log4j.DailyRollingFileAppender 12 | log4j.appender.file.File=zbus 13 | log4j.appender.file.DatePattern='.'yyyy-MM-dd 14 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 15 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /src/test/resources/page/style.css: -------------------------------------------------------------------------------- 1 | .navbar-brand { 2 | padding-top: 8px; 3 | } 4 | .navbar-brand > img { 5 | width: 36px; 6 | height: 36px; 7 | display: inline; 8 | } 9 | 10 | .navbar-brand > span { 11 | color: rgb(145, 220, 90); 12 | font-weight: bold; 13 | visibility: visible; 14 | display: inline-block; 15 | clear: both; 16 | font-size: 24px; 17 | line-height: 24px; 18 | white-space: nowrap; 19 | position: relative; 20 | padding: 0px; 21 | top: 4px; 22 | } 23 | .topic { 24 | margin: 3px; 25 | } 26 | 27 | 28 | .filter-box{ 29 | float: right; 30 | clear: right; 31 | padding-top: 1px; 32 | } 33 | textarea.log { 34 | border-style: none; 35 | border-color: Transparent; 36 | overflow: auto; 37 | resize: none; 38 | } 39 | 40 | .label-as-badge{ 41 | border-radius: 3em; 42 | padding-left: 6px; 43 | padding-right: 6px; 44 | } 45 | .topic-deactive{ 46 | color: black; 47 | background-color: white; 48 | } 49 | 50 | .badge-deactive{ 51 | color: black; 52 | background-color: #777; 53 | } 54 | .add-topic-modal{ 55 | width: 400px; 56 | } 57 | .add-topic-content{ 58 | margin-left: 32px; 59 | margin-right: 32px; 60 | margin-top: 8px; 61 | margin-bottom: 16px; 62 | } 63 | .add-topic-content div{ 64 | margin-top: 6px; 65 | } 66 | input.topic-item{ 67 | width: 220px; 68 | } 69 | .target{ 70 | margin-top: 0px; 71 | } 72 | .close-box{ 73 | float: right; 74 | clear: right; 75 | } 76 | 77 | .action { 78 | margin: 6px; 79 | padding: 6px; 80 | cursor: pointer; 81 | } 82 | .action-list { 83 | margin: 8px; 84 | } 85 | .modal-header{ 86 | padding: 10px; 87 | } 88 | .modal { 89 | text-align: center; 90 | } 91 | 92 | @media screen and (min-width: 768px) { 93 | .modal:before { 94 | display: inline-block; 95 | vertical-align: middle; 96 | content: " "; 97 | height: 100%; 98 | } 99 | } 100 | 101 | .modal-dialog { 102 | display: inline-block; 103 | text-align: left; 104 | vertical-align: middle; 105 | } 106 | 107 | 108 | .caption{ 109 | margin-left: 6px; 110 | display: inline; 111 | } 112 | .caption span{ 113 | font-weight: bolder; 114 | } 115 | 116 | .consumer-group-list { 117 | overflow-y: auto; 118 | } 119 | 120 | 121 | .table-outter{ 122 | border: 2px solid #ddd; 123 | margin: 0px; 124 | width: 100%; 125 | max-width: 100%; 126 | } 127 | .table-outter>tbody>tr{ 128 | border-bottom: 2px solid #ddd; 129 | } 130 | 131 | .table-outter>tbody>tr>td{ 132 | border-right: 2px solid #ddd; 133 | } 134 | 135 | 136 | .table-nested{ 137 | margin: 0px; 138 | width: 100%; 139 | max-width: 100%; 140 | } 141 | 142 | .table-nested>tbody>tr{ 143 | border-bottom: 1px solid #ddd; 144 | line-height: 24px; 145 | } 146 | .table-nested>tbody>tr:last-child{ 147 | border: none; 148 | } 149 | .table-nested>tbody>tr>td{ 150 | border-right: 1px solid #ddd; 151 | } 152 | .table-nested>tbody>tr>td:last-child{ 153 | border: none; 154 | } 155 | 156 | .table-nested>tbody>tr>td, 157 | .table-nested>tfoot>tr>td, 158 | .table-nested>tfoot>tr>th, 159 | .table-nested>thead>tr>td, 160 | .table-nested>thead>tr>th { 161 | padding: 0px; 162 | vertical-align: middle; 163 | } 164 | 165 | .tgroup tr>td:nth-child(1) { 166 | width: 12%; 167 | } 168 | .tgroup tr>td:nth-child(2) { 169 | width: 88%; 170 | } 171 | 172 | 173 | .sgroup tr>td:nth-child(1) { 174 | width: 25%; 175 | } 176 | .sgroup tr>td:nth-child(2) { 177 | width: 15%; 178 | } 179 | .sgroup tr>td:nth-child(3) { 180 | width: 60%; 181 | } 182 | 183 | .sgroup td span { 184 | margin-right: 4px; 185 | } 186 | 187 | 188 | .cgroup tr>td:nth-child(1) { 189 | width: 30%; 190 | } 191 | .cgroup tr>td:nth-child(2) { 192 | width: 20%; 193 | } 194 | .cgroup tr>td:nth-child(3) { 195 | width: 10%; 196 | } 197 | .cgroup tr>td:nth-child(4) { 198 | width: 30%; 199 | } 200 | .header-ctrl{ 201 | font-weight: bold; 202 | background-color: #f5f5f5; 203 | line-height: 30px; 204 | border-bottom: none; 205 | } 206 | 207 | .op { 208 | float: right; 209 | margin-right: 10px; 210 | } 211 | 212 | .op div { 213 | float: left; 214 | margin-left: 6px; 215 | } 216 | 217 | .op-del { 218 | color: red; 219 | } 220 | 221 | .op2 { 222 | float: left; 223 | margin-left: 10px; 224 | font-weight: bold; 225 | } 226 | 227 | .cap { 228 | float: left; 229 | } 230 | 231 | td div.td { 232 | margin-left: 10px; 233 | float: left; 234 | } 235 | 236 | td div.num{ 237 | font-weight: bold; 238 | } 239 | 240 | .login input { 241 | font-size: 16px; 242 | } 243 | 244 | .login .token{ 245 | width: 300px; 246 | } 247 | 248 | .hide{ 249 | display: none; 250 | } -------------------------------------------------------------------------------- /src/test/resources/page/upload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | zbus = mq + rpc 6 | 10 | 11 | 12 | 13 |
14 |
15 | 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /src/test/resources/rpc/auth.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 2ba912a8-4a8d-49d2-1a22-198fd285cb06 6 | 461277322-943d-4b2f-b9b6-3f860d746ffd 7 | 8 | 9 | 3ba912a6-4a8d-49d1-1a66-198ea285cb03 10 | 123475622-953d-4b2f-a7b6-4f860d126cce 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/test/resources/rpc/context.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | classpath*:/rpc/mapper/*.xml 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/test/resources/rpc/mapper/db.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /src/test/resources/rpc/mybatis.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/test/resources/rpc/mysql.xml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/test/resources/ssl/zbus.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDuTCCAqGgAwIBAgIJAL7ek1F/ZGgtMA0GCSqGSIb3DQEBCwUAMHMxCzAJBgNV 3 | BAYTAk5aMRAwDgYDVQQIDAdXYWlrYXRvMREwDwYDVQQHDAhIYW1pbHRvbjENMAsG 4 | A1UECgwEemJ1czEQMA4GA1UEAwwHemJ1cy5pbzEeMBwGCSqGSIb3DQEJARYPNDQx 5 | OTQ0NjJAcXEuY29tMB4XDTE3MDQyNzIzMTYzM1oXDTE4MDQyNzIzMTYzM1owczEL 6 | MAkGA1UEBhMCTloxEDAOBgNVBAgMB1dhaWthdG8xETAPBgNVBAcMCEhhbWlsdG9u 7 | MQ0wCwYDVQQKDAR6YnVzMRAwDgYDVQQDDAd6YnVzLmlvMR4wHAYJKoZIhvcNAQkB 8 | Fg80NDE5NDQ2MkBxcS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB 9 | AQDLIRdSXFXpQn4mA2WTKNUQEv+UOnzllxsBxiagHHGOCeXT2lLYMG4Sy1g/ZcX1 10 | EjIv1YEN4wOJfYBGkO5O2bkuSnbRwTep6RrmLBHy7VSyYlx9zvbDG7NIHWBtrpLa 11 | uRktABvaaO5R9WWJ3axG2Pkip332c3v5K1cwgN4uWTIypTVMyaeLBhGevdF1U+8D 12 | PjRAyK1TAsgtqTkSwpHoCNLPrLPSkJHJCgO/dIFGR4an12a2BBoUXtW1Xcqt9SOk 13 | 6HSWglKENyF59HGU4FfatsRgWADXGJZFN1MhubCh80JTEfo4siKuSaQwXj1m0m2y 14 | HR8S1yF1i8KwFgpW8dKaB6DNAgMBAAGjUDBOMB0GA1UdDgQWBBSqhDd0wKcVsaGW 15 | q4LJt9tL25pGTTAfBgNVHSMEGDAWgBSqhDd0wKcVsaGWq4LJt9tL25pGTTAMBgNV 16 | HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCzja5Yh9l/PkJAHDm/u0CmjCYo 17 | UfWQKRUsO1H0e/UacLngEH41o6y58y/wdiqJKWtPn+qVxIApn8C/Ds3ziCVDbtBa 18 | TSq3lOcL+Ze4QVNWUljA6Ai4pOveOgfoWqG5N1j4tQGRr+fqdGaFdYXmu3r1BGko 19 | p6KgB1/OyPAmDipMXBBZkWwxhlI9Knzf+C24KDFRfpVBtwXKZF+eK4PzpRzvC+Lb 20 | envj/Akj6UOiqtCo5kR9Q4rLVjdAZF10zHHL9IIausI3wyir/pqC10Dl85gVLe5W 21 | 7jgvTtJSRhrdGjI5lviHNCjQC0RZtfHz2URreSacclclsGM6lwHNbrpMdONl 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /src/test/resources/ssl/zbus.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDLIRdSXFXpQn4m 3 | A2WTKNUQEv+UOnzllxsBxiagHHGOCeXT2lLYMG4Sy1g/ZcX1EjIv1YEN4wOJfYBG 4 | kO5O2bkuSnbRwTep6RrmLBHy7VSyYlx9zvbDG7NIHWBtrpLauRktABvaaO5R9WWJ 5 | 3axG2Pkip332c3v5K1cwgN4uWTIypTVMyaeLBhGevdF1U+8DPjRAyK1TAsgtqTkS 6 | wpHoCNLPrLPSkJHJCgO/dIFGR4an12a2BBoUXtW1Xcqt9SOk6HSWglKENyF59HGU 7 | 4FfatsRgWADXGJZFN1MhubCh80JTEfo4siKuSaQwXj1m0m2yHR8S1yF1i8KwFgpW 8 | 8dKaB6DNAgMBAAECggEAbD4O+nF/ylQHeuQ2fWu11eH51ZgxM/sIhjJ8JLfjfwgh 9 | M3pUySVNkrBPL0Fhco2mtry0D51YJiz9bR0QEG6O8m710CKBMgaosdzsF6KGjqRB 10 | mzztW9zn9VbKKshrMyiNlOBI92MRFBWLbSL2Ca7XW7MbOXgiqQ2CYbNaMiKP0FIr 11 | +YGUNCHVte9OlJIqh8UtT8itwzCZvyXfWfoMRmfmVTOBR/1KHzWxjdea7CPkTac9 12 | YynCh4pYyol5tJqhnGhR2OgH42NUcXtvelmGm1PRvxNBOjs1rBzE1qg4yhknmjie 13 | 2vPJXkgCTiHv4kfYtAaDIA5TbbI38S3noEfLEI6RAQKBgQDoEsLcaAR8Dn1uCs3P 14 | Vp6QVZGi/aQKu6Iou1r4Y4p33yX9DoFg3zOOcSz0fuWwy7BpkM3X5uM5SUNvtfCp 15 | kicWoisMU8zbRowbTXUz/MeaNKSOGuRnvdG5L10k3fjuuYcXbZ4Ks9rROJHICr/L 16 | /P1Ojml86j97YgfjjdnYgWuhjQKBgQDgEmTuy0LINgOWDFR5XqUSUKsA5JMJIF6d 17 | V8/wXW2z09Burqo+Pmj5EOaZf7xvoEQkQApJHgvA+tp70rmnXDqDzprXEHe0bBoT 18 | 7PfxZ8tPpuGXRhIvGwr2DryyGeuFdV9k3gP8hJ2hvkKu5tyIiStnHdBZvLNAYc/W 19 | S9X4q+UMQQKBgGgGANJKzbfNxutMbHRDn0+TC3TDvIQTFtyrHlu4Qpj4rU6A8f06 20 | DyIKGNx/BPX6V1j6T0o3dCJ5dIDeTMG1gU/j4OflqC2hsauLTL3A0LeOYTRRWZAm 21 | xZr8YAPme26GOseFmxGxDKQ7dxzztIT7IY/UxfP4C/yCNIcLTlp9qIEBAoGABDq0 22 | pwE1KHxEgw+GhKfxq6/UGnc2A0UWJBglN58709oapAwt8HDTIGheQeV0VBMNVjXT 23 | O+ASTrktaIrosC0Aeb5rk8WezMwBjgC6CVdxMfavaWCMNVFoWo6apy3wERvPCiNa 24 | peiG5SenMI/w967HH/IjHZ5/L6bo+l2CE2iDMUECgYB7OHE2b58pZZtcc3Khrwf0 25 | 5Kv0MacHh2HJpzdvmqDOSny+iqrgM4xrS6Rq4uRbl19vK7vLM0mw2ANAO1RSAo8G 26 | WOu+xnmd4TgRFfBXSDgzLszjk1rivWSbxQKaz8sHPKVb8MczBfK39WE6/hSh+vGg 27 | mPH8OLOeeU6euh2CN4elwA== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /zbus-dist/bin/zbus.bat: -------------------------------------------------------------------------------- 1 | ECHO OFF 2 | 3 | REM SET JAVA_HOME=D:\SDK\jdk6_x64 4 | 5 | SET ZBUS_HOME=.. 6 | SET JAVA_OPTS=-server -Dfile.encoding=UTF-8 -Xms64m -Xmx1024m -XX:+UseParallelGC 7 | SET MAIN_CLASS=io.zbus.mq.MqServer 8 | 9 | IF "%1" == "" ( 10 | SET MAIN_OPTS=-conf ../conf/zbus.xml 11 | ) ELSE ( 12 | SET MAIN_OPTS=-conf %1 13 | ) 14 | 15 | SET LIB_OPTS=%ZBUS_HOME%/lib/*;%ZBUS_HOME%/classes;%ZBUS_HOME%/*;%ZBUS_HOME%/conf; 16 | IF NOT EXIST "%JAVA_HOME%" ( 17 | SET JAVA=java 18 | ) ELSE ( 19 | SET JAVA="%JAVA_HOME%\bin\java" 20 | ) 21 | %JAVA% %JAVA_OPTS% -cp %LIB_OPTS% %MAIN_CLASS% %MAIN_OPTS% -------------------------------------------------------------------------------- /zbus-dist/bin/zbus.sh: -------------------------------------------------------------------------------- 1 | #/usr/bin 2 | #cat zbus.sh | col -b > zbus2.sh ==> fix win=>lin 3 | if [ -z ${JAVA_HOME} ]; then 4 | JAVA_HOME=/apps/jdk 5 | fi 6 | ZBUS_HOME=../ 7 | JAVA_OPTS="-Dfile.encoding=UTF-8 -server -Xms64m -Xmx1024m -XX:+UseParallelGC" 8 | MAIN_CLASS=io.zbus.mq.MqServer 9 | if [ -z "$1" ] 10 | then 11 | MAIN_OPTS="-conf ../conf/zbus.xml" 12 | else 13 | MAIN_OPTS="-conf $1" 14 | fi 15 | 16 | LIB_OPTS="$ZBUS_HOME/lib/*:$ZBUS_HOME/classes:$ZBUS_HOME/*:$ZBUS_HOME/conf/" 17 | nohup $JAVA_HOME/bin/java $JAVA_OPTS -cp $LIB_OPTS $MAIN_CLASS $MAIN_OPTS & 18 | 19 | 20 | -------------------------------------------------------------------------------- /zbus-dist/conf/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, stdout 3 | 4 | # Direct log messages to stdout 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c:%L - %m%n 9 | 10 | 11 | log4j.appender.file=org.apache.log4j.DailyRollingFileAppender 12 | log4j.appender.file.File=zbus 13 | log4j.appender.file.DatePattern='.'yyyy-MM-dd 14 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 15 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /zbus-dist/conf/ssl/zbus.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGKTCCBRGgAwIBAgIIBSse/jYPlSIwDQYJKoZIhvcNAQELBQAwgbQxCzAJBgNV 3 | BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRow 4 | GAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEtMCsGA1UECxMkaHR0cDovL2NlcnRz 5 | LmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMwMQYDVQQDEypHbyBEYWRkeSBTZWN1 6 | cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwHhcNMTgwNzA1MTU0NDEyWhcN 7 | MTkwNzA1MTU0NDEyWjA1MSEwHwYDVQQLExhEb21haW4gQ29udHJvbCBWYWxpZGF0 8 | ZWQxEDAOBgNVBAMTB3pidXMuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 9 | AoIBAQDBVvXKWPDFGY2R1dbWrR+ytGocv0ch/B2P/7KHq7zZlM8QhmDuTt5RXBJP 10 | 3BgDE10NAMM0qyljzlfuM15DtFviVnlxddE/Il85bMnfJlADXfFIXZxhRZVfvwaY 11 | aZd2/MQpf3M9mcbpVKtPpaRKXbYN7i5xzTjvl3yyjIvPGCIzDZoZ+hGIv1SlD+Lp 12 | /1lf9wF9CHBzCLoKOUNVRTEEs1Yx8TI5zLjKh5H/07bnREJ23ASbDeaIWXK/cGB7 13 | d1ojmDbJlXtng5muDt+mhSkXr6Z9cJ9DmKooueCLG+roL/XPVDKIw53nl6qULioP 14 | f/2iFE4Zlu+Mfcal8AEtDFlbrcEBAgMBAAGjggK7MIICtzAMBgNVHRMBAf8EAjAA 15 | MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNVHQ8BAf8EBAMCBaAw 16 | NwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5nb2RhZGR5LmNvbS9nZGlnMnMx 17 | LTg0NC5jcmwwXQYDVR0gBFYwVDBIBgtghkgBhv1tAQcXATA5MDcGCCsGAQUFBwIB 18 | FitodHRwOi8vY2VydGlmaWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMAgG 19 | BmeBDAECATB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw 20 | LmdvZGFkZHkuY29tLzBABggrBgEFBQcwAoY0aHR0cDovL2NlcnRpZmljYXRlcy5n 21 | b2RhZGR5LmNvbS9yZXBvc2l0b3J5L2dkaWcyLmNydDAfBgNVHSMEGDAWgBRAwr0n 22 | jsw0gzCiM9f7bLPwtCyAzjAfBgNVHREEGDAWggd6YnVzLmlvggt3d3cuemJ1cy5p 23 | bzAdBgNVHQ4EFgQUDhLd00+Ttqq2cdUs6QOyanRdbkEwggEFBgorBgEEAdZ5AgQC 24 | BIH2BIHzAPEAdwCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWRr 25 | IEw6AAAEAwBIMEYCIQD4HimLQ3jPrIT96mifEHYuiitl4t6meQxFAKZJ1RnVlwIh 26 | APugXoBXaAyy5ZvktHlrTj2OD69CcdDhlee+atYto8xLAHYAdH7agzGtMxCRIZzO 27 | JU9CcMK//V5CIAjGNzV55hB7zFYAAAFkayBNNQAABAMARzBFAiEAoPp3vWqu6dNy 28 | qIvdKDBkgzyp9R6JamhlPaSI4tOuGyoCIFw9k/p6sSZVSJQR/XNzG5sL/KItO2mE 29 | Gp5C5ke4wBi3MA0GCSqGSIb3DQEBCwUAA4IBAQBU6ccq2vdu39LmhOH7P2kXq8n2 30 | HreyYo98a7x2acxq3MPLLdWqF9zfX3+XCzZmd/GkodLa6aoNktzU6hB/kfZ+lJ3n 31 | 2fxmazhTs5g0DmIrn+C99Uh1/LbXvwx0Sbn6HwgCmjwunuHzNPWSamxZ0QjOvbBA 32 | 0S79J2WcZ1rLvUNVY/mvVOhf+RtQypkOoaP8BtPqGoU5XtfMHqpO9CbcgOAf1CFb 33 | EDCGuRt2yxis/Xz8QM/EvPr3pq1u5+aJb9yyS7wTaQNSxU6vi3gdsZTaLv1GpJS4 34 | x1oeWPFo9mtRMugjM/01kmbDUVZDNZV7mTsAMMRpkJt026AKnhLixphvj/LD 35 | -----END CERTIFICATE----- 36 | -------------------------------------------------------------------------------- /zbus-dist/conf/ssl/zbus.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBVvXKWPDFGY2R 3 | 1dbWrR+ytGocv0ch/B2P/7KHq7zZlM8QhmDuTt5RXBJP3BgDE10NAMM0qyljzlfu 4 | M15DtFviVnlxddE/Il85bMnfJlADXfFIXZxhRZVfvwaYaZd2/MQpf3M9mcbpVKtP 5 | paRKXbYN7i5xzTjvl3yyjIvPGCIzDZoZ+hGIv1SlD+Lp/1lf9wF9CHBzCLoKOUNV 6 | RTEEs1Yx8TI5zLjKh5H/07bnREJ23ASbDeaIWXK/cGB7d1ojmDbJlXtng5muDt+m 7 | hSkXr6Z9cJ9DmKooueCLG+roL/XPVDKIw53nl6qULioPf/2iFE4Zlu+Mfcal8AEt 8 | DFlbrcEBAgMBAAECggEAbn+U2qEaeouwLblZoDgx9aDHRMbNkM7W1oX9My0kMfaq 9 | oXcrzwekaDuG+71+u8NFWzkkV+W7Mh+sgac6KNfb6/AgWIhNnxe19MwIVFFBSatX 10 | S1S1G6L5TE+RJWqz9n1gX5dH9dz9oj2R62NwElCczDlksgXolIav7hwFi8bvRN1x 11 | NYWXoVGrfhR/PITCZE0/hY2IAkxfe/9nZ3Mmgl8hlU9hEVkDMPSk+0CcrQvSWy0b 12 | a+h5mYcbnSqH6yfNL9APYH8rurhHrvkbm0+VmGy8m7gY6U3jN3MSwHRQ7EQKwggk 13 | JqhL4Uzh9T+jHCa4gTlu5VQvxv8MVUTtZyZhMCC5QQKBgQD6OkxgCHpBt/VdiNlo 14 | EH+/NjjjOEyQaTQEF4LJafM3CMorecreNid37nwWbrVifFvBZJDLaAQKj9xhy5Ht 15 | X4934g1BIlGoIWY3gKu+Nd/zbGUsbr1WZwvBbncG9ybLjnq875CPwo9Nt/bn3BX3 16 | iCxvkHm0CqVCXPJr5u26khD5zwKBgQDFzLauEFYLteEgxBZP8yw3Gm7KCC7dIfUm 17 | CvJQ7iZXcr3khFcCpQ2bi3QdQs6GCnh0CGxyRL52Q3BPdiifBFqMfOvENWuqo0o2 18 | D3bh6jc5Z/Mj3hr+3FHdlYrawHLBAydHIXriVkq4DDY3n0fDjx77veldALSgJCEa 19 | 7rgZAH7cLwKBgCgg3UqxUVnktHaxkZv8uV/ixDC8QJsQJAVb999xHE4BHNroBz6n 20 | lKDJICFA09ndc6GKDSZxoeRHueH9EYPtxUZGfDWr2UiLQqc3/VLdtPKGuZrsj3Sh 21 | xeLZYkE9tX0Ddm+CQ76qRu0ByZjZVLSDpAyoMLxM0L/ZxA7F0+4NqqdFAoGAYyI8 22 | lHSfi3L2iAN+40cO6/cVe7AqPK4ePZjS5XjWQpHBVlx1d1/duA1mfpvTAh8RS6ZF 23 | I+gMRR17lnez2C7IawzY5ReZBIaeVQXfIU7PqrfMhjd09DLb3OBsHULCwLWh4+aF 24 | vhZdkGyeZ7Yus3Zxot4FrZUC8hfpd6QZJH65FgUCgYEA3VmNjbdfQEat4IdhlhK2 25 | eBAS9JepzdQJhABe1A/0fz792hWp4kci+EUuoDpq8hYgWTssxqLIkxmrMkI0nKU9 26 | GkEu0nUaPW/b1388xBUPiDEmbm9oQ5bcpNgtujMsA2klYFe75yE2p7UOet5hKNBM 27 | i7NfnPXLfr0ssNg5iGFe4+Q= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /zbus-dist/conf/zbus.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
0.0.0.0:80
7 | false 8 | 9 | 10 | 11 | 12 | 2ba912a8-4a8d-49d2-1a22-198fd285cb06 13 | 461277322-943d-4b2f-b9b6-3f860d746ffd 14 | 15 | 16 | 3ba912a6-4a8d-49d1-1a66-198ea285cb03 17 | 123475622-953d-4b2f-a7b6-4f860d126cce 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 |
0.0.0.0:15555
26 |
27 | 28 | 29 | 30 |
0.0.0.0:25555
31 | 43 |
44 | 45 | 46 | 47 | /tmp/zbus 48 | 49 | 102400 50 | 128M 51 | true 52 |
53 | 54 | -------------------------------------------------------------------------------- /zbus-dist/lib/fastjson-1.2.46.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushmore/zbus-server/b27bb689599066a8b81f3609a5ce4c903a413b99/zbus-dist/lib/fastjson-1.2.46.jar -------------------------------------------------------------------------------- /zbus-dist/lib/log4j-1.2.16.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushmore/zbus-server/b27bb689599066a8b81f3609a5ce4c903a413b99/zbus-dist/lib/log4j-1.2.16.jar -------------------------------------------------------------------------------- /zbus-dist/lib/netty-all-4.1.22.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushmore/zbus-server/b27bb689599066a8b81f3609a5ce4c903a413b99/zbus-dist/lib/netty-all-4.1.22.Final.jar -------------------------------------------------------------------------------- /zbus-dist/lib/slf4j-api-1.7.21.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushmore/zbus-server/b27bb689599066a8b81f3609a5ce4c903a413b99/zbus-dist/lib/slf4j-api-1.7.21.jar -------------------------------------------------------------------------------- /zbus-dist/lib/slf4j-log4j12-1.7.21.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushmore/zbus-server/b27bb689599066a8b81f3609a5ce4c903a413b99/zbus-dist/lib/slf4j-log4j12-1.7.21.jar -------------------------------------------------------------------------------- /zbus-dist/lib/zbus-1.0.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushmore/zbus-server/b27bb689599066a8b81f3609a5ce4c903a413b99/zbus-dist/lib/zbus-1.0.0-SNAPSHOT.jar --------------------------------------------------------------------------------