mirror of https://github.com/apache/nifi.git
NIFI-3609: ConnectWebSocket auto session recovery
- Removed unused disconnect method from WebSocketService interface. - Added session maintenance background thread at JettyWebSocketClient which reconnects sessions those are still referred by ConnectWebSocket processor but no longer active. - Added Session Maintenance Interval property to JettyWebSocketClient. - Allowed specifying existing session id so that it can be recovered transparently. - Moved test classes to appropriate package. - Added test cases that verify the same session id can be used after WebSocket server restarts.
This commit is contained in:
parent
8fa35294eb
commit
0a014b471b
|
@ -45,9 +45,4 @@ public abstract class AbstractWebSocketService extends AbstractControllerService
|
||||||
routers.sendMessage(endpointId, sessionId, sendMessage);
|
routers.sendMessage(endpointId, sessionId, sendMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disconnect(final String endpointId, final String sessionId, final String reason) throws IOException, WebSocketConfigurationException {
|
|
||||||
routers.disconnect(endpointId, sessionId, reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,4 +124,8 @@ public class WebSocketMessageRouter {
|
||||||
sessions.remove(sessionId);
|
sessions.remove(sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean containsSession(final String sessionId) {
|
||||||
|
return sessions.containsKey(sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@ public class WebSocketMessageRouters {
|
||||||
|
|
||||||
public synchronized void deregisterProcessor(final String endpointId, final Processor processor) throws WebSocketConfigurationException {
|
public synchronized void deregisterProcessor(final String endpointId, final Processor processor) throws WebSocketConfigurationException {
|
||||||
final WebSocketMessageRouter router = getRouterOrFail(endpointId);
|
final WebSocketMessageRouter router = getRouterOrFail(endpointId);
|
||||||
|
routers.remove(endpointId);
|
||||||
router.deregisterProcessor(processor);
|
router.deregisterProcessor(processor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,9 +68,4 @@ public class WebSocketMessageRouters {
|
||||||
router.sendMessage(sessionId, sendMessage);
|
router.sendMessage(sessionId, sendMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect(final String endpointId, final String sessionId, final String reason) throws IOException, WebSocketConfigurationException {
|
|
||||||
final WebSocketMessageRouter router = getRouterOrFail(endpointId);
|
|
||||||
router.disconnect(sessionId, reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,4 @@ public interface WebSocketService extends ControllerService {
|
||||||
|
|
||||||
void sendMessage(final String endpointId, final String sessionId, final SendMessage sendMessage) throws IOException, WebSocketConfigurationException;
|
void sendMessage(final String endpointId, final String sessionId, final SendMessage sendMessage) throws IOException, WebSocketConfigurationException;
|
||||||
|
|
||||||
void disconnect(final String endpointId, final String sessionId, final String reason) throws Exception;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.apache.nifi.annotation.lifecycle.OnShutdown;
|
||||||
import org.apache.nifi.components.PropertyDescriptor;
|
import org.apache.nifi.components.PropertyDescriptor;
|
||||||
import org.apache.nifi.components.ValidationResult;
|
import org.apache.nifi.components.ValidationResult;
|
||||||
import org.apache.nifi.controller.ConfigurationContext;
|
import org.apache.nifi.controller.ConfigurationContext;
|
||||||
|
import org.apache.nifi.logging.ComponentLog;
|
||||||
import org.apache.nifi.processor.util.StandardValidators;
|
import org.apache.nifi.processor.util.StandardValidators;
|
||||||
import org.apache.nifi.ssl.SSLContextService;
|
import org.apache.nifi.ssl.SSLContextService;
|
||||||
import org.apache.nifi.websocket.WebSocketClientService;
|
import org.apache.nifi.websocket.WebSocketClientService;
|
||||||
|
@ -39,8 +40,13 @@ import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
@Tags({"WebSocket", "Jetty", "client"})
|
@Tags({"WebSocket", "Jetty", "client"})
|
||||||
@CapabilityDescription("Implementation of WebSocketClientService." +
|
@CapabilityDescription("Implementation of WebSocketClientService." +
|
||||||
|
@ -81,6 +87,16 @@ public class JettyWebSocketClient extends AbstractJettyWebSocketService implemen
|
||||||
.defaultValue("3 sec")
|
.defaultValue("3 sec")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
public static final PropertyDescriptor SESSION_MAINTENANCE_INTERVAL = new PropertyDescriptor.Builder()
|
||||||
|
.name("session-maintenance-interval")
|
||||||
|
.displayName("Session Maintenance Interval")
|
||||||
|
.description("The interval between session maintenance activities.")
|
||||||
|
.required(true)
|
||||||
|
.expressionLanguageSupported(true)
|
||||||
|
.addValidator(StandardValidators.TIME_PERIOD_VALIDATOR)
|
||||||
|
.defaultValue("10 sec")
|
||||||
|
.build();
|
||||||
|
|
||||||
private static final List<PropertyDescriptor> properties;
|
private static final List<PropertyDescriptor> properties;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
@ -89,6 +105,7 @@ public class JettyWebSocketClient extends AbstractJettyWebSocketService implemen
|
||||||
props.add(WS_URI);
|
props.add(WS_URI);
|
||||||
props.add(SSL_CONTEXT);
|
props.add(SSL_CONTEXT);
|
||||||
props.add(CONNECTION_TIMEOUT);
|
props.add(CONNECTION_TIMEOUT);
|
||||||
|
props.add(SESSION_MAINTENANCE_INTERVAL);
|
||||||
|
|
||||||
properties = Collections.unmodifiableList(props);
|
properties = Collections.unmodifiableList(props);
|
||||||
}
|
}
|
||||||
|
@ -96,6 +113,8 @@ public class JettyWebSocketClient extends AbstractJettyWebSocketService implemen
|
||||||
private WebSocketClient client;
|
private WebSocketClient client;
|
||||||
private URI webSocketUri;
|
private URI webSocketUri;
|
||||||
private long connectionTimeoutMillis;
|
private long connectionTimeoutMillis;
|
||||||
|
private volatile ScheduledExecutorService sessionMaintenanceScheduler;
|
||||||
|
private final ReentrantLock connectionLock = new ReentrantLock();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
|
protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
|
||||||
|
@ -116,15 +135,38 @@ public class JettyWebSocketClient extends AbstractJettyWebSocketService implemen
|
||||||
configurePolicy(context, client.getPolicy());
|
configurePolicy(context, client.getPolicy());
|
||||||
|
|
||||||
client.start();
|
client.start();
|
||||||
|
activeSessions.clear();
|
||||||
|
|
||||||
webSocketUri = new URI(context.getProperty(WS_URI).getValue());
|
webSocketUri = new URI(context.getProperty(WS_URI).getValue());
|
||||||
connectionTimeoutMillis = context.getProperty(CONNECTION_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS);
|
connectionTimeoutMillis = context.getProperty(CONNECTION_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
final Long sessionMaintenanceInterval = context.getProperty(SESSION_MAINTENANCE_INTERVAL).asTimePeriod(TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
sessionMaintenanceScheduler = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
sessionMaintenanceScheduler.scheduleAtFixedRate(() -> {
|
||||||
|
try {
|
||||||
|
maintainSessions();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
getLogger().warn("Failed to maintain sessions due to {}", new Object[]{e}, e);
|
||||||
|
}
|
||||||
|
}, sessionMaintenanceInterval, sessionMaintenanceInterval, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnDisabled
|
@OnDisabled
|
||||||
@OnShutdown
|
@OnShutdown
|
||||||
@Override
|
@Override
|
||||||
public void stopClient() throws Exception {
|
public void stopClient() throws Exception {
|
||||||
|
activeSessions.clear();
|
||||||
|
|
||||||
|
if (sessionMaintenanceScheduler != null) {
|
||||||
|
try {
|
||||||
|
sessionMaintenanceScheduler.shutdown();
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().warn("Failed to shutdown session maintainer due to {}", new Object[]{e}, e);
|
||||||
|
}
|
||||||
|
sessionMaintenanceScheduler = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -135,7 +177,14 @@ public class JettyWebSocketClient extends AbstractJettyWebSocketService implemen
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connect(final String clientId) throws IOException {
|
public void connect(final String clientId) throws IOException {
|
||||||
|
connect(clientId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connect(final String clientId, String sessionId) throws IOException {
|
||||||
|
|
||||||
|
connectionLock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
final WebSocketMessageRouter router;
|
final WebSocketMessageRouter router;
|
||||||
try {
|
try {
|
||||||
router = routers.getRouterOrFail(clientId);
|
router = routers.getRouterOrFail(clientId);
|
||||||
|
@ -143,6 +192,7 @@ public class JettyWebSocketClient extends AbstractJettyWebSocketService implemen
|
||||||
throw new IllegalStateException("Failed to get router due to: " + e, e);
|
throw new IllegalStateException("Failed to get router due to: " + e, e);
|
||||||
}
|
}
|
||||||
final RoutingWebSocketListener listener = new RoutingWebSocketListener(router);
|
final RoutingWebSocketListener listener = new RoutingWebSocketListener(router);
|
||||||
|
listener.setSessionId(sessionId);
|
||||||
|
|
||||||
final ClientUpgradeRequest request = new ClientUpgradeRequest();
|
final ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||||
final Future<Session> connect = client.connect(listener, webSocketUri, request);
|
final Future<Session> connect = client.connect(listener, webSocketUri, request);
|
||||||
|
@ -155,7 +205,53 @@ public class JettyWebSocketClient extends AbstractJettyWebSocketService implemen
|
||||||
throw new IOException("Failed to connect " + webSocketUri + " due to: " + e, e);
|
throw new IOException("Failed to connect " + webSocketUri + " due to: " + e, e);
|
||||||
}
|
}
|
||||||
getLogger().info("Connected, session={}", new Object[]{session});
|
getLogger().info("Connected, session={}", new Object[]{session});
|
||||||
|
activeSessions.put(clientId, listener.getSessionId());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
connectionLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> activeSessions = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
void maintainSessions() throws Exception {
|
||||||
|
if (client == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectionLock.lock();
|
||||||
|
|
||||||
|
final ComponentLog logger = getLogger();
|
||||||
|
try {
|
||||||
|
// Loop through existing sessions and reconnect.
|
||||||
|
for (String clientId : activeSessions.keySet()) {
|
||||||
|
final WebSocketMessageRouter router;
|
||||||
|
try {
|
||||||
|
router = routers.getRouterOrFail(clientId);
|
||||||
|
} catch (final WebSocketConfigurationException e) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("The clientId {} is no longer active. Discarding the clientId.", new Object[]{clientId});
|
||||||
|
}
|
||||||
|
activeSessions.remove(clientId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String sessionId = activeSessions.get(clientId);
|
||||||
|
// If this session is stil alive, do nothing.
|
||||||
|
if (!router.containsSession(sessionId)) {
|
||||||
|
// This session is no longer active, reconnect it.
|
||||||
|
// If it fails, the sessionId will remain in activeSessions, and retries later.
|
||||||
|
connect(clientId, sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
connectionLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Session maintenance completed. activeSessions={}", new Object[]{activeSessions});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -33,7 +33,11 @@ public class RoutingWebSocketListener extends WebSocketAdapter {
|
||||||
@Override
|
@Override
|
||||||
public void onWebSocketConnect(final Session session) {
|
public void onWebSocketConnect(final Session session) {
|
||||||
super.onWebSocketConnect(session);
|
super.onWebSocketConnect(session);
|
||||||
|
if (sessionId == null || sessionId.isEmpty()) {
|
||||||
|
// If sessionId is already assigned to this instance, don't publish new one.
|
||||||
|
// So that existing sesionId can be reused when reconnecting.
|
||||||
sessionId = UUID.randomUUID().toString();
|
sessionId = UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
final JettyWebSocketSession webSocketSession = new JettyWebSocketSession(sessionId, session);
|
final JettyWebSocketSession webSocketSession = new JettyWebSocketSession(sessionId, session);
|
||||||
router.captureSession(webSocketSession);
|
router.captureSession(webSocketSession);
|
||||||
}
|
}
|
||||||
|
@ -53,4 +57,12 @@ public class RoutingWebSocketListener extends WebSocketAdapter {
|
||||||
public void onWebSocketBinary(final byte[] payload, final int offset, final int len) {
|
public void onWebSocketBinary(final byte[] payload, final int offset, final int len) {
|
||||||
router.onWebSocketBinary(sessionId, payload, offset, len);
|
router.onWebSocketBinary(sessionId, payload, offset, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSessionId(String sessionId) {
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSessionId() {
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.websocket;
|
package org.apache.nifi.websocket.jetty;
|
||||||
|
|
||||||
import org.apache.nifi.components.PropertyDescriptor;
|
import org.apache.nifi.components.PropertyDescriptor;
|
||||||
import org.apache.nifi.components.ValidationContext;
|
import org.apache.nifi.components.ValidationContext;
|
|
@ -14,10 +14,9 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.websocket;
|
package org.apache.nifi.websocket.jetty;
|
||||||
|
|
||||||
import org.apache.nifi.components.ValidationResult;
|
import org.apache.nifi.components.ValidationResult;
|
||||||
import org.apache.nifi.websocket.jetty.JettyWebSocketClient;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
|
@ -14,11 +14,15 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.websocket;
|
package org.apache.nifi.websocket.jetty;
|
||||||
|
|
||||||
import org.apache.nifi.processor.Processor;
|
import org.apache.nifi.processor.Processor;
|
||||||
import org.apache.nifi.websocket.jetty.JettyWebSocketClient;
|
import org.apache.nifi.websocket.BinaryMessageConsumer;
|
||||||
import org.apache.nifi.websocket.jetty.JettyWebSocketServer;
|
import org.apache.nifi.websocket.ConnectedListener;
|
||||||
|
import org.apache.nifi.websocket.TextMessageConsumer;
|
||||||
|
import org.apache.nifi.websocket.WebSocketClientService;
|
||||||
|
import org.apache.nifi.websocket.WebSocketServerService;
|
||||||
|
import org.apache.nifi.websocket.WebSocketSessionInfo;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -176,6 +180,84 @@ public class TestJettyWebSocketCommunication {
|
||||||
serverService.deregisterProcessor(serverPath, serverProcessor);
|
serverService.deregisterProcessor(serverPath, serverProcessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClientServerCommunicationRecovery() throws Exception {
|
||||||
|
assumeFalse(isWindowsEnvironment());
|
||||||
|
// Expectations.
|
||||||
|
final CountDownLatch serverIsConnectedByClient = new CountDownLatch(1);
|
||||||
|
final CountDownLatch clientConnectedServer = new CountDownLatch(1);
|
||||||
|
final CountDownLatch serverReceivedTextMessageFromClient = new CountDownLatch(1);
|
||||||
|
final CountDownLatch serverReceivedBinaryMessageFromClient = new CountDownLatch(1);
|
||||||
|
final CountDownLatch clientReceivedTextMessageFromServer = new CountDownLatch(1);
|
||||||
|
final CountDownLatch clientReceivedBinaryMessageFromServer = new CountDownLatch(1);
|
||||||
|
|
||||||
|
final String textMessageFromClient = "Message from client.";
|
||||||
|
final String textMessageFromServer = "Message from server.";
|
||||||
|
|
||||||
|
final MockWebSocketProcessor serverProcessor = mock(MockWebSocketProcessor.class);
|
||||||
|
doReturn("serverProcessor1").when(serverProcessor).getIdentifier();
|
||||||
|
final AtomicReference<String> serverSessionIdRef = new AtomicReference<>();
|
||||||
|
|
||||||
|
doAnswer(invocation -> assertConnectedEvent(serverIsConnectedByClient, serverSessionIdRef, invocation))
|
||||||
|
.when(serverProcessor).connected(any(WebSocketSessionInfo.class));
|
||||||
|
|
||||||
|
doAnswer(invocation -> assertConsumeTextMessage(serverReceivedTextMessageFromClient, textMessageFromClient, invocation))
|
||||||
|
.when(serverProcessor).consume(any(WebSocketSessionInfo.class), anyString());
|
||||||
|
|
||||||
|
doAnswer(invocation -> assertConsumeBinaryMessage(serverReceivedBinaryMessageFromClient, textMessageFromClient, invocation))
|
||||||
|
.when(serverProcessor).consume(any(WebSocketSessionInfo.class), any(byte[].class), anyInt(), anyInt());
|
||||||
|
|
||||||
|
serverService.registerProcessor(serverPath, serverProcessor);
|
||||||
|
|
||||||
|
final String clientId = "client1";
|
||||||
|
|
||||||
|
final MockWebSocketProcessor clientProcessor = mock(MockWebSocketProcessor.class);
|
||||||
|
doReturn("clientProcessor1").when(clientProcessor).getIdentifier();
|
||||||
|
final AtomicReference<String> clientSessionIdRef = new AtomicReference<>();
|
||||||
|
|
||||||
|
|
||||||
|
doAnswer(invocation -> assertConnectedEvent(clientConnectedServer, clientSessionIdRef, invocation))
|
||||||
|
.when(clientProcessor).connected(any(WebSocketSessionInfo.class));
|
||||||
|
|
||||||
|
doAnswer(invocation -> assertConsumeTextMessage(clientReceivedTextMessageFromServer, textMessageFromServer, invocation))
|
||||||
|
.when(clientProcessor).consume(any(WebSocketSessionInfo.class), anyString());
|
||||||
|
|
||||||
|
doAnswer(invocation -> assertConsumeBinaryMessage(clientReceivedBinaryMessageFromServer, textMessageFromServer, invocation))
|
||||||
|
.when(clientProcessor).consume(any(WebSocketSessionInfo.class), any(byte[].class), anyInt(), anyInt());
|
||||||
|
|
||||||
|
clientService.registerProcessor(clientId, clientProcessor);
|
||||||
|
|
||||||
|
clientService.connect(clientId);
|
||||||
|
|
||||||
|
assertTrue("WebSocket client should be able to fire connected event.", clientConnectedServer.await(5, TimeUnit.SECONDS));
|
||||||
|
assertTrue("WebSocket server should be able to fire connected event.", serverIsConnectedByClient.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
// Nothing happens if maintenance is executed while sessions are alive.
|
||||||
|
((JettyWebSocketClient) clientService).maintainSessions();
|
||||||
|
|
||||||
|
// Restart server.
|
||||||
|
serverService.stopServer();
|
||||||
|
serverService.startServer(serverServiceContext.getConfigurationContext());
|
||||||
|
|
||||||
|
// Sessions will be recreated with the same session ids.
|
||||||
|
((JettyWebSocketClient) clientService).maintainSessions();
|
||||||
|
|
||||||
|
clientService.sendMessage(clientId, clientSessionIdRef.get(), sender -> sender.sendString(textMessageFromClient));
|
||||||
|
clientService.sendMessage(clientId, clientSessionIdRef.get(), sender -> sender.sendBinary(ByteBuffer.wrap(textMessageFromClient.getBytes())));
|
||||||
|
|
||||||
|
assertTrue("WebSocket server should be able to consume text message.", serverReceivedTextMessageFromClient.await(5, TimeUnit.SECONDS));
|
||||||
|
assertTrue("WebSocket server should be able to consume binary message.", serverReceivedBinaryMessageFromClient.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
serverService.sendMessage(serverPath, serverSessionIdRef.get(), sender -> sender.sendString(textMessageFromServer));
|
||||||
|
serverService.sendMessage(serverPath, serverSessionIdRef.get(), sender -> sender.sendBinary(ByteBuffer.wrap(textMessageFromServer.getBytes())));
|
||||||
|
|
||||||
|
assertTrue("WebSocket client should be able to consume text message.", clientReceivedTextMessageFromServer.await(5, TimeUnit.SECONDS));
|
||||||
|
assertTrue("WebSocket client should be able to consume binary message.", clientReceivedBinaryMessageFromServer.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
clientService.deregisterProcessor(clientId, clientProcessor);
|
||||||
|
serverService.deregisterProcessor(serverPath, serverProcessor);
|
||||||
|
}
|
||||||
|
|
||||||
protected Object assertConnectedEvent(CountDownLatch latch, AtomicReference<String> sessionIdRef, InvocationOnMock invocation) {
|
protected Object assertConnectedEvent(CountDownLatch latch, AtomicReference<String> sessionIdRef, InvocationOnMock invocation) {
|
||||||
final WebSocketSessionInfo sessionInfo = invocation.getArgumentAt(0, WebSocketSessionInfo.class);
|
final WebSocketSessionInfo sessionInfo = invocation.getArgumentAt(0, WebSocketSessionInfo.class);
|
||||||
assertNotNull(sessionInfo.getLocalAddress());
|
assertNotNull(sessionInfo.getLocalAddress());
|
|
@ -14,10 +14,11 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.websocket;
|
package org.apache.nifi.websocket.jetty;
|
||||||
|
|
||||||
import org.apache.nifi.reporting.InitializationException;
|
import org.apache.nifi.reporting.InitializationException;
|
||||||
import org.apache.nifi.ssl.StandardSSLContextService;
|
import org.apache.nifi.ssl.StandardSSLContextService;
|
||||||
|
import org.apache.nifi.websocket.WebSocketService;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,9 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.websocket;
|
package org.apache.nifi.websocket.jetty;
|
||||||
|
|
||||||
import org.apache.nifi.components.ValidationResult;
|
import org.apache.nifi.components.ValidationResult;
|
||||||
import org.apache.nifi.websocket.jetty.JettyWebSocketServer;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
Loading…
Reference in New Issue