From 90b600e02bb96a6e2aae6de0ce67659577ba5f7b Mon Sep 17 00:00:00 2001 From: Bainian Liu Date: Thu, 20 Dec 2018 12:08:11 -0800 Subject: [PATCH] Java sample app for hybridconnection over http and websocket modes (#35) Java sample app for hybridconnection over http and websocket modes Steps to run these samples: 1, Install JDK 1.8 or higher. 2. Install Apache Maven. 3. Clone or pull the latest library code at: https://github.com/Azure/azure-relay-java. 4. In cmd, go to the project root of azure-relay-java, then run "mvn clean package". 5. Copy/paste over the "...-jar-with-depencies.jar" file under "/target" and place it under the "/lib" folder in the sample apps. 6. If haven't already, create a Relay namespace in Azure portal here, then create a Hybrid Connection instance inside under the "Entities" tab with "Requires Client Authentication" option checked. 7. Obtain a valid connection string from your hybrid connection instance, then set it as an environment variable with variable name as "RELAY_CONNECTION_STRING" and value as the entire connection string. 8. Run the sample listener app, then run the sample sender app. Running the sender app without a running listener instance will result in an error. --- .gitignore | 55 ++++++++++++++++ .../java/simple-http-demo/.classpath | 7 +++ .../src/samples/HttpListener.java | 56 +++++++++++++++++ .../src/samples/HttpSender.java | 63 +++++++++++++++++++ .../java/simple-websocket-demo/.classpath | 7 +++ .../src/samples/WebsocketListener.java | 60 ++++++++++++++++++ .../src/samples/WebsocketSender.java | 43 +++++++++++++ 7 files changed, 291 insertions(+) create mode 100644 samples/hybrid-connections/java/simple-http-demo/.classpath create mode 100644 samples/hybrid-connections/java/simple-http-demo/src/samples/HttpListener.java create mode 100644 samples/hybrid-connections/java/simple-http-demo/src/samples/HttpSender.java create mode 100644 samples/hybrid-connections/java/simple-websocket-demo/.classpath create mode 100644 samples/hybrid-connections/java/simple-websocket-demo/src/samples/WebsocketListener.java create mode 100644 samples/hybrid-connections/java/simple-websocket-demo/src/samples/WebsocketSender.java diff --git a/.gitignore b/.gitignore index f1e3d20..525471d 100644 --- a/.gitignore +++ b/.gitignore @@ -250,3 +250,58 @@ paket-files/ # JetBrains Rider .idea/ *.sln.iml + +# Java +*.class + +#External libs +extlib/ + +# Auth files +*.auth +*.azureauth + +# Local checkstyle +*.checkstyle + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear + +# Azure Tooling # +node_modules +packages + +# Eclipse # +*.pydevproject +.project +.metadata +bin/** +tmp/** +tmp/**/* +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# Other Tooling # +.classpath +.project +target +.idea +*.iml + +# Mac OS # +.DS_Store +.DS_Store? + +# Windows # +Thumbs.db \ No newline at end of file diff --git a/samples/hybrid-connections/java/simple-http-demo/.classpath b/samples/hybrid-connections/java/simple-http-demo/.classpath new file mode 100644 index 0000000..f914ad4 --- /dev/null +++ b/samples/hybrid-connections/java/simple-http-demo/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/samples/hybrid-connections/java/simple-http-demo/src/samples/HttpListener.java b/samples/hybrid-connections/java/simple-http-demo/src/samples/HttpListener.java new file mode 100644 index 0000000..6cdbeec --- /dev/null +++ b/samples/hybrid-connections/java/simple-http-demo/src/samples/HttpListener.java @@ -0,0 +1,56 @@ +package samples; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.Scanner; +import java.util.concurrent.CompletableFuture; + +import com.microsoft.azure.relay.HybridConnectionListener; +import com.microsoft.azure.relay.HybridConnectionUtil; +import com.microsoft.azure.relay.RelayedHttpListenerResponse; +import com.microsoft.azure.relay.TokenProvider; + +public class HttpListener { + static final String CONNECTION_STRING_ENV_VARIABLE_NAME = "RELAY_CONNECTION_STRING"; + static final Map connectionParams = HybridConnectionUtil.parseConnectionString(System.getenv(CONNECTION_STRING_ENV_VARIABLE_NAME)); + static final String RELAY_NAMESPACE = connectionParams.get("Endpoint"); + static final String ENTITY_PATH = connectionParams.get("EntityPath"); + static final String KEY_NAME = connectionParams.get("SharedAccessKeyName"); + static final String KEY = connectionParams.get("SharedAccessKey"); + + public static void main(String[] args) throws URISyntaxException { + TokenProvider tokenProvider = TokenProvider.createSharedAccessSignatureTokenProvider(KEY_NAME, KEY); + HybridConnectionListener listener = new HybridConnectionListener(new URI(RELAY_NAMESPACE + ENTITY_PATH), tokenProvider); + + listener.setRequestHandler((context) -> { + ByteBuffer inputStream = context.getRequest().getInputStream(); + String receivedText = (inputStream != null) ? new String(inputStream.array()) : ""; + System.out.println("requestHandler received " + receivedText); + + RelayedHttpListenerResponse response = context.getResponse(); + response.setStatusCode(202); + response.setStatusDescription("OK"); + + try { + response.getOutputStream().write(("Echo: " + receivedText).getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + + // The context MUST be closed for the message to be sent + context.getResponse().close(); + }); + + listener.openAsync().join(); + + Scanner in = new Scanner(System.in); + System.out.println("Press ENTER to terminate this program."); + in.nextLine(); + + listener.closeAsync().join(); + in.close(); + } +} diff --git a/samples/hybrid-connections/java/simple-http-demo/src/samples/HttpSender.java b/samples/hybrid-connections/java/simple-http-demo/src/samples/HttpSender.java new file mode 100644 index 0000000..983429f --- /dev/null +++ b/samples/hybrid-connections/java/simple-http-demo/src/samples/HttpSender.java @@ -0,0 +1,63 @@ +package samples; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.time.Duration; +import java.util.Map; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; + +import com.microsoft.azure.relay.HybridConnectionUtil; +import com.microsoft.azure.relay.StringUtil; +import com.microsoft.azure.relay.TokenProvider; + +public class HttpSender { + static final String CONNECTION_STRING_ENV_VARIABLE_NAME = "RELAY_CONNECTION_STRING"; + static final Map connectionParams = HybridConnectionUtil.parseConnectionString(System.getenv(CONNECTION_STRING_ENV_VARIABLE_NAME)); + static final String RELAY_NAMESPACE = connectionParams.get("Endpoint"); + static final String ENTITY_PATH = connectionParams.get("EntityPath"); + static final String KEY_NAME = connectionParams.get("SharedAccessKeyName"); + static final String KEY = connectionParams.get("SharedAccessKey"); + + public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { + TokenProvider tokenProvider = TokenProvider.createSharedAccessSignatureTokenProvider(KEY_NAME, KEY); + String urlString = HybridConnectionUtil.getURLString(RELAY_NAMESPACE, ENTITY_PATH); + String tokenString = tokenProvider.getTokenAsync(urlString, Duration.ofHours(1)).join().getToken(); + Scanner in = new Scanner(System.in); + + while (true) { + System.out.println("Please enter the message you want to send over http, \"quit\" or \"q\" to terminate:"); + String message = in.nextLine(); + if (message.equalsIgnoreCase("quit") || message.equalsIgnoreCase("q")) break; + + HttpURLConnection conn = (HttpURLConnection)new URL(urlString).openConnection(); + // To send a message body, use POST + conn.setRequestMethod(StringUtil.isNullOrEmpty(message) ? "GET" : "POST"); + conn.setRequestProperty("ServiceBusAuthorization", tokenString); + conn.setDoOutput(true); + + OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); + out.write(message, 0, message.length()); + out.flush(); + out.close(); + + String inputLine; + StringBuilder responseBuilder = new StringBuilder(); + BufferedReader inStream = new BufferedReader(new InputStreamReader(conn.getInputStream())); + + System.out.println("status code: " + conn.getResponseCode()); + while ((inputLine = inStream.readLine()) != null) { + responseBuilder.append(inputLine); + } + + inStream.close(); + System.out.println("received back " + responseBuilder.toString()); + } + + in.close(); + } +} diff --git a/samples/hybrid-connections/java/simple-websocket-demo/.classpath b/samples/hybrid-connections/java/simple-websocket-demo/.classpath new file mode 100644 index 0000000..f914ad4 --- /dev/null +++ b/samples/hybrid-connections/java/simple-websocket-demo/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/samples/hybrid-connections/java/simple-websocket-demo/src/samples/WebsocketListener.java b/samples/hybrid-connections/java/simple-websocket-demo/src/samples/WebsocketListener.java new file mode 100644 index 0000000..347b7b6 --- /dev/null +++ b/samples/hybrid-connections/java/simple-websocket-demo/src/samples/WebsocketListener.java @@ -0,0 +1,60 @@ +package samples; + +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.Scanner; +import java.util.concurrent.CompletableFuture; + +import com.microsoft.azure.relay.ClientWebSocket; +import com.microsoft.azure.relay.HybridConnectionListener; +import com.microsoft.azure.relay.HybridConnectionUtil; +import com.microsoft.azure.relay.TokenProvider; + +public class WebsocketListener { + static boolean quit = false; + + static final String CONNECTION_STRING_ENV_VARIABLE_NAME = "RELAY_CONNECTION_STRING"; + static final Map connectionParams = HybridConnectionUtil.parseConnectionString(System.getenv(CONNECTION_STRING_ENV_VARIABLE_NAME)); + static final String RELAY_NAMESPACE = connectionParams.get("Endpoint"); + static final String ENTITY_PATH = connectionParams.get("EntityPath"); + static final String KEY_NAME = connectionParams.get("SharedAccessKeyName"); + static final String KEY = connectionParams.get("SharedAccessKey"); + + public static void main(String[] args) throws URISyntaxException { + TokenProvider tokenProvider = TokenProvider.createSharedAccessSignatureTokenProvider(KEY_NAME, KEY); + HybridConnectionListener listener = new HybridConnectionListener(new URI(RELAY_NAMESPACE + ENTITY_PATH), tokenProvider); + + listener.openAsync().join(); + System.out.println("Listener is online. Press ENTER to terminate this program."); + + CompletableFuture.runAsync(() -> { + Scanner in = new Scanner(System.in); + in.nextLine(); + + listener.closeAsync().join(); + in.close(); + }); + + while (listener.isOnline()) { + ClientWebSocket websocket = listener.acceptConnectionAsync().join(); + + // If listener closes, then listener.acceptConnectionAsync() will complete with null after closing down + if (websocket != null) { + CompletableFuture.runAsync(() -> { + System.out.println("New session connected."); + + while (websocket.isOpen()) { + ByteBuffer bytesReceived = websocket.receiveMessageAsync().join(); + String msg = new String(bytesReceived.array()); + + System.out.println("Received: " + msg); + websocket.sendAsync("Echo: " + msg); + } + System.out.println("Session disconnected."); + }); + } + } + } +} diff --git a/samples/hybrid-connections/java/simple-websocket-demo/src/samples/WebsocketSender.java b/samples/hybrid-connections/java/simple-websocket-demo/src/samples/WebsocketSender.java new file mode 100644 index 0000000..5c4e897 --- /dev/null +++ b/samples/hybrid-connections/java/simple-websocket-demo/src/samples/WebsocketSender.java @@ -0,0 +1,43 @@ +package samples; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Map; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; + +import com.microsoft.azure.relay.HybridConnectionClient; +import com.microsoft.azure.relay.HybridConnectionUtil; +import com.microsoft.azure.relay.TokenProvider; + +public class WebsocketSender { + static final String CONNECTION_STRING_ENV_VARIABLE_NAME = "RELAY_CONNECTION_STRING"; + static final Map connectionParams = HybridConnectionUtil.parseConnectionString(System.getenv(CONNECTION_STRING_ENV_VARIABLE_NAME)); + static final String RELAY_NAMESPACE = connectionParams.get("Endpoint"); + static final String ENTITY_PATH = connectionParams.get("EntityPath"); + static final String KEY_NAME = connectionParams.get("SharedAccessKeyName"); + static final String KEY = connectionParams.get("SharedAccessKey"); + + public static void main(String[] args) throws InterruptedException, ExecutionException, URISyntaxException { + TokenProvider tokenProvider = TokenProvider.createSharedAccessSignatureTokenProvider(KEY_NAME, KEY); + HybridConnectionClient client = new HybridConnectionClient(new URI(RELAY_NAMESPACE + ENTITY_PATH), tokenProvider); + + Scanner in = new Scanner(System.in); + + client.createConnectionAsync().thenAccept((socket) -> { + while (true) { + System.out.println("Please enter the text you want to send, or enter \"quit\" or \"q\" to exit"); + String input = in.nextLine(); + if (input.equalsIgnoreCase("quit") || input.equalsIgnoreCase("q")) break; + socket.sendAsync(input).join(); + + socket.receiveMessageAsync().thenAccept((byteBuffer) -> { + System.out.println("Received: " + new String(byteBuffer.array())); + }); + } + + client.closeAsync().join(); + in.close(); + }); + } +}