提交 01c4e458 编写于 作者: R Rossen Stoyanchev

Add support for "system" STOMP session

The "system" STOMP session is established at startup and can be used
to send messages without a client session, e.g. to support broadcasting
from a REST/HTTP handler method.
上级 44db0f81
......@@ -67,6 +67,10 @@ public class StompHeaderAccessor extends PubSubHeaderAccesssor {
public static final String NACK = "nack";
public static final String LOGIN = "login";
public static final String PASSCODE = "passcode";
public static final String DESTINATION = "destination";
public static final String CONTENT_TYPE = "content-type";
......@@ -297,6 +301,23 @@ public class StompHeaderAccessor extends PubSubHeaderAccesssor {
return getHeaderValue(NACK);
}
public void setLogin(String login) {
this.headers.put(LOGIN, login);
}
public String getLogin() {
return getHeaderValue(LOGIN);
}
public void setPasscode(String passcode) {
this.headers.put(PASSCODE, passcode);
}
public String getPasscode() {
return getHeaderValue(PASSCODE);
}
public void setReceiptId(String receiptId) {
this.headers.put(RECEIPT_ID, receiptId);
}
......
......@@ -25,6 +25,7 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import org.springframework.context.SmartLifecycle;
import org.springframework.http.MediaType;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
......@@ -54,7 +55,10 @@ import reactor.tcp.netty.NettyTcpClient;
* @since 4.0
*/
@SuppressWarnings("rawtypes")
public class StompRelayPubSubMessageHandler<M extends Message> extends AbstractPubSubMessageHandler<M> {
public class StompRelayPubSubMessageHandler<M extends Message> extends AbstractPubSubMessageHandler<M>
implements SmartLifecycle {
private static final String STOMP_RELAY_SYSTEM_SESSION_ID = "stompRelaySystemSessionId";
private MessageChannel<M> clientChannel;
......@@ -62,26 +66,22 @@ public class StompRelayPubSubMessageHandler<M extends Message> extends AbstractP
private MessageConverter payloadConverter;
private final TcpClient<String, String> tcpClient;
private TcpClient<String, String> tcpClient;
private final Map<String, RelaySession> relaySessions = new ConcurrentHashMap<String, RelaySession>();
private Object lifecycleMonitor = new Object();
private boolean running = false;
/**
* @param clientChannel a channel for sending messages from the remote message broker
* back to clients
*/
public StompRelayPubSubMessageHandler(PubSubChannelRegistry<M, ?> registry) {
Assert.notNull(registry, "registry is required");
this.clientChannel = registry.getClientOutputChannel();
this.tcpClient = new TcpClient.Spec<String, String>(NettyTcpClient.class)
.using(new Environment())
.codec(new DelimitedCodec<String, String>((byte) 0, true, StandardCodecs.STRING_CODEC))
.connect("127.0.0.1", 61613)
.get();
this.payloadConverter = new CompositeMessageConverter(null);
}
......@@ -94,6 +94,71 @@ public class StompRelayPubSubMessageHandler<M extends Message> extends AbstractP
return null;
}
@Override
public boolean isAutoStartup() {
return true;
}
@Override
public int getPhase() {
return Integer.MAX_VALUE;
}
@Override
public boolean isRunning() {
synchronized (this.lifecycleMonitor) {
return this.running;
}
}
@Override
public void start() {
synchronized (this.lifecycleMonitor) {
// TODO: make this configurable
this.tcpClient = new TcpClient.Spec<String, String>(NettyTcpClient.class)
.using(new Environment())
.codec(new DelimitedCodec<String, String>((byte) 0, true, StandardCodecs.STRING_CODEC))
.connect("127.0.0.1", 61613)
.get();
StompHeaderAccessor headers = StompHeaderAccessor.create(StompCommand.CONNECT);
headers.setAcceptVersion("1.1,1.2");
headers.setLogin("guest");
headers.setPasscode("guest");
headers.setHeartbeat(0, 0);
@SuppressWarnings("unchecked")
M message = (M) MessageBuilder.withPayload(new byte[0]).copyHeaders(headers.toStompMessageHeaders()).build();
RelaySession session = new RelaySession(message, headers) {
@Override
protected void sendMessageToClient(M message) {
// TODO: check for ERROR frame (reconnect?)
}
};
this.relaySessions.put(STOMP_RELAY_SYSTEM_SESSION_ID, session);
this.running = true;
}
}
@Override
public void stop() {
synchronized (this.lifecycleMonitor) {
this.running = false;
this.tcpClient.close();
}
}
@Override
public void stop(Runnable callback) {
synchronized (this.lifecycleMonitor) {
stop();
callback.run();
}
}
@Override
public void handleConnect(M message) {
StompHeaderAccessor stompHeaders = StompHeaderAccessor.wrap(message);
......@@ -146,10 +211,19 @@ public class StompRelayPubSubMessageHandler<M extends Message> extends AbstractP
StompHeaderAccessor headers = StompHeaderAccessor.wrap(message);
headers.setStompCommandIfNotSet(command);
if (headers.getSessionId() == null && (StompCommand.SEND.equals(command))) {
}
String sessionId = headers.getSessionId();
if (sessionId == null) {
logger.error("No sessionId in message " + message);
return;
if (StompCommand.SEND.equals(command)) {
sessionId = STOMP_RELAY_SYSTEM_SESSION_ID;
}
else {
logger.error("No sessionId in message " + message);
return;
}
}
RelaySession session = this.relaySessions.get(sessionId);
......@@ -163,7 +237,7 @@ public class StompRelayPubSubMessageHandler<M extends Message> extends AbstractP
}
private final class RelaySession {
private class RelaySession {
private final String sessionId;
......@@ -236,6 +310,10 @@ public class StompRelayPubSubMessageHandler<M extends Message> extends AbstractP
}
relaySessions.remove(this.sessionId);
}
sendMessageToClient(message);
}
protected void sendMessageToClient(M message) {
clientChannel.send(message);
}
......@@ -245,7 +323,7 @@ public class StompRelayPubSubMessageHandler<M extends Message> extends AbstractP
headers.setMessage(errorText);
@SuppressWarnings("unchecked")
M errorMessage = (M) MessageBuilder.withPayload(new byte[0]).copyHeaders(headers.toHeaders()).build();
clientChannel.send(errorMessage);
sendMessageToClient(errorMessage);
}
public void forward(M message, StompHeaderAccessor headers) {
......@@ -309,4 +387,5 @@ public class StompRelayPubSubMessageHandler<M extends Message> extends AbstractP
return true;
}
}
}
......@@ -171,7 +171,7 @@ public class PubSubHeaderAccesssor {
if (this.headers.get(headerName) != null) {
return this.headers.get(headerName);
}
else if (this.originalHeaders.get(headerName) != null) {
else if ((this.originalHeaders != null) && (this.originalHeaders.get(headerName) != null)) {
return this.originalHeaders.get(headerName);
}
return null;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册