diff --git a/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/Chat.java b/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/Chat.java index d553926747..5f9345519b 100644 --- a/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/Chat.java +++ b/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/Chat.java @@ -20,6 +20,12 @@ public class Chat { System.out.println("REGISTERED HANDLER: " + message); }, String.class); + hubConnection.onClosed((ex) -> { + if(ex.getMessage() != null){ + System.out.printf("There was an error: %s", ex.getMessage()); + } + }); + //This is a blocking call hubConnection.start(); diff --git a/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubConnection.java b/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubConnection.java index f9ca982a37..6164d97e66 100644 --- a/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubConnection.java +++ b/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubConnection.java @@ -8,6 +8,7 @@ import com.google.gson.JsonArray; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; public class HubConnection { private String url; @@ -20,6 +21,7 @@ public class HubConnection { private static final String RECORD_SEPARATOR = "\u001e"; private HubConnectionState connectionState = HubConnectionState.DISCONNECTED; private Logger logger; + private List> onClosedCallbackList; public HubConnection(String url, Transport transport, Logger logger){ this.url = url; @@ -162,6 +164,12 @@ public class HubConnection { transport.stop(); connectionState = HubConnectionState.DISCONNECTED; logger.log(LogLevel.Information, "HubConnection stopped."); + if (onClosedCallbackList != null){ + HubException hubException = new HubException(errorMessage); + for (Consumer callback: onClosedCallbackList) { + callback.accept(hubException); + } + } } /** @@ -406,4 +414,12 @@ public class HubConnection { handlers.remove(name); logger.log(LogLevel.Trace, "Removing handlers for client method %s" , name); } + + public void onClosed(Consumer callback) { + if (onClosedCallbackList == null){ + onClosedCallbackList = new ArrayList<>(); + } + + onClosedCallbackList.add(callback); + } } \ No newline at end of file diff --git a/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubException.java b/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubException.java new file mode 100644 index 0000000000..e995fdc200 --- /dev/null +++ b/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubException.java @@ -0,0 +1,17 @@ +// 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; + +public class HubException extends Exception { + public HubException() { + } + + public HubException(String errorMessage) { + super(errorMessage); + } + + public HubException(String errorMessage, Exception innerException) { + super(errorMessage, innerException); + } +} diff --git a/clients/java/signalr/src/test/java/HubConnectionTest.java b/clients/java/signalr/src/test/java/HubConnectionTest.java index 59985a8b05..1b71543795 100644 --- a/clients/java/signalr/src/test/java/HubConnectionTest.java +++ b/clients/java/signalr/src/test/java/HubConnectionTest.java @@ -597,6 +597,65 @@ public class HubConnectionTest { assertEquals(1, value.get(), 0); } + @Test + public void onClosedCallbackRunsWhenStopIsCalled() throws Exception { + AtomicReference value1 = new AtomicReference<>(); + Transport mockTransport = new MockTransport(); + HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); + hubConnection.start(); + hubConnection.onClosed((ex) -> { + assertNull(value1.get()); + value1.set("Closed callback ran."); + }); + hubConnection.stop(); + + assertEquals(HubConnectionState.DISCONNECTED, hubConnection.getConnectionState()); + assertEquals(value1.get(), "Closed callback ran."); + } + + @Test + public void multipleOnClosedCallbacksRunWhenStopIsCalled() throws Exception { + AtomicReference value1 = new AtomicReference<>(); + AtomicReference value2 = new AtomicReference<>(); + Transport mockTransport = new MockTransport(); + HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); + hubConnection.start(); + + hubConnection.onClosed((ex) -> { + assertNull(value1.get()); + value1.set("Closed callback ran."); + }); + + hubConnection.onClosed((ex) -> { + assertNull(value2.get()); + value2.set("The second onClosed callback ran"); + }); + + assertNull(value1.get()); + assertNull(value2.get()); + hubConnection.stop(); + + assertEquals(HubConnectionState.DISCONNECTED, hubConnection.getConnectionState()); + assertEquals("Closed callback ran.",value1.get()); + assertEquals("The second onClosed callback ran", value2.get()); + } + + @Test + public void HubConnectionClosesAndRunsOnClosedCallbackAfterCloseMessageWithError() throws Exception { + MockTransport mockTransport = new MockTransport(); + HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); + hubConnection.onClosed((ex) -> { + assertEquals(ex.getMessage(), "There was an error"); + }); + hubConnection.start(); + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + + assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); + + mockTransport.receiveMessage("{\"type\":7,\"error\": \"There was an error\"}" + RECORD_SEPARATOR); + + assertEquals(HubConnectionState.DISCONNECTED, hubConnection.getConnectionState()); + } private class MockTransport implements Transport { private OnReceiveCallBack onReceiveCallBack; diff --git a/clients/java/signalr/src/test/java/HubExceptionTest.java b/clients/java/signalr/src/test/java/HubExceptionTest.java new file mode 100644 index 0000000000..bfebadfb9f --- /dev/null +++ b/clients/java/signalr/src/test/java/HubExceptionTest.java @@ -0,0 +1,24 @@ +// 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.HubException; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class HubExceptionTest { + @Test + public void VeryHubExceptionMesssageIsSet() { + String errorMessage = "This is a HubException"; + HubException hubException = new HubException(errorMessage); + assertEquals(hubException.getMessage(), errorMessage); + } + + @Test + public void VeryHubExceptionInnerExceptionIsSet() { + String errorMessage = "This is the inner exception of the HubException"; + Exception innerException = new Exception(errorMessage); + HubException hubException = new HubException(null, innerException); + assertEquals(hubException.getCause().getMessage(), errorMessage); + } +}