├── .editorconfig ├── .gitignore ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main └── java │ └── ng │ └── abdlquadri │ └── eventbus │ ├── EventBus.java │ ├── EventBusFrameHandler.java │ ├── EventBusInitializer.java │ ├── EventBusUtil.java │ ├── handlers │ ├── ConnectHandler.java │ ├── Handler.java │ └── WriteHandler.java │ ├── senders │ └── ReplySender.java │ └── util │ └── EventBusMessageAttributes.java └── test └── java └── ng └── abdlquadri ├── TestAttributes.java ├── eventbus └── EventBusBridgeTest.java └── server └── TCPBridgedChatServer.java /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | end_of_line = lf 9 | insert_final_newline = true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | build/ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vertx-eventbus-java 2 | 3 | 4 | A [Vert.x EventBus](http://vertx.io/docs/vertx-core/java/#event_bus) client written in Java uses [Netty](http://netty.io/), works on Android 2.3.7 +: 5 | 6 | # Testing 7 | `./gradlew test` 8 | 9 | # Building 10 | 11 | `./gradlew build` . The jar file will be in build/libs. 12 | 13 | # Dependencies 14 | 15 | ```java 16 | compile "io.netty:netty-handler:4.1.0.Beta8" 17 | compile "org.sharegov:mjson:1.3" 18 | ``` 19 | 20 | # Sample projects 21 | * Sample Android Chat app [Vertx Event Bus Chat](https://github.com/abdlquadri/VertxEventBusChat). 22 | * Sample Vert.x Server bridged to TCP [vertx-tcp-bridged-chat-server](https://github.com/abdlquadri/vertx-tcp-bridged-chat-server). 23 | 24 | # Usage 25 | ```java 26 | final CountDownLatch countDownLatch = new CountDownLatch(1); 27 | EventBus.connect("127.0.0.1", 7000, new ConnectHandler() { 28 | @Override 29 | public void connected(boolean isConnected) { 30 | if (isConnected) { 31 | assertTrue(isConnected); 32 | } else { 33 | assertFalse(isConnected); 34 | } 35 | countDownLatch.countDown(); 36 | } 37 | }); 38 | countDownLatch.await(); 39 | ``` 40 | 41 | 42 | ```java 43 | final CountDownLatch countDownLatch = new CountDownLatch(1); 44 | EventBus.registerHandler("hello", new Handler() { 45 | @Override 46 | public void handle(String message) { 47 | 48 | assertEquals("some messgae", Json.read(message).at("body").at("value").asString()); 49 | countDownLatch.countDown(); 50 | } 51 | }); 52 | 53 | EventBus.publish("hello", Json.object().set("value", "some messgae").toString()); 54 | countDownLatch.await(); 55 | ``` 56 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | group 'ng.abdlquadri' 2 | version '1.1' 3 | 4 | apply plugin: 'java' 5 | 6 | project.sourceCompatibility = 1.5 7 | 8 | compileTestJava { 9 | project.sourceCompatibility = 1.8 10 | } 11 | 12 | repositories { 13 | mavenCentral() 14 | jcenter() 15 | maven { 16 | url = 'https://oss.sonatype.org/content/repositories/snapshots/' 17 | } 18 | } 19 | 20 | dependencies { 21 | compile "io.netty:netty-handler:4.1.0.Beta8" 22 | compile "org.sharegov:mjson:1.3" 23 | 24 | 25 | testCompile group: 'junit', name: 'junit', version: '4.11' 26 | testCompile group: 'io.vertx', name: 'vertx-core', version: '3.3.3' 27 | testCompile group: 'io.vertx', name: 'vertx-tcp-eventbus-bridge', version: '3.3.3' 28 | } 29 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abdlquadri/vertx-eventbus-java/84a53aa8348039214e591873949d4fc447b4383b/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Dec 09 13:34:46 WAT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'vertx-eventbus-java' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/ng/abdlquadri/eventbus/EventBus.java: -------------------------------------------------------------------------------- 1 | package ng.abdlquadri.eventbus; 2 | 3 | import static ng.abdlquadri.eventbus.EventBusUtil.addHandler; 4 | import static ng.abdlquadri.eventbus.EventBusUtil.addReplyHandler; 5 | import static ng.abdlquadri.eventbus.EventBusUtil.writeToWire; 6 | 7 | import java.net.InetSocketAddress; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.UUID; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | import java.util.concurrent.ConcurrentMap; 13 | import java.util.logging.Level; 14 | import java.util.logging.Logger; 15 | 16 | import io.netty.bootstrap.Bootstrap; 17 | import io.netty.channel.Channel; 18 | import io.netty.channel.ChannelFuture; 19 | import io.netty.channel.ChannelFutureListener; 20 | import io.netty.channel.nio.NioEventLoopGroup; 21 | import io.netty.channel.socket.nio.NioSocketChannel; 22 | 23 | import mjson.Json; 24 | 25 | import ng.abdlquadri.eventbus.handlers.ConnectHandler; 26 | import ng.abdlquadri.eventbus.handlers.Handler; 27 | import ng.abdlquadri.eventbus.handlers.WriteHandler; 28 | import ng.abdlquadri.eventbus.senders.ReplySender; 29 | import ng.abdlquadri.eventbus.util.EventBusMessageAttributes; 30 | 31 | /** 32 | * Created by abdlquadri on 12/9/15. 33 | */ 34 | public class EventBus { 35 | private static Logger log = Logger.getLogger(EventBus.class.getName()); 36 | 37 | public static Channel channel; 38 | public static final ConcurrentMap> handlers = new ConcurrentHashMap>(); 39 | public static final ConcurrentMap replyHandlers = new ConcurrentHashMap(); 40 | protected static HashMap replySenders = new HashMap(); 41 | public static ConnectHandler globalConnectHandler; 42 | 43 | private EventBus() { 44 | } 45 | 46 | public static void send(String address, String jsonMessage, String jsonHeaders, Handler handler) { 47 | String replyAddress = UUID.randomUUID().toString(); 48 | log.log(Level.INFO, "Making a SEND to EventBus Server"); 49 | 50 | Json json = Json.object().set(EventBusMessageAttributes.TYPE, "send") 51 | .set(EventBusMessageAttributes.ADDRESS, address) 52 | .set(EventBusMessageAttributes.REPLY_ADDRESS, replyAddress) 53 | .set(EventBusMessageAttributes.HEADERS, Json.read(jsonHeaders)) 54 | .set(EventBusMessageAttributes.BODY, Json.read(jsonMessage)); 55 | addReplyHandler(replyAddress, handler); 56 | writeToWire(channel, json.toString(), new WriteHandler() { 57 | @Override 58 | public void written(boolean isWritten) { 59 | log.log(Level.INFO, "Done Making a SEND to EventBus Server"); 60 | } 61 | }); 62 | } 63 | 64 | public static void send(String address, String jsonMessage, Handler handler) { 65 | String replyAddress = UUID.randomUUID().toString(); 66 | Json json = Json.object().set(EventBusMessageAttributes.TYPE, "send") 67 | .set(EventBusMessageAttributes.ADDRESS, address) 68 | .set(EventBusMessageAttributes.REPLY_ADDRESS, replyAddress) 69 | .set(EventBusMessageAttributes.HEADERS, Json.object()) 70 | .set(EventBusMessageAttributes.BODY, Json.read(jsonMessage)); 71 | addReplyHandler(replyAddress, handler); 72 | writeToWire(channel, json.toString(), new WriteHandler() { 73 | @Override 74 | public void written(boolean isWritten) { 75 | 76 | } 77 | }); 78 | } 79 | 80 | public static void send(String address, String jsonMessage, String jsonHeaders) { 81 | log.log(Level.INFO, "Making a SEND to EventBus Server"); 82 | 83 | Json json = Json.object().set(EventBusMessageAttributes.TYPE, "send") 84 | .set(EventBusMessageAttributes.ADDRESS, address) 85 | .set(EventBusMessageAttributes.HEADERS, Json.read(jsonHeaders)) 86 | .set(EventBusMessageAttributes.BODY, Json.read(jsonMessage)); 87 | writeToWire(channel, json.toString(), new WriteHandler() { 88 | @Override 89 | public void written(boolean isWritten) { 90 | log.log(Level.INFO, "Done Making a SEND to EventBus Server"); 91 | 92 | } 93 | }); 94 | } 95 | 96 | public static void publish(String address, String jsonMessage, String jsonHeaders) { 97 | log.log(Level.INFO, "Making a PUBLISH to EventBus Server"); 98 | Json json = Json.object().set(EventBusMessageAttributes.TYPE, "publish") 99 | .set(EventBusMessageAttributes.ADDRESS, address) 100 | .set(EventBusMessageAttributes.HEADERS, Json.read(jsonHeaders)) 101 | .set(EventBusMessageAttributes.BODY, Json.read(jsonMessage)); 102 | writeToWire(channel, json.toString(), new WriteHandler() { 103 | @Override 104 | public void written(boolean isWritten) { 105 | log.log(Level.INFO, "Done Making a PUBLISH to EventBus Server"); 106 | 107 | } 108 | }); 109 | } 110 | 111 | public static void send(String address, String jsonMessage) { 112 | Json json = Json.object().set(EventBusMessageAttributes.TYPE, "send") 113 | .set(EventBusMessageAttributes.ADDRESS, address) 114 | .set(EventBusMessageAttributes.HEADERS, Json.object()) 115 | .set(EventBusMessageAttributes.BODY, Json.read(jsonMessage)); 116 | writeToWire(channel, json.toString(), new WriteHandler() { 117 | @Override 118 | public void written(boolean isWritten) { 119 | 120 | } 121 | }); 122 | } 123 | 124 | public static void publish(String address, String jsonMessage) { 125 | Json json = Json.object().set(EventBusMessageAttributes.TYPE, "publish") 126 | .set(EventBusMessageAttributes.ADDRESS, address) 127 | .set(EventBusMessageAttributes.HEADERS, Json.object()) 128 | .set(EventBusMessageAttributes.BODY, Json.read(jsonMessage)); 129 | writeToWire(channel, json.toString(), new WriteHandler() { 130 | @Override 131 | public void written(boolean isWritten) { 132 | 133 | } 134 | }); 135 | } 136 | 137 | 138 | public static void registerHandler(String address, String jsonHeaders, Handler handler) { 139 | Json json = Json.object().set(EventBusMessageAttributes.TYPE, "register") 140 | .set(EventBusMessageAttributes.ADDRESS, address) 141 | .set(EventBusMessageAttributes.HEADERS, Json.read(jsonHeaders)); 142 | 143 | addHandler(address, handler); 144 | 145 | writeToWire(channel, json.toString(), new WriteHandler() { 146 | @Override 147 | public void written(boolean isWritten) { 148 | 149 | } 150 | }); 151 | } 152 | 153 | public static void registerHandler(String address, Handler handler) { 154 | Json json = Json.object().set(EventBusMessageAttributes.TYPE, "register") 155 | .set(EventBusMessageAttributes.ADDRESS, address) 156 | .set(EventBusMessageAttributes.HEADERS, Json.object()); 157 | 158 | addHandler(address, handler); 159 | 160 | writeToWire(channel, json.toString(), new WriteHandler() { 161 | @Override 162 | public void written(boolean isWritten) { 163 | 164 | } 165 | }); 166 | } 167 | 168 | public static void unregisterHandler(String address, String jsonHeaders) { 169 | Json json = Json.object().set(EventBusMessageAttributes.TYPE, "unregister") 170 | .set(EventBusMessageAttributes.ADDRESS, address) 171 | .set(EventBusMessageAttributes.HEADERS, Json.read(jsonHeaders)); 172 | 173 | handlers.remove(address); 174 | writeToWire(channel, json.toString(), new WriteHandler() { 175 | @Override 176 | public void written(boolean isWritten) { 177 | 178 | } 179 | }); 180 | } 181 | 182 | public static void unregisterHandler(String address) { 183 | Json json = Json.object().set(EventBusMessageAttributes.TYPE, "unregister") 184 | .set(EventBusMessageAttributes.ADDRESS, address) 185 | .set(EventBusMessageAttributes.HEADERS, Json.object()); 186 | 187 | handlers.remove(address); 188 | writeToWire(channel, json.toString(), new WriteHandler() { 189 | @Override 190 | public void written(boolean isWritten) { 191 | 192 | } 193 | }); 194 | } 195 | 196 | 197 | public static void connect(String host, int port, final ConnectHandler connectHandler) { 198 | log.log(Level.INFO, "Connecting to EventBus Server"); 199 | NioEventLoopGroup group = new NioEventLoopGroup(); 200 | 201 | Bootstrap bootstrap = new Bootstrap(); 202 | 203 | bootstrap.group(group) 204 | .channel(NioSocketChannel.class) 205 | .remoteAddress(new InetSocketAddress(host, port)) 206 | .handler(new EventBusInitializer()); 207 | 208 | final ChannelFuture channelFuture = bootstrap.connect(); 209 | channelFuture.addListener(new ChannelFutureListener() { 210 | @Override 211 | public void operationComplete(ChannelFuture future) throws Exception { 212 | if (future.isSuccess() && channelFuture.isDone() && channelFuture.channel().isActive()) { 213 | channel = future.channel(); 214 | globalConnectHandler = connectHandler; 215 | connectHandler.onConnect(channelFuture.channel().isActive()); 216 | log.log(Level.INFO, "Done Connecting to EventBus Server"); 217 | 218 | } else { 219 | connectHandler.onConnect(false); 220 | log.log(Level.SEVERE, "Failed Connecting to EventBus Server"); 221 | 222 | } 223 | 224 | } 225 | }); 226 | 227 | } 228 | 229 | public static void close() { 230 | if (channel != null) { 231 | final ChannelFuture closeFuture = channel.close(); 232 | closeFuture.addListener(new ChannelFutureListener() { 233 | public void operationComplete(ChannelFuture future) throws Exception { 234 | if (future.isSuccess() && future.isDone()){ 235 | log.log(Level.SEVERE, "Channel Successful Closed"); 236 | 237 | }else { 238 | log.log(Level.SEVERE, "Channel Failed Closed {1}", future.cause()); 239 | 240 | } 241 | } 242 | }); 243 | } else { 244 | log.log(Level.SEVERE, "Channel is not connected. You can not close a non existent connection :). Make sure the server is reachable and call EventBus.connect() method first."); 245 | throw new IllegalStateException("Channel is not connected. You can not close a non existent connection :). Make sure the server is reachable and call EventBus.connect() method first."); 246 | 247 | } 248 | } 249 | 250 | 251 | } 252 | -------------------------------------------------------------------------------- /src/main/java/ng/abdlquadri/eventbus/EventBusFrameHandler.java: -------------------------------------------------------------------------------- 1 | package ng.abdlquadri.eventbus; 2 | 3 | import static ng.abdlquadri.eventbus.EventBus.channel; 4 | import static ng.abdlquadri.eventbus.EventBus.globalConnectHandler; 5 | import static ng.abdlquadri.eventbus.EventBus.handlers; 6 | import static ng.abdlquadri.eventbus.EventBus.replyHandlers; 7 | import static ng.abdlquadri.eventbus.EventBusUtil.addReplySender; 8 | import static ng.abdlquadri.eventbus.EventBusUtil.sendPing; 9 | 10 | import java.util.List; 11 | import java.util.concurrent.TimeUnit; 12 | import java.util.logging.Level; 13 | import java.util.logging.Logger; 14 | 15 | import io.netty.buffer.ByteBuf; 16 | import io.netty.channel.ChannelHandlerContext; 17 | import io.netty.channel.SimpleChannelInboundHandler; 18 | 19 | import mjson.Json; 20 | 21 | import ng.abdlquadri.eventbus.handlers.Handler; 22 | import ng.abdlquadri.eventbus.senders.ReplySender; 23 | 24 | /** 25 | * Created by abdlquadri on 12/9/15. 26 | */ 27 | public class EventBusFrameHandler extends SimpleChannelInboundHandler { 28 | private Logger log = Logger.getLogger(EventBusFrameHandler.class.getName()); 29 | 30 | @Override 31 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 32 | log.log(Level.INFO, "CHANNEL IS ACTIVE"); 33 | if (channel.isActive()) { 34 | sendPing(channel); 35 | } 36 | ctx.channel().eventLoop().scheduleAtFixedRate(new Runnable() { 37 | @Override 38 | public void run() { 39 | if (channel.isActive()) { 40 | sendPing(channel); 41 | } 42 | } 43 | }, 5, 5, TimeUnit.SECONDS); 44 | 45 | } 46 | 47 | @Override 48 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 49 | log.log(Level.SEVERE, "CHANNEL NOT ACTIVE"); 50 | globalConnectHandler.onDisConnect(new IllegalStateException("You are disconnected from the EventBus")); 51 | 52 | } 53 | 54 | @Override 55 | protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { 56 | ByteBuf inMsg = (ByteBuf) msg; 57 | String eventBusMessage = messageBufferToString(inMsg); 58 | Json json = Json.read(eventBusMessage); 59 | final Json replyAddress = json.at("replyAddress"); 60 | Json address = json.at("address"); 61 | Json type = json.at("type"); 62 | if (replyAddress != null) { 63 | addReplySender(replyAddress.toString(), new ReplySender() { 64 | @Override 65 | public void send(String replyMessage) { 66 | EventBus.send(replyAddress.toString(), replyMessage); 67 | 68 | } 69 | 70 | @Override 71 | public void send(String replyMessage, String headers) { 72 | EventBus.send(replyAddress.toString(), replyMessage, headers); 73 | 74 | } 75 | 76 | @Override 77 | public void send(String replyMessage, String headers, Handler handler) { 78 | EventBus.send(replyAddress.toString(), replyMessage, headers, handler); 79 | } 80 | }); 81 | } 82 | 83 | if (address != null) { 84 | String stAddress = address.asString(); 85 | if (handlers.containsKey(stAddress)) { 86 | List messageHandlers = handlers.get(stAddress); 87 | for (Handler h : messageHandlers) { 88 | 89 | h.handle(eventBusMessage); 90 | 91 | } 92 | } else if (replyHandlers.containsKey(stAddress)) { 93 | Handler replyMessageHandlers = replyHandlers.get(stAddress); 94 | replyMessageHandlers.handle(eventBusMessage); 95 | replyHandlers.remove(stAddress); 96 | } else { 97 | if ("err".equals(type.toString())) { 98 | //TODO what do we do? 99 | log.log(Level.WARNING, json.toString()); 100 | 101 | } else { 102 | log.log(Level.SEVERE, json.toString()); 103 | 104 | } 105 | } 106 | } 107 | //TODO should we really leave the connection opened 108 | //TODO ctx.close(); 109 | } 110 | 111 | private String messageBufferToString(ByteBuf inMsg) { 112 | int messageLength = inMsg.readInt(); 113 | StringBuilder message = new StringBuilder(); 114 | for (int i = 0; i < messageLength; i++) { 115 | char c = (char) inMsg.readByte(); 116 | message.append(c); 117 | } 118 | return message.toString(); 119 | } 120 | 121 | @Override 122 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 123 | log.log(Level.WARNING, cause.getMessage()); 124 | ctx.close(); 125 | } 126 | 127 | 128 | } 129 | 130 | 131 | -------------------------------------------------------------------------------- /src/main/java/ng/abdlquadri/eventbus/EventBusInitializer.java: -------------------------------------------------------------------------------- 1 | package ng.abdlquadri.eventbus; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.ChannelPipeline; 6 | import io.netty.handler.codec.LengthFieldBasedFrameDecoder; 7 | 8 | /** 9 | * Created by abdlquadri on 12/9/15. 10 | */ 11 | public class EventBusInitializer extends ChannelInitializer { 12 | @Override 13 | protected void initChannel(Channel ch) throws Exception { 14 | ChannelPipeline pipeline = ch.pipeline(); 15 | pipeline.addLast(new LengthFieldBasedFrameDecoder(65 * 1024, 0, 4)); 16 | pipeline.addLast(new EventBusFrameHandler()); 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/ng/abdlquadri/eventbus/EventBusUtil.java: -------------------------------------------------------------------------------- 1 | package ng.abdlquadri.eventbus; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | 8 | import io.netty.buffer.ByteBuf; 9 | import io.netty.buffer.Unpooled; 10 | import io.netty.channel.Channel; 11 | import io.netty.channel.ChannelFuture; 12 | import io.netty.channel.ChannelFutureListener; 13 | 14 | import mjson.Json; 15 | 16 | import ng.abdlquadri.eventbus.handlers.Handler; 17 | import ng.abdlquadri.eventbus.handlers.WriteHandler; 18 | import ng.abdlquadri.eventbus.senders.ReplySender; 19 | 20 | /** 21 | * Created by abdlquadri on 12/19/15. 22 | */ 23 | public class EventBusUtil { 24 | private static Logger log = Logger.getLogger(EventBusUtil.class.getName()); 25 | 26 | private EventBusUtil() { 27 | } 28 | 29 | public static void sendPing(Channel channel) { 30 | 31 | String msg = Json.object() 32 | .set("type", "ping").toString(); 33 | log.log(Level.INFO, "Sending Ping to Server."); 34 | writeToWire(channel, msg, new WriteHandler() { 35 | @Override 36 | public void written(boolean isWritten) { 37 | log.log(Level.INFO, "Done Sending Ping to Server."); 38 | } 39 | }); 40 | } 41 | 42 | public static void writeToWire(final Channel channel, String jsonObject, final WriteHandler writeHandler) { 43 | int length = jsonObject.length(); 44 | ByteBuf buffer = Unpooled.buffer() 45 | .writeInt(length) 46 | .writeBytes(jsonObject.getBytes()); 47 | log.log(Level.INFO, "Writing to wire."); 48 | 49 | if (channel != null) { 50 | final ChannelFuture channelFuture = channel.writeAndFlush(buffer); 51 | channelFuture.addListener(new ChannelFutureListener() { 52 | @Override 53 | public void operationComplete(ChannelFuture future) throws Exception { 54 | 55 | if (future.isDone() && future.isSuccess()) { 56 | writeHandler.written(true); 57 | log.log(Level.INFO, "Done Writing to wire."); 58 | } else { 59 | writeHandler.written(false); 60 | log.log(Level.SEVERE, "Failed Writing to wire."); 61 | } 62 | 63 | } 64 | }); 65 | } else { 66 | throw new IllegalStateException("Channel is not connected. Make sure the server is reachable and call EventBus" + 67 | ".connect() method first."); 68 | } 69 | } 70 | 71 | public static void addHandler(String address, Handler handler) { 72 | List handlers = EventBus.handlers.get(address); 73 | log.log(Level.INFO, "Adding Handlers to Eventbus."); 74 | if (handlers == null) { 75 | 76 | handlers = new ArrayList(); 77 | handlers.add(handler); 78 | 79 | EventBus.handlers.put(address, handlers); 80 | log.log(Level.INFO, "Done Adding Handlers to Eventbus. # of Current Hanlders {1}", handlers.size()); 81 | 82 | } else { 83 | 84 | if (EventBus.handlers.containsKey(address)) { 85 | EventBus.handlers.put(address, handlers); 86 | } 87 | log.log(Level.INFO, "Replaced Handler on Eventbus. # of Current Hanlders {1}", handlers.size()); 88 | } 89 | 90 | } 91 | 92 | public static void addReplyHandler(String address, Handler handler) { 93 | log.log(Level.INFO, "Adding ReplyHandlers for Eventbus Address {1}", address); 94 | if (!EventBus.replyHandlers.containsKey(address)) { 95 | EventBus.replyHandlers.put(address, handler); 96 | } 97 | log.log(Level.INFO, "Done Adding ReplyHandlers for Eventbus Address {1}", address); 98 | } 99 | 100 | public static void addReplySender(String address, ReplySender sender) { 101 | log.log(Level.INFO, "Adding ReplySenders for Eventbus Address {1}", address); 102 | if (!EventBus.replySenders.containsKey(address)) { 103 | EventBus.replySenders.put(address, sender); 104 | } 105 | log.log(Level.INFO, "Done Adding ReplySenders for Eventbus Address {1}", address); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/ng/abdlquadri/eventbus/handlers/ConnectHandler.java: -------------------------------------------------------------------------------- 1 | package ng.abdlquadri.eventbus.handlers; 2 | 3 | /** 4 | * Created by abdlquadri on 12/20/15. 5 | */ 6 | public interface ConnectHandler { 7 | public void onConnect(boolean isConnected); 8 | public void onDisConnect(Throwable cause); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/ng/abdlquadri/eventbus/handlers/Handler.java: -------------------------------------------------------------------------------- 1 | package ng.abdlquadri.eventbus.handlers; 2 | 3 | /** 4 | * Created by abdlquadri on 12/18/15. 5 | */ 6 | public interface Handler { 7 | public void handle(String message); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/ng/abdlquadri/eventbus/handlers/WriteHandler.java: -------------------------------------------------------------------------------- 1 | package ng.abdlquadri.eventbus.handlers; 2 | 3 | /** 4 | * Created by abdlquadri on 12/21/15. 5 | */ 6 | public interface WriteHandler { 7 | public void written(boolean isWritten); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/ng/abdlquadri/eventbus/senders/ReplySender.java: -------------------------------------------------------------------------------- 1 | package ng.abdlquadri.eventbus.senders; 2 | 3 | import ng.abdlquadri.eventbus.handlers.Handler; 4 | 5 | /** 6 | * Created by abdlquadri on 12/20/15. 7 | */ 8 | public interface ReplySender { 9 | void send(String replyMessage); 10 | 11 | void send(String replyMessage, String headers); 12 | 13 | void send(String replyMessage, String headers, Handler handler); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ng/abdlquadri/eventbus/util/EventBusMessageAttributes.java: -------------------------------------------------------------------------------- 1 | package ng.abdlquadri.eventbus.util; 2 | 3 | /** 4 | * Created by abdlquadri on 1/5/17. 5 | */ 6 | public class EventBusMessageAttributes { 7 | public static final String ADDRESS = "address"; 8 | public static final String REPLY_ADDRESS = "replyAddress"; 9 | public static final String HEADERS = "headers"; 10 | public static final String BODY = "body"; 11 | public static final String TYPE = "type"; 12 | 13 | private EventBusMessageAttributes() { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/ng/abdlquadri/TestAttributes.java: -------------------------------------------------------------------------------- 1 | package ng.abdlquadri; 2 | 3 | /** 4 | * Created by abdlquadri on 2/28/17. 5 | */ 6 | public class TestAttributes { 7 | 8 | public static final String SERVER = "127.0.0.1"; 9 | public static final int PORT = 7171; 10 | 11 | public static final String HELLO_ADDRESS = "hello"; 12 | public static final String PUBLISH_ADDRESS = "publish"; 13 | public static final String PING_PONG_ADDRESS = "ping-pong"; 14 | public static final String INTERNAL_HELLO_ADDRESS = "internal-hello"; 15 | 16 | 17 | private TestAttributes() { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/ng/abdlquadri/eventbus/EventBusBridgeTest.java: -------------------------------------------------------------------------------- 1 | package ng.abdlquadri.eventbus; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertFalse; 5 | import static org.junit.Assert.assertTrue; 6 | 7 | import java.util.concurrent.CountDownLatch; 8 | 9 | import io.vertx.core.AsyncResult; 10 | import io.vertx.core.Vertx; 11 | 12 | import org.junit.AfterClass; 13 | import org.junit.BeforeClass; 14 | import org.junit.Test; 15 | 16 | import mjson.Json; 17 | 18 | import ng.abdlquadri.TestAttributes; 19 | import ng.abdlquadri.eventbus.handlers.ConnectHandler; 20 | import ng.abdlquadri.eventbus.handlers.Handler; 21 | import ng.abdlquadri.server.TCPBridgedChatServer; 22 | 23 | 24 | /** 25 | * Created by user on 11/22/15. 26 | */ 27 | public class EventBusBridgeTest { 28 | 29 | @BeforeClass 30 | public static void createServer() throws InterruptedException { 31 | final CountDownLatch countDownLatch = new CountDownLatch(1); 32 | Vertx.vertx().deployVerticle(new TCPBridgedChatServer(), new io.vertx.core.Handler>() { 33 | @Override 34 | public void handle(AsyncResult result) { 35 | assertTrue(result.succeeded()); 36 | countDownLatch.countDown(); 37 | } 38 | }); 39 | countDownLatch.await(); 40 | 41 | final CountDownLatch countDownLatch1 = new CountDownLatch(1); 42 | EventBus.connect(TestAttributes.SERVER, TestAttributes.PORT, new ConnectHandler() { 43 | public void onConnect(boolean isConnected) { 44 | if (isConnected) { 45 | assertTrue(isConnected); 46 | } else { 47 | assertFalse(isConnected); 48 | } 49 | countDownLatch1.countDown(); 50 | } 51 | 52 | public void onDisConnect(Throwable cause) { 53 | cause.printStackTrace(); 54 | } 55 | 56 | }); 57 | countDownLatch1.await(); 58 | } 59 | 60 | @AfterClass 61 | public static void stopServer() { 62 | EventBus.close(); 63 | } 64 | 65 | 66 | @Test 67 | public void testSend() throws InterruptedException { 68 | 69 | EventBus.send(TestAttributes.HELLO_ADDRESS, Json.object().set("value", "from send Bridge").toString()); 70 | } 71 | 72 | @Test 73 | public void testSendWithReply() throws InterruptedException { 74 | final CountDownLatch countDownLatch = new CountDownLatch(1); 75 | EventBus.send(TestAttributes.HELLO_ADDRESS, Json.object().set("value", "from sendW Bridge").toString(), new Handler() { 76 | @Override 77 | public void handle(String message) { 78 | String value = Json.read(message).at("body").at("value").asString(); 79 | assertEquals("Hello from sendW Bridge", value); 80 | countDownLatch.countDown(); 81 | } 82 | }); 83 | countDownLatch.await(); 84 | } 85 | 86 | @Test 87 | public void testRegister() throws InterruptedException { 88 | final CountDownLatch countDownLatch = new CountDownLatch(1); 89 | EventBus.registerHandler(TestAttributes.HELLO_ADDRESS, new Handler() { 90 | @Override 91 | public void handle(String message) { 92 | System.out.println("TEST " + message); 93 | assertEquals("some messgae", Json.read(message).at("body").at("value").asString()); 94 | countDownLatch.countDown(); 95 | } 96 | }); 97 | 98 | EventBus.publish(TestAttributes.HELLO_ADDRESS, Json.object().set("value", "some messgae").toString()); 99 | countDownLatch.await(); 100 | } 101 | 102 | //{"type":"err","message":"access_denied"} 103 | // @Test 104 | // public void testAccessDenied() throws InterruptedException { 105 | // EventBus.send("holla", Json.object().set("value", "from send Bridge").toString()); 106 | // 107 | // } 108 | 109 | 110 | //{"failureCode":-1,"failureType":"TIMEOUT","type":"message","message":"Timed out waiting for a reply"} 111 | // @Test 112 | // public void testReplyTimeout() throws InterruptedException { 113 | // final CountDownLatch countDownLatch = new CountDownLatch(1); 114 | // EventBus.send("hellonoreply", Json.object().set("value", "from sendW Bridge").toString(), new Handler() { 115 | // @Override 116 | // public void handle(String message) { 117 | // String value = Json.read(message).at("body").at("value").asString(); 118 | // assertEquals("Hello from sendW Bridge", value); 119 | // countDownLatch.countDown(); 120 | // } 121 | // }); 122 | // countDownLatch.await(); 123 | // } 124 | 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/test/java/ng/abdlquadri/server/TCPBridgedChatServer.java: -------------------------------------------------------------------------------- 1 | package ng.abdlquadri.server; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.AsyncResult; 5 | import io.vertx.core.Future; 6 | import io.vertx.core.Handler; 7 | import io.vertx.core.eventbus.Message; 8 | import io.vertx.core.json.JsonObject; 9 | import io.vertx.core.logging.Logger; 10 | import io.vertx.core.logging.LoggerFactory; 11 | import io.vertx.ext.bridge.BridgeOptions; 12 | import io.vertx.ext.bridge.PermittedOptions; 13 | import io.vertx.ext.eventbus.bridge.tcp.TcpEventBusBridge; 14 | 15 | import ng.abdlquadri.TestAttributes; 16 | 17 | public class TCPBridgedChatServer extends AbstractVerticle { 18 | Logger logger = LoggerFactory.getLogger(getClass()); 19 | 20 | @Override 21 | public void start(Future startFuture) throws Exception { 22 | 23 | vertx.eventBus().consumer(TestAttributes.PUBLISH_ADDRESS); 24 | 25 | vertx.eventBus().consumer(TestAttributes.HELLO_ADDRESS, new Handler>() { 26 | @Override 27 | public void handle(Message message) { 28 | message.reply(new JsonObject().put("value", "Hello " + message.body().getString("value"))); 29 | } 30 | }); 31 | 32 | TcpEventBusBridge bridge = TcpEventBusBridge.create(vertx, new BridgeOptions() 33 | .addInboundPermitted(new PermittedOptions().setAddress(TestAttributes.HELLO_ADDRESS)) 34 | .addOutboundPermitted(new PermittedOptions().setAddress(TestAttributes.HELLO_ADDRESS)) 35 | ); 36 | 37 | 38 | bridge.listen(TestAttributes.PORT, new Handler>() { 39 | @Override 40 | public void handle(AsyncResult res) { 41 | System.out.println("Ready"); 42 | 43 | startFuture.complete(); 44 | } 45 | }); 46 | } 47 | } 48 | --------------------------------------------------------------------------------