I'm trying to send messages to my topic, but the problem is when I send the message nothing happens... I'm using apache tomcat 7.0.53
UPDATE: 04/15: Link to test:
http://ec2-54-187-72-145.us-west-2.compute.amazonaws.com:8080/kupo
Login: admin
Password: admin
LINK TO ACCESS TOMCAT LOG:
http://ec2-54-187-72-145.us-west-2.compute.amazonaws.com:28778/
P.S: You need to checked the combobox on the sidebar to start watch the messages
Github Link: https://github.com/tiarebalbi/kupo
LOG:
DEBUG - gWebSocketHandlerDecorator - Connection established, SockJS session id=_mqg8qer, uri=/kupo/application/807/_mqg8qer/websocket
DEBUG - StompDecoder - Decoded [Payload byte[0]][Headers= {stompCommand=CONNECT, nativeHeaders={heart-beat=[10000,10000], accept-version=[1.1,1.0]}, simpMessageType=CONNECT, id=e79a615e-5522-a0f9-aecf-6ea5a54b3d9b, timestamp=1397013491497}]
DEBUG - StompEncoder - Encoded STOMP command=CONNECTED headers={user-name=[balbi], heart-beat=[0,0], version=[1.1]}
DEBUG - StompDecoder - Decoded [Payload byte[0]][Headers={stompCommand=SUBSCRIBE, nativeHeaders={id=[sub-0], destination=[/topic/greetings]}, simpMessageType=SUBSCRIBE, simpSubscriptionId=sub-0, simpDestination=/topic/greetings, id=42c2019d-96a0-95f0-29aa-2bcc62d6d721, timestamp=1397013491501}]
CODE:
#Service
public class ExampleServiceImpl implements ApplicationListener<BrokerAvailabilityEvent> {
private AtomicBoolean brokerAvailable = new AtomicBoolean();
#Autowired
private MessageSendingOperations<String> messagingTemplate;
#Override
public void onApplicationEvent(BrokerAvailabilityEvent event) {
this.brokerAvailable.set(event.isBrokerAvailable());
}
#Scheduled(fixedDelay=3000)
public void testing() {
if (this.brokerAvailable.get()) {
this.messagingTemplate.convertAndSend("/topic/greetings", "Testing....");
}
}
Javascript Connect:
var socket = new SockJS('/kupo/application'); // <!-- My endpoint
var stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
var username = frame.headers['user-name'];
console.log("User connected: " + username);
stompClient.subscribe("/topic/greetings", function(message) { // <-- Topic where I want to received the message
console.log("TOPIC:",message);
});
} , function(error) {
console.log("STOMP protocol error " + error);
});
Browser Console:
Opening Web Socket... stomp.min.js:8
Web Socket Opened... stomp.min.js:8
>>> CONNECT
accept-version:1.1,1.0
heart-beat:10000,10000
<<< CONNECTED
user-name:balbi
heart-beat:0,0
version:1.1
connected to server undefined stomp.min.js:8
User connected: balbi
>>> SUBSCRIBE
id:sub-0
destination:/topic/greetings
Websocket Context Configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketApplicationContext extends AbstractWebSocketMessageBrokerConfigurer {
#Autowired
private Environment env;
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
if (env.acceptsProfiles("test.tomcat")) {
registry.addEndpoint("/application")
.setHandshakeHandler(
new DefaultHandshakeHandler(new TomcatRequestUpgradeStrategy()))
.withSockJS();
} else {
registry.addEndpoint("/application").withSockJS();
}
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue/", "/topic/");
registry.setApplicationDestinationPrefixes("/app");
}
}
When connecting to your application, I managed to send a message to a topic from the JavaScript console and get a message back in the web page.
var socket = new SockJS('/kupo/application');
var stompClient = Stomp.over(socket);
stompClient.send('/topic/greetings',{},"hello");
And I received:
<<< MESSAGE
subscription:sub-0
content-length:5
message-id:ts3oov6b-1
destination:/topic/greetings
content-length:5
hello
Is your Scheduling task being called as expected?
Why are you, in your main configuration, importing some Configurations and still scanning the configuration package? Shouldn't it be one or the other?
Related
I am using netty-socket.io and I implemented the server like the demo.
I receive onConnect event both on server and client, but when I sent a message {message: message} I don't get anything on the server event though I see the message being sent in the network tab.
Configuration config = new Configuration();
config.setHostname("localhost");
config.setPort(9092);
final SocketIOServer server = new SocketIOServer(config);
server.addConnectListener(socketIOClient -> System.out.println("Connection test"));
server.addEventListener("messageevent", MessageEventObject.class, new DataListener<MessageEventObject>() {
#Override
public void onData(SocketIOClient socketIOClient, MessageEventObject messageEventObject, AckRequest ackRequest) throws Exception {
System.out.println("message received!");
}
});
server.start();
My MessageEventObject has String message property, constructor getters and setters, looking the same as client-sided.
And this is my websocket service client-sided:
export class WebsocketService {
private socket;
private subject = new Subject < any > ();
constructor() {
console.log('test!');
}
public connect(host: string, port: number) {
this.socket = io(`http://${host}:${port}`, {
'reconnection': false
});
this.socket.on('connect', this.onConnected);
this.socket.on('connect_error', this.onConnectionFailure);
}
public getConnectionStateUpdate(): Observable < any > {
return this.subject.asObservable();
}
public sendMessage(message: string) {
console.log('test');
this.socket.emit('messageevent', {
message: message
});
}
private onConnected = () => {
this.subject.next({
connected: true
});
}
private onConnectionFailure = () => {
this.subject.next({
connected: false
});
}
}
Is there anything that I did wrong?
I would love to answer my own question after tons of debugging and breaking my head, my laziness to use Engine IO with tomcat or jetty, and just wanting to use that awesome netty package which does not require any servlets, I tried to fix it and figure out.
At first I thought it was the client's protocol version, so I used the exact same client as the demo shows on their github page here but that didn't work so the problem is server-sided.
It appears that your object (MessageEventObject) must have a default empty constructor aswell in addition to your other constructors, probably because netty tries to build an empty object and it fails which causes an exception that you don't see.
I created a new verticle that should response for HTTP requests and SockJS bridged events. Based on this question https://stackoverflow.com/questions/41516328 and vert.x manual https://vertx.io/docs/vertx-web/java/#_sockjs I created this piece of code:
Java:
#Override
public void start(Future<Void> startFuture) throws Exception {
startHttpServer(startFuture);
startSockJSHandler();
}
private void startHttpServer(Future<Void> startFuture) {
HttpServer server = vertx.createHttpServer(new HttpServerOptions());
server.requestHandler(req -> {
System.out.println("[" + new Date().toString() + "] Request #" + ++requestCount);
if (req.path().contains("http")) {
req.response().putHeader("Access-Control-Allow-Origin", "*").end("req_num: " + requestCount);
}
}).listen(8080, ar -> startFuture.handle(ar.mapEmpty()));
}
private void startSockJSHandler() {
Router router = Router.router(vertx);
SockJSHandlerOptions sockJSOptions = new SockJSHandlerOptions().setHeartbeatInterval(2000);
SockJSHandler sockJSHandler = SockJSHandler.create(vertx, sockJSOptions);
BridgeOptions bridgeOptions = new BridgeOptions();
bridgeOptions.addInboundPermitted(new PermittedOptions().setAddressRegex(".*")).addOutboundPermitted(new PermittedOptions().setAddressRegex(".*"));
sockJSHandler.bridge(bridgeOptions, be -> {
System.out.println("BRIDGE EVENT: " + be.type().toString());
});
router.route("/eventbus/*").handler(sockJSHandler);
}
JavaScript eventbus client:
var sock = new SockJS('http://localhost:8080/eventbus/');
sock.onopen = function() {
console.log('open');
sock.send('test');
};
sock.onmessage = function(e) {
console.log('message', e.data);
sock.close();
};
sock.onclose = function() {
console.log('close');
};
HTTP request/response works fine, but SockJS events not. In web browser 'Network' module I see only one SockJS request (http://localhost:8080/eventbus/info). 8 seconds in 'pending' status, and after this time the status is changed to 'closed' (method onclose() is called at the end).
Did I do something wrong?
The HttpServer must delegate requests to the Router. Otherwise nothing happens. Usually, it is configured to delegate all requests to the Router.
server.requestHandler(router::accept).listen(8080);
See Basic Vert.x-Web concepts in the docs.
I know spring integration has TcpInboundGateway and ByteArrayStxEtxSerializer to handle data coming through TCP port.
ByteArrayStxEtxSerializer works great if the TCP server needs to read all the data sent from the client and then processes it. (request and response model) I am using single-use=false so that multiple requests can be processed in the same connection.
For example if the client sends 0x02AAPL0x03 then Server can send the AAPL price.
My TCP Server is working if the client sends 0x02AAPL0x030x02GOOG0x03. It sends the price of AAPL and GOOG price.
Sometimes clients can send EOT (0x04). If the client sends EOT, I would like to close the socket connection.
For example: Client request can be 0x02AAPL0x030x02GOOG0x03 0x020x040x03. Note EOT came in the last packet.
I know ByteArrayStxEtxSerializer deserializer can be customized to read the bytes sent by the client.
is deserializer good place to close socket connection? if not, how should spring integration framework be notified to close socket connection?
Please help.
Here is my spring configuration:
<int-ip:tcp-connection-factory id="crLfServer"
type="server"
port="${availableServerSocket}"
single-use="false"
so-timeout="10000"
using-nio="false"
serializer="connectionSerializeDeserialize"
deserializer="connectionSerializeDeserialize"
so-linger="2000"/>
<bean id="connectionSerializeDeserialize" class="org.springframework.integration.ip.tcp.serializer.ByteArrayStxEtxSerializer"/>
<int-ip:tcp-inbound-gateway id="gatewayCrLf"
connection-factory="crLfServer"
request-channel="serverBytes2StringChannel"
error-channel="errorChannel"
reply-timeout="10000"/> <!-- reply-timeout works on inbound-gateway -->
<int:channel id="toSA" />
<int:service-activator input-channel="toSA"
ref="myService"
method="prepare"/>
<int:object-to-string-transformer id="serverBytes2String"
input-channel="serverBytes2StringChannel"
output-channel="toSA"/>
<int:transformer id="errorHandler"
input-channel="errorChannel"
expression="payload.failedMessage.payload + ':' + payload.cause.message"/>
UPDATE:
Adding throw new SoftEndOfStreamException("Stream closed") to close the stream in serializer works and I can see the CLOSED log entry in EventListener. When the server closes the connection, I expect to receive java.io.InputStream.read() as -1 in the client. But the client is receiving the
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at sun.nio.cs.StreamDecoder.read0(StreamDecoder.java:107)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:93)
at java.io.InputStreamReader.read(InputStreamReader.java:151)
is there anything else to close the connection on the server side and propagate it to client?
I appreciate your help.
Thank you
The deserializer doesn't have access to the socket, just the input stream; closing it would probably work, but you will likely get a lot of noise in the log.
The best solution is to throw a SoftEndOfStreamException; that signals that the socket should be closed and everything cleaned up.
EDIT
Add a listener to detect/log the close...
#SpringBootApplication
public class So40471456Application {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(So40471456Application.class, args);
Socket socket = SocketFactory.getDefault().createSocket("localhost", 1234);
socket.getOutputStream().write("foo\r\n".getBytes());
socket.close();
Thread.sleep(10000);
context.close();
}
#Bean
public EventListener eventListener() {
return new EventListener();
}
#Bean
public TcpNetServerConnectionFactory server() {
return new TcpNetServerConnectionFactory(1234);
}
#Bean
public TcpReceivingChannelAdapter inbound() {
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
adapter.setConnectionFactory(server());
adapter.setOutputChannelName("foo");
return adapter;
}
#ServiceActivator(inputChannel = "foo")
public void syso(byte[] in) {
System.out.println(new String(in));
}
public static class EventListener implements ApplicationListener<TcpConnectionCloseEvent> {
private final Log logger = LogFactory.getLog(getClass());
#Override
public void onApplicationEvent(TcpConnectionCloseEvent event) {
logger.info(event);
}
}
}
With XML, just add a <bean/> for your listener class.
Result:
foo
2016-11-07 16:52:04.133 INFO 29536 --- [pool-1-thread-2] c.e.So40471456Application$EventListener : TcpConnectionCloseEvent
[source=org.springframework.integration.ip.tcp.connection.TcpNetConnection#118a7548],
[factory=server, connectionId=localhost:50347:1234:b9fcfaa9-e92c-487f-be59-1ed7ebd9312e]
**CLOSED**
EDIT2
It worked as expected for me...
#SpringBootApplication
public class So40471456Application {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(So40471456Application.class, args);
Socket socket = SocketFactory.getDefault().createSocket("localhost", 1234);
socket.getOutputStream().write("foo\r\n".getBytes());
try {
System.out.println("\n\n\n" + socket.getInputStream().read() + "\n\n\n");
context.getBean(EventListener.class).latch.await(10, TimeUnit.SECONDS);
}
finally {
socket.close();
context.close();
}
}
#Bean
public EventListener eventListener() {
return new EventListener();
}
#Bean
public TcpNetServerConnectionFactory server() {
TcpNetServerConnectionFactory server = new TcpNetServerConnectionFactory(1234);
server.setDeserializer(is -> {
throw new SoftEndOfStreamException();
});
return server;
}
#Bean
public TcpReceivingChannelAdapter inbound() {
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
adapter.setConnectionFactory(server());
adapter.setOutputChannelName("foo");
return adapter;
}
public static class EventListener implements ApplicationListener<TcpConnectionCloseEvent> {
private final Log logger = LogFactory.getLog(getClass());
private final CountDownLatch latch = new CountDownLatch(1);
#Override
public void onApplicationEvent(TcpConnectionCloseEvent event) {
logger.info(event);
latch.countDown();
}
}
}
Result:
2016-11-08 08:27:25.964 INFO 86147 --- [ main] com.example2.So40471456Application : Started So40471456Application in 1.195 seconds (JVM running for 1.764)
-1
2016-11-08 08:27:25.972 INFO 86147 --- [pool-1-thread-2] c.e.So40471456Application$EventListener : TcpConnectionCloseEvent [source=org.springframework.integration.ip.tcp.connection.TcpNetConnection#fee3774], [factory=server, connectionId=localhost:54984:1234:f79a6826-0336-4823-8844-67054903a094] **CLOSED**
I'm newbie to the web-socket programming...
I have the following JavaScript client code:
var connection = new WebSocket('ws://localhost:8080/OmegaThings/registerdevice');
connection.onopen = function () {
console.log("Socket has been opened state = " + connection.readyState);
connection.send('Ping'); // Send the message 'Ping' to the server
connection.send('Websocket client');
};
console.log("Socket has been opened state = " + connection.readyState);
connection.send('finish');
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
Java endpoint:
#ServerEndpoint("/registerdevice")
public class RegisterDeviceEndPoint
{
private static final Logger LOG = Logger.getLogger(RegisterDeviceEndPoint.class.getName());
#OnOpen
public void connectionOpened()
{
LOG.log(Level.INFO, "******************connection opened**************");
}
#OnMessage
public synchronized void processMessage(Session session, String message)
{
LOG.log(Level.INFO, "received message: {0}", message);
}
#OnClose
public void connectionClosed()
{
LOG.log(Level.INFO, "connection closed");
}
}
on the firefox console I got the following output:
"Socket has been opened state = 1"
InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable
"Socket has been opened state = 0"
on the GlassFish server log I got "ping" and "Websocket client", but the connection closed after onopen event exit(not sure), thus, the last word "finish" doesn't appear on the log and the error occurs.
I want to know if my code is correct?
What causes the error? javascript code, GlassFish server configuration or the java endpoint code?
Try to change the glassfish 8080 port, eg: 8887, or make sure Your antivirus/other application are not using port 80, I previously had experience where my server websocket was blocked by antivirus which using port 80.
Im trying to connect from a Java client i am writing to my nodejs sockjs server.
The sockjs server is just a simple echo server, taken from the examples on git:
var http = require('http');
var sockjs = require('sockjs');
var node_static = require('node-static');
// 1. Echo sockjs server
var sockjs_opts = {sockjs_url: "http://cdn.sockjs.org/sockjs-0.3.min.js"};
var sockjs_echo = sockjs.createServer(sockjs_opts);
sockjs_echo.on('connection', function(conn) {
conn.on('data', function(message) {
conn.write(message);
});
});
// 2. Static files server
var static_directory = new node_static.Server(__dirname);
// 3. Usual http stuff
var server = http.createServer();
server.addListener('request', function(req, res) {
static_directory.serve(req, res);
});
server.addListener('upgrade', function(req,res){
res.end();
});
sockjs_echo.installHandlers(server, {prefix:'/echo'});
console.log(' [*] Listening on 0.0.0.0:8080' );
server.listen(8080, '0.0.0.0');
Now i've tried to connect from my Java client with the following:
public static void connect() throws Exception {
final WebSocket ws = new WebSocket();
ws.addWebSocketListener(
new WebSocketAdapter() {
#Override
public void onMessage(WebSocketEvent messageEvent) {
System.out.println("Received Event Data: " + messageEvent.getData());
// let's close the open connection...
try {
ws.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onOpen(WebSocketEvent openEvent) {
System.out.println("Connection to Server is up!");
// we are able to talk to the WebSocket gateway
try {
ws.send("Hey, server!");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
);
ws.connect(new URI("ws://server.hello.com:8080/echo/websocket"));
}
The error i am getting when my java client tried to connect is:
com.kaazing.gateway.client.html5.impl.bridge.BridgeUtil
initCrossOriginProxy WARNING: Unable to connect: the Gateway may not
be running, a network route may be unavailable, or the Gateway may not
be configured properly
Any ideas what could be wrong?