Negotiate + SignalR Service Support for the Java client (#2882)

This commit is contained in:
Mikael Mengistu 2018-09-05 16:53:07 -07:00 committed by GitHub
parent ac7ca5b270
commit dc6088bf21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 452 additions and 188 deletions

View File

@ -18,6 +18,7 @@ dependencies {
testImplementation group: 'junit', name: 'junit', version: '4.12'
implementation "org.java-websocket:Java-WebSocket:1.3.8"
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
}
task sourceJar(type: Jar) {

View File

@ -7,34 +7,37 @@ import java.util.Scanner;
public class Chat {
public static void main(String[] args) throws Exception {
System.out.println("Enter the URL of the SignalR Chat you want to join");
Scanner reader = new Scanner(System.in); // Reading from System.in
String input;
input = reader.nextLine();
System.out.println("Enter the URL of the SignalR Chat you want to join");
Scanner reader = new Scanner(System.in); // Reading from System.in
String input = reader.nextLine();
HubConnection hubConnection = new HubConnectionBuilder()
.withUrl(input)
.configureLogging(LogLevel.Information).build();
System.out.print("Enter your name:");
String enteredName = reader.nextLine();
hubConnection.on("Send", (message) -> {
System.out.println("REGISTERED HANDLER: " + message);
}, String.class);
HubConnection hubConnection = new HubConnectionBuilder()
.withUrl(input)
.configureLogging(LogLevel.Information).build();
hubConnection.onClosed((ex) -> {
if(ex.getMessage() != null){
System.out.printf("There was an error: %s", ex.getMessage());
}
});
hubConnection.on("Send", (name, message) -> {
System.out.println(name + ": " + message);
}, String.class, String.class);
//This is a blocking call
hubConnection.start();
while (!input.equals("leave")){
// Scans the next token of the input as an int.
input = reader.nextLine();
hubConnection.send("Send", input);
hubConnection.onClosed((ex) -> {
if (ex.getMessage() != null) {
System.out.printf("There was an error: %s", ex.getMessage());
}
});
hubConnection.stop();
//This is a blocking call
hubConnection.start();
String message = "";
while (!message.equals("leave")) {
// Scans the next token of the input as an int.
message = reader.nextLine();
hubConnection.send("Send", enteredName, message);
}
hubConnection.stop();
}
}

View File

@ -5,9 +5,11 @@ package com.microsoft.aspnet.signalr;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
public class HubConnection {
@ -22,8 +24,14 @@ public class HubConnection {
private HubConnectionState connectionState = HubConnectionState.DISCONNECTED;
private Logger logger;
private List<Consumer<Exception>> onClosedCallbackList;
private boolean skipNegotiate = false;
private NegotiateResponse negotiateResponse;
private String accessToken;
private Map<String, String> headers = new HashMap<>();
public HubConnection(String url, Transport transport, Logger logger){
private static int MAX_NEGOTIATE_ATTEMPTS = 100;
public HubConnection(String url, Transport transport, Logger logger, boolean skipNegotiate) {
this.url = url;
this.protocol = new JsonHubProtocol();
@ -32,7 +40,7 @@ public class HubConnection {
} else {
this.logger = new NullLogger();
}
this.skipNegotiate = skipNegotiate;
this.callback = (payload) -> {
if (!handshakeReceived) {
@ -56,16 +64,16 @@ public class HubConnection {
HubMessage[] messages = protocol.parseMessages(payload);
for (HubMessage message : messages) {
logger.log(LogLevel.Debug,"Received message of type %s", message.getMessageType());
logger.log(LogLevel.Debug, "Received message of type %s", message.getMessageType());
switch (message.getMessageType()) {
case INVOCATION:
InvocationMessage invocationMessage = (InvocationMessage)message;
InvocationMessage invocationMessage = (InvocationMessage) message;
if (handlers.containsKey(invocationMessage.target)) {
ArrayList<Object> args = gson.fromJson((JsonArray)invocationMessage.arguments[0], (new ArrayList<>()).getClass());
ArrayList<Object> args = gson.fromJson((JsonArray) invocationMessage.arguments[0], (new ArrayList<>()).getClass());
List<ActionBase> actions = handlers.get(invocationMessage.target);
if (actions != null) {
logger.log(LogLevel.Debug, "Invoking handlers for target %s", invocationMessage.target);
for (ActionBase action: actions) {
for (ActionBase action : actions) {
action.invoke(args.toArray());
}
}
@ -75,7 +83,7 @@ public class HubConnection {
break;
case CLOSE:
logger.log(LogLevel.Information, "Close message received from server.");
CloseMessage closeMessage = (CloseMessage)message;
CloseMessage closeMessage = (CloseMessage) message;
stop(closeMessage.getError());
break;
case PING:
@ -92,20 +100,23 @@ public class HubConnection {
}
};
if (transport == null){
try {
this.transport = new WebSocketTransport(this.url, this.logger);
} catch (URISyntaxException e) {
e.printStackTrace();
}
} else {
if (transport != null) {
this.transport = transport;
}
}
public HubConnection(String url, Transport transport, Logger logger) {
this(url, transport, logger, false);
}
public HubConnection(String url, Transport transport, boolean skipNegotiate) {
this(url, transport, new NullLogger(), skipNegotiate);
}
/**
* Initializes a new instance of the {@link HubConnection} class.
* @param url The url of the SignalR server to connect to.
*
* @param url The url of the SignalR server to connect to.
* @param transport The {@link Transport} that the client will use to communicate with the server.
*/
public HubConnection(String url, Transport transport) {
@ -114,6 +125,7 @@ public class HubConnection {
/**
* Initializes a new instance of the {@link HubConnection} class.
*
* @param url The url of the SignalR server to connect to.
*/
public HubConnection(String url) {
@ -122,15 +134,17 @@ public class HubConnection {
/**
* Initializes a new instance of the {@link HubConnection} class.
* @param url The url of the SignalR server to connect to.
*
* @param url The url of the SignalR server to connect to.
* @param logLevel The minimum level of messages to log.
*/
public HubConnection(String url, LogLevel logLevel){
public HubConnection(String url, LogLevel logLevel) {
this(url, null, new ConsoleLogger(logLevel));
}
/**
* Indicates the state of the {@link HubConnection} to the server.
*
* @return HubConnection state enum.
*/
public HubConnectionState getConnectionState() {
@ -139,14 +153,47 @@ public class HubConnection {
/**
* Starts a connection to the server.
*
* @throws Exception An error occurred while connecting.
*/
public void start() throws Exception {
if (connectionState != HubConnectionState.DISCONNECTED) {
return;
}
if (!skipNegotiate) {
int negotiateAttempts = 0;
do {
accessToken = (negotiateResponse == null) ? null : negotiateResponse.getAccessToken();
negotiateResponse = Negotiate.processNegotiate(url, accessToken);
if (negotiateResponse.getConnectionId() != null) {
if (url.contains("?")) {
url = url + "&id=" + negotiateResponse.getConnectionId();
} else {
url = url + "?id=" + negotiateResponse.getConnectionId();
}
}
if (negotiateResponse.getAccessToken() != null) {
this.headers.put("Authorization", "Bearer " + negotiateResponse.getAccessToken());
}
if (negotiateResponse.getRedirectUrl() != null) {
url = this.negotiateResponse.getRedirectUrl();
}
negotiateAttempts++;
} while (negotiateResponse.getRedirectUrl() != null && negotiateAttempts < MAX_NEGOTIATE_ATTEMPTS);
if (!negotiateResponse.getAvailableTransports().contains("WebSockets")) {
throw new HubException("There were no compatible transports on the server.");
}
}
logger.log(LogLevel.Debug, "Starting HubConnection");
if (transport == null) {
transport = new WebSocketTransport(url, logger, headers);
}
transport.setOnReceive(this.callback);
transport.start();
String handshake = HandshakeProtocol.createHandshakeRequestMessage(new HandshakeRequestMessage(protocol.getName(), protocol.getVersion()));
@ -163,8 +210,8 @@ public class HubConnection {
return;
}
if(errorMessage != null) {
logger.log(LogLevel.Error , "HubConnection disconnected with an error %s.", errorMessage);
if (errorMessage != null) {
logger.log(LogLevel.Error, "HubConnection disconnected with an error %s.", errorMessage);
} else {
logger.log(LogLevel.Debug, "Stopping HubConnection.");
}
@ -172,9 +219,9 @@ public class HubConnection {
transport.stop();
connectionState = HubConnectionState.DISCONNECTED;
logger.log(LogLevel.Information, "HubConnection stopped.");
if (onClosedCallbackList != null){
if (onClosedCallbackList != null) {
HubException hubException = new HubException(errorMessage);
for (Consumer<Exception> callback: onClosedCallbackList) {
for (Consumer<Exception> callback : onClosedCallbackList) {
callback.accept(hubException);
}
}
@ -190,8 +237,9 @@ public class HubConnection {
/**
* Invokes a hub method on the server using the specified method name.
* Does not wait for a response from the receiver.
*
* @param method The name of the server method to invoke.
* @param args The arguments to be passed to the method.
* @param args The arguments to be passed to the method.
* @throws Exception If there was an error while sending.
*/
public void send(String method, Object... args) throws Exception {
@ -207,7 +255,8 @@ public class HubConnection {
/**
* Registers a handler that will be invoked when the hub method with the specified method name is invoked.
* @param target The name of the hub method to define.
*
* @param target The name of the hub method to define.
* @param callback The handler that will be raised when the hub method is invoked.
* @return A {@link Subscription} that can be disposed to unsubscribe from the hub method.
*/
@ -220,10 +269,11 @@ public class HubConnection {
/**
* Registers a handler that will be invoked when the hub method with the specified method name is invoked.
* @param target The name of the hub method to define.
*
* @param target The name of the hub method to define.
* @param callback The handler that will be raised when the hub method is invoked.
* @param param1 The first parameter.
* @param <T1> The first argument type.
* @param param1 The first parameter.
* @param <T1> The first argument type.
* @return A {@link Subscription} that can be disposed to unsubscribe from the hub method.
*/
public <T1> Subscription on(String target, Action1<T1> callback, Class<T1> param1) {
@ -235,12 +285,13 @@ public class HubConnection {
/**
* Registers a handler that will be invoked when the hub method with the specified method name is invoked.
* @param target The name of the hub method to define.
*
* @param target The name of the hub method to define.
* @param callback The handler that will be raised when the hub method is invoked.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @return A {@link Subscription} that can be disposed to unsubscribe from the hub method.
*/
public <T1, T2> Subscription on(String target, Action2<T1, T2> callback, Class<T1> param1, Class<T2> param2) {
@ -254,14 +305,15 @@ public class HubConnection {
/**
* Registers a handler that will be invoked when the hub method with the specified method name is invoked.
* @param target The name of the hub method to define.
*
* @param target The name of the hub method to define.
* @param callback The handler that will be raised when the hub method is invoked.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param param3 The third parameter.
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @param <T3> The third parameter type.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param param3 The third parameter.
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @param <T3> The third parameter type.
* @return A {@link Subscription} that can be disposed to unsubscribe from the hub method.
*/
public <T1, T2, T3> Subscription on(String target, Action3<T1, T2, T3> callback,
@ -276,16 +328,17 @@ public class HubConnection {
/**
* Registers a handler that will be invoked when the hub method with the specified method name is invoked.
* @param target The name of the hub method to define.
*
* @param target The name of the hub method to define.
* @param callback The handler that will be raised when the hub method is invoked.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param param3 The third parameter.
* @param param4 The fourth parameter.
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @param <T3> The third parameter type.
* @param <T4> The fourth parameter type.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param param3 The third parameter.
* @param param4 The fourth parameter.
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @param <T3> The third parameter type.
* @param <T4> The fourth parameter type.
* @return A {@link Subscription} that can be disposed to unsubscribe from the hub method.
*/
public <T1, T2, T3, T4> Subscription on(String target, Action4<T1, T2, T3, T4> callback,
@ -300,18 +353,19 @@ public class HubConnection {
/**
* Registers a handler that will be invoked when the hub method with the specified method name is invoked.
* @param target The name of the hub method to define.
*
* @param target The name of the hub method to define.
* @param callback The handler that will be raised when the hub method is invoked.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param param3 The third parameter.
* @param param4 The fourth parameter.
* @param param5 The fifth parameter.
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @param <T3> The third parameter type.
* @param <T4> The fourth parameter type.
* @param <T5> The fifth parameter type.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param param3 The third parameter.
* @param param4 The fourth parameter.
* @param param5 The fifth parameter.
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @param <T3> The third parameter type.
* @param <T4> The fourth parameter type.
* @param <T5> The fifth parameter type.
* @return A {@link Subscription} that can be disposed to unsubscribe from the hub method.
*/
public <T1, T2, T3, T4, T5> Subscription on(String target, Action5<T1, T2, T3, T4, T5> callback,
@ -327,27 +381,28 @@ public class HubConnection {
/**
* Registers a handler that will be invoked when the hub method with the specified method name is invoked.
* @param target The name of the hub method to define.
*
* @param target The name of the hub method to define.
* @param callback The handler that will be raised when the hub method is invoked.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param param3 The third parameter.
* @param param4 The fourth parameter.
* @param param5 The fifth parameter.
* @param param6 The sixth parameter.
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @param <T3> The third parameter type.
* @param <T4> The fourth parameter type.
* @param <T5> The fifth parameter type.
* @param <T6> The sixth parameter type.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param param3 The third parameter.
* @param param4 The fourth parameter.
* @param param5 The fifth parameter.
* @param param6 The sixth parameter.
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @param <T3> The third parameter type.
* @param <T4> The fourth parameter type.
* @param <T5> The fifth parameter type.
* @param <T6> The sixth parameter type.
* @return A {@link Subscription} that can be disposed to unsubscribe from the hub method.
*/
public <T1, T2, T3, T4, T5, T6> Subscription on(String target, Action6<T1, T2, T3, T4, T5, T6> callback,
Class<T1> param1, Class<T2> param2, Class<T3> param3, Class<T4> param4, Class<T5> param5, Class<T6> param6) {
ActionBase action = params -> {
callback.invoke(param1.cast(params[0]), param2.cast(params[1]), param3.cast(params[2]), param4.cast(params[3]),
param5.cast(params[4]) ,param6.cast(params[5]));
param5.cast(params[4]), param6.cast(params[5]));
};
handlers.put(target, action);
logger.log(LogLevel.Trace, "Registering handler for client method: %s", target);
@ -356,29 +411,30 @@ public class HubConnection {
/**
* Registers a handler that will be invoked when the hub method with the specified method name is invoked.
* @param target The name of the hub method to define.
*
* @param target The name of the hub method to define.
* @param callback The handler that will be raised when the hub method is invoked.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param param3 The third parameter.
* @param param4 The fourth parameter.
* @param param5 The fifth parameter.
* @param param6 The sixth parameter.
* @param param7 The seventh parameter.
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @param <T3> The third parameter type.
* @param <T4> The fourth parameter type.
* @param <T5> The fifth parameter type.
* @param <T6> The sixth parameter type.
* @param <T7> The seventh parameter type.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param param3 The third parameter.
* @param param4 The fourth parameter.
* @param param5 The fifth parameter.
* @param param6 The sixth parameter.
* @param param7 The seventh parameter.
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @param <T3> The third parameter type.
* @param <T4> The fourth parameter type.
* @param <T5> The fifth parameter type.
* @param <T6> The sixth parameter type.
* @param <T7> The seventh parameter type.
* @return A {@link Subscription} that can be disposed to unsubscribe from the hub method.
*/
public <T1, T2, T3, T4, T5, T6, T7> Subscription on(String target, Action7<T1, T2, T3, T4, T5, T6, T7> callback,
Class<T1> param1, Class<T2> param2, Class<T3> param3, Class<T4> param4, Class<T5> param5, Class<T6> param6, Class<T7> param7) {
ActionBase action = params -> {
callback.invoke(param1.cast(params[0]), param2.cast(params[1]), param3.cast(params[2]), param4.cast(params[3]),
param5.cast(params[4]) ,param6.cast(params[5]), param7.cast(params[6]));
param5.cast(params[4]), param6.cast(params[5]), param7.cast(params[6]));
};
handlers.put(target, action);
logger.log(LogLevel.Trace, "Registering handler for client method: %s", target);
@ -387,31 +443,32 @@ public class HubConnection {
/**
* Registers a handler that will be invoked when the hub method with the specified method name is invoked.
* @param target The name of the hub method to define.
*
* @param target The name of the hub method to define.
* @param callback The handler that will be raised when the hub method is invoked.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param param3 The third parameter.
* @param param4 The fourth parameter.
* @param param5 The fifth parameter.
* @param param6 The sixth parameter.
* @param param7 The seventh parameter.
* @param param8 The eighth parameter
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @param <T3> The third parameter type.
* @param <T4> The fourth parameter type.
* @param <T5> The fifth parameter type.
* @param <T6> The sixth parameter type.
* @param <T7> The seventh parameter type.
* @param <T8> The eighth parameter type.
* @param param1 The first parameter.
* @param param2 The second parameter.
* @param param3 The third parameter.
* @param param4 The fourth parameter.
* @param param5 The fifth parameter.
* @param param6 The sixth parameter.
* @param param7 The seventh parameter.
* @param param8 The eighth parameter
* @param <T1> The first parameter type.
* @param <T2> The second parameter type.
* @param <T3> The third parameter type.
* @param <T4> The fourth parameter type.
* @param <T5> The fifth parameter type.
* @param <T6> The sixth parameter type.
* @param <T7> The seventh parameter type.
* @param <T8> The eighth parameter type.
* @return A {@link Subscription} that can be disposed to unsubscribe from the hub method.
*/
public <T1, T2, T3, T4, T5, T6, T7, T8> Subscription on(String target, Action8<T1, T2, T3, T4, T5, T6, T7, T8> callback,
Class<T1> param1, Class<T2> param2, Class<T3> param3, Class<T4> param4, Class<T5> param5, Class<T6> param6, Class<T7> param7, Class<T8> param8) {
Class<T1> param1, Class<T2> param2, Class<T3> param3, Class<T4> param4, Class<T5> param5, Class<T6> param6, Class<T7> param7, Class<T8> param8) {
ActionBase action = params -> {
callback.invoke(param1.cast(params[0]), param2.cast(params[1]), param3.cast(params[2]), param4.cast(params[3]),
param5.cast(params[4]) ,param6.cast(params[5]), param7.cast(params[6]), param8.cast(params[7]));
param5.cast(params[4]), param6.cast(params[5]), param7.cast(params[6]), param8.cast(params[7]));
};
handlers.put(target, action);
logger.log(LogLevel.Trace, "Registering handler for client method: %s", target);
@ -420,15 +477,16 @@ public class HubConnection {
/**
* Removes all handlers associated with the method with the specified method name.
*
* @param name The name of the hub method from which handlers are being removed.
*/
public void remove(String name) {
handlers.remove(name);
logger.log(LogLevel.Trace, "Removing handlers for client method %s" , name);
logger.log(LogLevel.Trace, "Removing handlers for client method %s", name);
}
public void onClosed(Consumer<Exception> callback) {
if (onClosedCallbackList == null){
if (onClosedCallbackList == null) {
onClosedCallbackList = new ArrayList<>();
}

View File

@ -0,0 +1,63 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
package com.microsoft.aspnet.signalr;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
public class Negotiate {
public static NegotiateResponse processNegotiate(String url) throws IOException {
return processNegotiate(url, null);
}
public static NegotiateResponse processNegotiate(String url, String accessTokenHeader) throws IOException {
url = resolveNegotiateUrl(url);
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(null, new byte[]{});
Request.Builder requestBuilder = new Request.Builder()
.url(url)
.post(body);
if (accessTokenHeader != null) {
requestBuilder.addHeader("Authorization", "Bearer " + accessTokenHeader);
}
Request request = requestBuilder.build();
Response response = client.newCall(request).execute();
String result = response.body().string();
return new NegotiateResponse(result);
}
public static String resolveNegotiateUrl(String url) {
String negotiateUrl = "";
// Check if we have a query string. If we do then we ignore it for now.
int queryStringIndex = url.indexOf('?');
if (queryStringIndex > 0) {
negotiateUrl = url.substring(0, url.indexOf('?'));
} else {
negotiateUrl = url;
}
//Check if the url ends in a /
if (negotiateUrl.charAt(negotiateUrl.length() - 1) != '/') {
negotiateUrl += "/";
}
negotiateUrl += "negotiate";
// Add the query string back if it existed.
if (queryStringIndex > 0) {
negotiateUrl += url.substring(url.indexOf('?'));
}
return negotiateUrl;
}
}

View File

@ -0,0 +1,52 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
package com.microsoft.aspnet.signalr;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.util.HashSet;
import java.util.Set;
public class NegotiateResponse {
private String connectionId;
private Set<String> availableTransports = new HashSet<>();
private String redirectUrl;
private String accessToken;
private JsonParser jsonParser = new JsonParser();
public NegotiateResponse(String negotiatePayload) {
JsonObject negotiateResponse = jsonParser.parse(negotiatePayload).getAsJsonObject();
if (negotiateResponse.has("url")) {
this.redirectUrl = negotiateResponse.get("url").getAsString();
if (negotiateResponse.has("accessToken")) {
this.accessToken = negotiateResponse.get("accessToken").getAsString();
}
return;
}
this.connectionId = negotiateResponse.get("connectionId").getAsString();
JsonArray transports = (JsonArray) negotiateResponse.get("availableTransports");
for (int i = 0; i < transports.size(); i++) {
availableTransports.add(transports.get(i).getAsJsonObject().get("transport").getAsString());
}
}
public String getConnectionId() {
return connectionId;
}
public Set<String> getAvailableTransports() {
return availableTransports;
}
public String getRedirectUrl() {
return redirectUrl;
}
public String getAccessToken() {
return accessToken;
}
}

View File

@ -5,6 +5,9 @@ package com.microsoft.aspnet.signalr;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
@ -13,35 +16,42 @@ public class WebSocketTransport implements Transport {
private OnReceiveCallBack onReceiveCallBack;
private URI url;
private Logger logger;
private Map<String, String> headers;
private static final String HTTP = "http";
private static final String HTTPS = "https";
private static final String WS = "ws";
private static final String WSS = "wss";
public WebSocketTransport(String url, Logger logger) throws URISyntaxException {
public WebSocketTransport(String url, Logger logger, Map<String, String> headers) throws URISyntaxException {
this.url = formatUrl(url);
this.logger = logger;
this.headers = headers;
}
public URI getUrl(){
public WebSocketTransport(String url, Logger logger) throws URISyntaxException {
this(url, logger, null);
}
public URI getUrl() {
return url;
}
private URI formatUrl(String url) throws URISyntaxException {
if(url.startsWith(HTTPS)){
if (url.startsWith(HTTPS)) {
url = WSS + url.substring(HTTPS.length());
}
else if(url.startsWith(HTTP)){
} else if (url.startsWith(HTTP)) {
url = WS + url.substring(HTTP.length());
}
return new URI(url);
}
@Override
public void start() throws Exception {
logger.log(LogLevel.Debug, "Starting Websocket connection.");
webSocketClient = createWebSocket();
webSocketClient = createWebSocket(headers);
if (!webSocketClient.connectBlocking()) {
String errorMessage = "There was an error starting the Websockets transport.";
logger.log(LogLevel.Debug, errorMessage);
@ -72,31 +82,31 @@ public class WebSocketTransport implements Transport {
logger.log(LogLevel.Information, "WebSocket connection stopped");
}
private WebSocketClient createWebSocket() {
return new WebSocketClient(url) {
@Override
public void onOpen(ServerHandshake handshakedata) {
System.out.println("Connected to " + url);
}
private WebSocketClient createWebSocket(Map<String, String> headers) {
return new WebSocketClient(url, headers) {
@Override
public void onOpen(ServerHandshake handshakedata) {
System.out.println("Connected to " + url);
}
@Override
public void onMessage(String message) {
try {
onReceive(message);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onMessage(String message) {
try {
onReceive(message);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onClose(int code, String reason, boolean remote) {
@Override
public void onClose(int code, String reason, boolean remote) {
System.out.println("Connection Closed");
}
}
@Override
public void onError(Exception ex) {
@Override
public void onError(Exception ex) {
System.out.println("Error: " + ex.getMessage());
}
};
}
};
}
}

View File

@ -17,7 +17,7 @@ public class HubConnectionTest {
@Test
public void checkHubConnectionState() throws Exception {
Transport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.start();
assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState());
@ -28,7 +28,7 @@ public class HubConnectionTest {
@Test
public void HubConnectionClosesAfterCloseMessage() throws Exception {
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.start();
mockTransport.receiveMessage("{}" + RECORD_SEPARATOR);
@ -44,7 +44,7 @@ public class HubConnectionTest {
public void RegisteringMultipleHandlersAndBothGetTriggered() throws Exception {
AtomicReference<Double> value = new AtomicReference<>(0.0);
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
Action action = () -> value.getAndUpdate((val) -> val + 1);
hubConnection.on("inc", action);
@ -70,7 +70,7 @@ public class HubConnectionTest {
public void RemoveHandlerByName() throws Exception {
AtomicReference<Double> value = new AtomicReference<>(0.0);
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
Action action = () -> value.getAndUpdate((val) -> val + 1);
hubConnection.on("inc", action);
@ -97,7 +97,7 @@ public class HubConnectionTest {
public void AddAndRemoveHandlerImmediately() throws Exception {
AtomicReference<Double> value = new AtomicReference<>(0.0);
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
Action action = () -> value.getAndUpdate((val) -> val + 1);
hubConnection.on("inc", action);
@ -122,7 +122,7 @@ public class HubConnectionTest {
public void RemovingMultipleHandlersWithOneCallToRemove() throws Exception {
AtomicReference<Double> value = new AtomicReference<>(0.0);
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
Action action = () -> value.getAndUpdate((val) -> val + 1);
Action secondAction = () -> value.getAndUpdate((val) -> val + 2);
@ -154,7 +154,7 @@ public class HubConnectionTest {
public void RemoveHandlerWithUnsubscribe() throws Exception {
AtomicReference<Double> value = new AtomicReference<>(0.0);
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
Action action = () -> value.getAndUpdate((val) -> val + 1);
Subscription subscription = hubConnection.on("inc", action);
@ -182,7 +182,7 @@ public class HubConnectionTest {
public void UnsubscribeTwice() throws Exception {
AtomicReference<Double> value = new AtomicReference<>(0.0);
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
Action action = () -> value.getAndUpdate((val) -> val + 1);
Subscription subscription = hubConnection.on("inc", action);
@ -211,7 +211,7 @@ public class HubConnectionTest {
public void RemoveSingleHandlerWithUnsubscribe() throws Exception {
AtomicReference<Double> value = new AtomicReference<>(0.0);
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
Action action = () -> value.getAndUpdate((val) -> val + 1);
Action secondAction = () -> value.getAndUpdate((val) -> val + 2);
@ -241,7 +241,7 @@ public class HubConnectionTest {
public void AddAndRemoveHandlerImmediatelyWithSubscribe() throws Exception {
AtomicReference<Double> value = new AtomicReference<>(0.0);
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
Action action = () -> value.getAndUpdate((val) -> val + 1);
Subscription sub = hubConnection.on("inc", action);
@ -260,7 +260,7 @@ public class HubConnectionTest {
public void RegisteringMultipleHandlersThatTakeParamsAndBothGetTriggered() throws Exception {
AtomicReference<Double> value = new AtomicReference<>(0.0);
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
Action1<Double> action = (number) -> value.getAndUpdate((val) -> val + number);
@ -282,7 +282,7 @@ public class HubConnectionTest {
public void SendWithNoParamsTriggersOnHandler() throws Exception {
AtomicReference<Double> value = new AtomicReference<Double>(0.0);
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.on("inc", () ->{
assertEquals(0.0, value.get(), 0);
@ -301,7 +301,7 @@ public class HubConnectionTest {
public void SendWithParamTriggersOnHandler() throws Exception {
AtomicReference<String> value = new AtomicReference<>();
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.on("inc", (param) ->{
assertNull(value.get());
@ -323,7 +323,7 @@ public class HubConnectionTest {
AtomicReference<Double> value2 = new AtomicReference<>();
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.on("inc", (param1, param2) ->{
assertNull(value1.get());
@ -350,7 +350,7 @@ public class HubConnectionTest {
AtomicReference<String> value3 = new AtomicReference<>();
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.on("inc", (param1, param2, param3) ->{
assertNull(value1.get());
@ -381,7 +381,7 @@ public class HubConnectionTest {
AtomicReference<String> value4 = new AtomicReference<>();
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.on("inc", (param1, param2, param3, param4) ->{
assertNull(value1.get());
@ -415,7 +415,7 @@ public class HubConnectionTest {
AtomicReference<Double> value5 = new AtomicReference<>();
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.on("inc", (param1, param2, param3, param4, param5) ->{
assertNull(value1.get());
@ -453,7 +453,7 @@ public class HubConnectionTest {
AtomicReference<String> value6 = new AtomicReference<>();
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.on("inc", (param1, param2, param3, param4, param5, param6) -> {
assertNull(value1.get());
@ -495,7 +495,7 @@ public class HubConnectionTest {
AtomicReference<String> value7 = new AtomicReference<>();
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.on("inc", (param1, param2, param3, param4, param5, param6, param7) -> {
assertNull(value1.get());
@ -541,7 +541,7 @@ public class HubConnectionTest {
AtomicReference<String> value8 = new AtomicReference<>();
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.on("inc", (param1, param2, param3, param4, param5, param6, param7, param8) -> {
assertNull(value1.get());
@ -580,8 +580,8 @@ public class HubConnectionTest {
@Test
public void ReceiveHandshakeResponseAndMessage() throws Exception {
AtomicReference<Double> value = new AtomicReference<Double>(0.0);
MockTransport transport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", transport);
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.on("inc", () ->{
assertEquals(0.0, value.get(), 0);
@ -591,9 +591,9 @@ public class HubConnectionTest {
// On start we're going to receive the handshake response and also an invocation in the same payload.
hubConnection.start();
String expectedSentMessage = "{\"protocol\":\"json\",\"version\":1}" + RECORD_SEPARATOR;
assertEquals(expectedSentMessage, transport.getSentMessages()[0]);
assertEquals(expectedSentMessage, mockTransport.getSentMessages()[0]);
transport.receiveMessage("{}" + RECORD_SEPARATOR + "{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR);
mockTransport.receiveMessage("{}" + RECORD_SEPARATOR + "{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR);
// Confirming that our handler was called and that the counter property was incremented.
assertEquals(1, value.get(), 0);
@ -603,7 +603,7 @@ public class HubConnectionTest {
public void onClosedCallbackRunsWhenStopIsCalled() throws Exception {
AtomicReference<String> value1 = new AtomicReference<>();
Transport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.start();
hubConnection.onClosed((ex) -> {
assertNull(value1.get());
@ -620,7 +620,7 @@ public class HubConnectionTest {
AtomicReference<String> value1 = new AtomicReference<>();
AtomicReference<String> value2 = new AtomicReference<>();
Transport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.start();
hubConnection.onClosed((ex) -> {
@ -645,7 +645,7 @@ public class HubConnectionTest {
@Test
public void HubConnectionClosesAndRunsOnClosedCallbackAfterCloseMessageWithError() throws Exception {
MockTransport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.onClosed((ex) -> {
assertEquals(ex.getMessage(), "There was an error");
});
@ -662,7 +662,7 @@ public class HubConnectionTest {
@Test
public void CallingStartOnStartedHubConnectionNoOps() throws Exception {
Transport mockTransport = new MockTransport();
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport);
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
hubConnection.start();
assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState());

View File

@ -0,0 +1,38 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
import com.microsoft.aspnet.signalr.NegotiateResponse;
import org.junit.Test;
import static org.junit.Assert.*;
public class NegotiateResponseTest {
@Test
public void VerifyNegotiateResponse() {
String stringNegotiateResponse = "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" +
"availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}," +
"{\"transport\":\"ServerSentEvents\",\"transferFormats\":[\"Text\"]}," +
"{\"transport\":\"LongPolling\",\"transferFormats\":[\"Text\",\"Binary\"]}]}";
NegotiateResponse negotiateResponse = new NegotiateResponse(stringNegotiateResponse);
assertTrue(negotiateResponse.getAvailableTransports().contains("WebSockets"));
assertTrue(negotiateResponse.getAvailableTransports().contains("ServerSentEvents"));
assertTrue(negotiateResponse.getAvailableTransports().contains("LongPolling"));
assertNull(negotiateResponse.getAccessToken());
assertNull(negotiateResponse.getRedirectUrl());
assertEquals("bVOiRPG8-6YiJ6d7ZcTOVQ", negotiateResponse.getConnectionId());
}
@Test
public void VerifyRedirectNegotiateResponse() {
String stringNegotiateResponse = "{\"url\":\"www.example.com\"," +
"\"accessToken\":\"some_access_token\"," +
"\"availableTransports\":[]}";
NegotiateResponse negotiateResponse = new NegotiateResponse(stringNegotiateResponse);
assertTrue(negotiateResponse.getAvailableTransports().isEmpty());
assertNull(negotiateResponse.getConnectionId());
assertEquals("some_access_token", negotiateResponse.getAccessToken());
assertEquals("www.example.com", negotiateResponse.getRedirectUrl());
assertNull(negotiateResponse.getConnectionId());
}
}

View File

@ -0,0 +1,39 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
import com.microsoft.aspnet.signalr.Negotiate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
@RunWith(Parameterized.class)
public class ResolveNegotiateUrlTest {
private String url;
private String resolvedUrl;
public ResolveNegotiateUrlTest(String url, String resolvedUrl) {
this.url = url;
this.resolvedUrl = resolvedUrl;
}
@Parameterized.Parameters
public static Collection protocols() {
return Arrays.asList(new String[][]{
{"http://example.com/hub/", "http://example.com/hub/negotiate"},
{"http://example.com/hub", "http://example.com/hub/negotiate"},
{"http://example.com/endpoint?q=my/Data", "http://example.com/endpoint/negotiate?q=my/Data"},
{"http://example.com/endpoint/?q=my/Data", "http://example.com/endpoint/negotiate?q=my/Data"},
{"http://example.com/endpoint/path/more?q=my/Data", "http://example.com/endpoint/path/more/negotiate?q=my/Data"},});
}
@Test
public void checkNegotiateUrl() {
String urlResult = Negotiate.resolveNegotiateUrl(this.url);
assertEquals(this.resolvedUrl, urlResult);
}
}