I have a controller. Obtain data from client and in my service I get messages from API, but using WEBSocket connection. I never worked with WEBSockets before, so I found code example and implemented it. It works fine but the problem is, I have no idea how can I return obtained messages to my controller and to send response to the client.
public void sendRequest(String trader, List<String> cryptoGroup) {
// String json = ...prepare JSON...
try {
// open websocket
final WebsocketClientEndpoint clientEndPoint = new WebsocketClientEndpoint(new URI(link));
// add listener
clientEndPoint.addMessageHandler(System.out::println);
// send message to websocket
clientEndPoint.sendMessage(json);
// wait 5 seconds for messages from websocket
Thread.sleep(5000);
} catch (InterruptedException ex) {
throw new RuntimeException("InterruptedException exception: " + ex.getMessage());
} catch (URISyntaxException ex) {
throw new RuntimeException("URISyntaxException exception: " + ex.getMessage());
}
}
public void addMessageHandler(MessageHandler msgHandler) {
this.messageHandler = msgHandler;
}
public static interface MessageHandler {
public void handleMessage(String message);
}
Maybe there is a some kind of a pattern for such cases, some kind of observer-listener or something... I'll be appreciate for the ideas
Related
In my current code i had a servlet from which if i create post to the servlet it will open a new websocket client , that mean 10 client connection each running for same purpose but with different api and secret , so i need to close particular session
I am using Jetty :: Websocket :: Client v9.4.48.v20220622
Please suggest , as i can get the session details but unable to use because it's not working with String data type . only in Session session it is working and i am unable to store session details anywhere else , as only in String data type i can save .
Whereas a is my API and b is my Secret Key ;
PS : Websocket connection is working fine to send expected data
class connector {
String a;
String b;
public void start() {
WebSocketClient client = new WebSocketClient();
MyWebSocket socket = new MyWebSocket();
try {
client.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
URI destUri = null;
try {
destUri = new URI("wss://socket.delta.exchange");
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ClientUpgradeRequest request = new ClientUpgradeRequest();
System.out.println("Connecting to: " + destUri);
try {
client.connect(socket, destUri, request);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
socket.awaitClose(3600, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
client.stop();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#WebSocket
public class MyWebSocket {
private final CountDownLatch closeLatch = new CountDownLatch(1);
#OnWebSocketConnect
public void onConnect(Session session) throws IOException {
session.getRemoteAddress();
System.out.println("Connection opened");
PingPong newObj = new PingPong();
newObj.session = session;
Authorization authMe = new Authorization();
Identifier getSt = new Identifier();
newObj.enableHeartBeat();
System.out.println(session);
session.getRemote().sendString(authMe.data(a, b));
}
#OnWebSocketMessage
public void onMessage(String message) {
MessageHandler objmsg = new MessageHandler();
objmsg.check();
System.out.println(
"Current Thread ID: "
+ Thread.currentThread().getId());
System.out.println("Message from Server: -- " + message);
}
#OnWebSocketClose
public void onClose(int statusCode, String reason) {
System.out.println("WebSocket Closed. Code:" + statusCode);
}
public boolean awaitClose(int duration, TimeUnit unit)
throws InterruptedException {
return this.closeLatch.await(duration, unit);
}
}
}
I want to do session.close() for a particular session details which i got from
session.getRemoteAddress().toString();
Session session ;
String sessionDetailSaved ;
i want to search for sessionDetailSaved and compare with all the on running sessions and close it
Or else any other way i can close particular session with different method may be interrupting session thread but sure it will not completely close connection .
Maven Dependency i am using
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-client</artifactId>
<version>9.4.48.v20220622</version>
</dependency>
Calling Session.close() will initiate a close handshake where the remote endpoint should reply with a response close frame, and once the close response has been received the WebSocket connection will be closed. You can send custom close status code and reason with Session.close(int statusCode, String reason).
You also have the option to call Session.disconnect() which will do a hard close of the underlying connection without sending this close frame.
In regards to your code, it looks like you are never completing the closeLatch in the OnWebSocketClose method, so your awaitClose method will always timeout.
Also, if possible you should try to re-use the same WebSocketClient instance for multiple connections because it is a heavy weight object. It is expensive to create a new one for each request.
I'm trying to aply Redisson features for my project as message broker and I have a question. Is it possible to push Redisson to precceding recieved messages asynchronously? I have created a small example, sent 4 messages from different URL's. I expected, that Redisson proceeded them asynchronously, but it did it one by one.
Here the implementation:
public class RedisListenerServiceImpl implements MessageListener<String> {
private static final Logger log = LoggerFactory.getLogger(RedisListenerServiceImpl.class);
private final ObjectMapper objectMapper = new ObjectMapper();
#Override
public void onMessage(CharSequence channel, String stringMsg) {
log.info("Message received: {}", stringMsg);
MessageDto msg;
try {
msg = objectMapper.readValue(stringMsg, MessageDto.class);
} catch (final IOException e) {
log.error("Unable to deserialize message: {}", e.getMessage(), e);
return;
}
try {
//Do my stuff
} catch (Exception e) {
log.error("Unable to get service from factory: {}", e.getMessage(), e);
}
}
}
And the config:
#Configuration
public class RedisListenerConfig {
#Autowired
public RedisListenerConfig(RedissonClient redisClient,
MessageListener redisListenerService,
#Value("${redis.sub.key}") String redisSubKey) {
RTopic subscribeTopic = redisClient.getTopic(redisSubKey);
subscribeTopic.addListenerAsync(String.class, redisListenerService);
}
}
It's expected behavior. If you want your messages to be processed concurrently when the Listener onMessage() method is triggered, just use a thread pool to process it.
Since Redisson doesn't know how many threads you want to consume the triggered events, it leaves the implementation detail to you.
public class RedisListenerServiceImpl implements MessageListener<String> {
private static final Logger log = LoggerFactory.getLogger(RedisListenerServiceImpl.class);
private final ObjectMapper objectMapper = new ObjectMapper();
private final ExecutorService executorService = Executors.newFixedThreadPool(10);
#Override
public void onMessage(CharSequence channel, String stringMsg) {
log.info("Message received: {}", stringMsg);
MessageDto msg;
try {
msg = objectMapper.readValue(stringMsg, MessageDto.class);
executorService.submit(()->{
System.out.println("do something with message: "+msg);
});
} catch (final IOException e) {
log.error("Unable to deserialize message: {}", e.getMessage(), e);
return;
}
try {
//Do my stuff
} catch (Exception e) {
log.error("Unable to get service from factory: {}", e.getMessage(), e);
}
}
I am creating a chat application ,one to one chatting is working properly ,but when comes to multi user chat i am not able to listen their messages
I am using smack for implementing the XMPP protocol
Here is the code
Server configuration part is
public void serverCongig() throws XMPPException {
LOGGER.info(String.format("Initializing connection to server %1$s port
%2$d", server, port));
SmackConfiguration.setPacketReplyTimeout(packetReplyTimeout);
config = new ConnectionConfiguration(server,
port,PropertyReader.getPropertiesValue("server_domain"));
// config.setSASLAuthenticationEnabled(false);
config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
connection = new XMPPConnection(config);
try
{
connection.connect();
LOGGER.info("Connected: " + connection.isConnected()+" Service
name"+connection.getServiceName());
chatManager = connection.getChatManager();
messageListener = new MyMessageListener();
}
catch(Exception e)
{
callThread();
e.printStackTrace();
}
finally
{
callThread();
}
}
Message listening part is
class MyMessageListener implements MessageListener {
#Override
public void processMessage(Chat chat, Message message) {
try
{
String from = message.getTo();
String body = message.getBody();
String toUser="";
LOGGER.info(String.format("Received message '%1$s' from %2$s", body, from));
String[] user=from.split("#");
for(int i=0;i<user.length;i++)
toUser=user[0];
LOGGER.info("Receiver Phone number"+toUser);
SendMsgToWhatsapp create=new SendMsgToWhatsapp();
try {
if(!body.equalsIgnoreCase(null))
{
create.processWhatsappMessage(toUser, body);
}
} catch (Exception ex) {
callThread();
// Logger.getLogger(XmppManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
catch(Exception e)
{
e.printStackTrace();
callThread();
}
}
I had a similar question and that's what I found:
XEP-0313: Message Archive Management (https://xmpp.org/extensions/xep-0313.html) describes to work with the message archive.
In smack you can use it like that
MamManager mamManager = MamManager.getInstanceFor(connection);
MamManager.MamQueryArgs mamQueryArgs = MamManager.MamQueryArgs.builder()
.limitResultsToJid(jid)
.setResultPageSizeTo(10)
.queryLastPage()
.build();
MamManager.MamQuery mamQuery = mamManager.queryArchive(mamQueryArgs);
List<Message> messages = mamQuery.getMessages();
for (Message m : messages) {
System.out.println(m.getBody());
}
But when I tried to use it, I received problems with dependencies in maven, so I loaded smack jar manually from dailybuilds (https://download.igniterealtime.org/smack/dailybuilds/smack-SNAPSHOT-2020-07-21.zip) and the remaining dependencies added through maven
In my case it work.
https://download.igniterealtime.org/smack/docs/latest/javadoc/org/jivesoftware/smackx/mam/package-summary.html (smackx.mam javadoc)
I am trying to recieve SNMP v3 traps from a device, using Adventnet.
When getting a trap I see the following AdventNet exception thrown:
Exception while constructing message after receiving PDU. Dropping this PDU received from xxx.xxx.xxx.xxx. com.adventnet.snmp.snmp2.SnmpException: Parse Header: Incorrect Scoped data
If I monitor the traps using NG-Soft browser the traps are recieved correctly.
Here is my code:
private void initV3Parameters(NEData neData) throws InterruptedException
{
logger.debug("in.");
try
{
logger.debug(".in");
SnmpAPI m_api = new SnmpAPI();
m_api.setDebug( true );
SnmpSession m_session = new SnmpSession(m_api);
m_session.addSnmpClient(this);
UDPProtocolOptions m_udpOpt = new UDPProtocolOptions();
m_udpOpt.setRemoteHost(neData.m_szIpAddress);
m_session.setProtocolOptions(m_udpOpt);
try
{
m_session.open();
String message="Succes to bind port: "+session.getLocalPort();
logger.info(message);
System.out.println(message);
}
catch (Exception ex)
{
String message = "Failed to open session - Port in use or permission denied. \n Message- "+ ex.getMessage() + "\n Will exit from Trap process. ";
logger.error(message, ex);
System.err.println(message);
throw new RuntimeException(message);
}
SnmpEngineEntry engineentry = new SnmpEngineEntry(neData.m_szIpAddress, m_udpOpt.getRemotePort());
SnmpEngineTable enginetable = m_api.getSnmpEngine();
enginetable.addEntry(engineentry);
try
{
engineentry.discoverSnmpEngineID(m_session,10000,3);
}
catch (Exception e)
{
logger.error("Failed to discover snmp EngineID. " + e.getMessage());
printToLog("failed",neData);
return;
}
USMUserEntry entry = new USMUserEntry(neData.usmUser.getBytes(), engineentry.getEngineID());
entry.setAuthProtocol(Integer.parseInt(neData.authProtocol));
entry.setAuthPassword(neData.authPassword.getBytes());
entry.setPrivProtocol(Integer.parseInt(neData.privProtocol));
entry.setPrivPassword(neData.privPassword.getBytes());
byte[] authKey = USMUtils.password_to_key(entry.getAuthProtocol(),
neData.authPassword.getBytes(),
neData.authPassword.getBytes().length,
engineentry.getEngineID());
entry.setAuthKey(authKey);
byte[] privKey = USMUtils.password_to_key(entry.getAuthProtocol(),
neData.privPassword.getBytes(),
neData.privPassword.getBytes().length,
engineentry.getEngineID());
entry.setPrivKey(privKey);
entry.setEngineEntry(engineentry);
entry.setSecurityLevel(Snmp3Message.AUTH_PRIV);
SecurityProvider provider = m_api.getSecurityProvider();
USMUserTable userTable = (USMUserTable) provider.getTable(3);
userTable.addEntry(entry);
entry.timeSynchronize(m_session, m_udpOpt);
printToLog("success",neData);
}
catch (Exception exp)
{
logger.error(exp.getMessage()+" for ip = "+neData.m_szIpAddress,exp);
discoveredDeque.put(neData);
printToLog("failed",neData);
}
}
I've also tried Using High-Level API
USMUtils.init_v3_parameters(
neData.usmUser,
null,
Integer.valueOf(neData.authProtocol),
neData.authPassword,
neData.privPassword,
udpOptions,
session,
false,
Integer.valueOf(neData.privProtocol));
In this case I see the trap using public void debugPrint (String debugOutput)
and no exception is throwing.
But there is nothing in the callback
Any advice will be welcome!!!
It turns out that there was a problem with the time synchronization of the device that sends the traps and my code worked perfectly fine.
probably NG-Soft doesn't care from time sync...
I attach my code here in case any of you will need it in the future...
private SnmpSession session;
/**
* Create a listener for trap version 1-2
*/
public void trapsListener ()
{
logger.debug(".in");
SnmpAPI api = new SnmpAPI();
// api.setDebug( true );
session = new SnmpSession(api);
session.addSnmpClient(this);
UDPProtocolOptions udpOpt = new UDPProtocolOptions();
udpOpt.setLocalPort(TRAP_PORT);
session.setProtocolOptions(udpOpt);
try
{
session.open();
String message="Succes to bind port: "+session.getLocalPort();
logger.info(message);
System.out.println(message);
}
catch (Exception ex)
{
String message = "Failed to open session - Port in use or permission denied. \n Message- "+ ex.getMessage() + "\n Will exit from Trap process. ";
logger.error(message, ex);
System.err.println(message);
throw new RuntimeException(message);
}
}
/**
* For each new device
* 1) discover the snmp engineID
* 2) create SnmpEngineEntry and add it to SnmpEngineTable
* 3) create USMUserEntry and add it to USMUserTable
* 4) performs time synchronization
**/
private void initV3Parameters(Device data) throws InterruptedException
{
logger.debug("in.");
try
{
UDPProtocolOptions udpOptions = new UDPProtocolOptions();
udpOptions.setLocalPort(TRAP_PORT);
udpOptions.setRemoteHost(data.getIpAddress());
USMUtils.init_v3_parameters(
data.getUsmUser(),
null,// null means that the SNMPv3 discovery will be activated
Integer.valueOf(data.getAuthProtocol()),
data.getAuthPassword(),
data.getPrivPassword(),
udpOptions,
session,
false,
Integer.valueOf(data.getPrivProtocol()));
printToLog("secsses",data);
}
catch (SnmpException exp) {
logger.error(exp.getMessage()+" for ip = "+data.getIpAddress(),exp);
printToLog("failed",data);
}
}
The below is my Websocket subscription code.
Client side:
var request = '{"sessionId": "_fjuhdf896786767", "username":"admin", "status":true}'
ws = new WebSocket(wsUri);
console.log("registered");
ws.onopen = function() {
console.log("connection opened!")
ws.send(request);
}
ws.onmessage = function(msg) {
console.log("received message:");
window.getData(JSON.parse(msg.data));
}
At server side, the implementioation of websocket is below:
#ServerEndPoint(value="/status")
public class WebsocketServer {
#OnOpen
public void OpenMsg(Session session, EndpointConfig cnfg) {
String retdata = "";
try {
if (session.isOpen()) {
log.info("OpenMsg() payload req data from client" + decoder);
retdata = getCount(decoder);
log.info("OpenMsg() retdata " + retdata);
session.getBasicRemote().sendText(retdata.toString());
try {
Thread.sleep(pollinterval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
try {
session.close();
log.error("Exception occured while Opening WS Session");
e.printStackTrace();
} catch (IOException e1) {
// Ignore
}
}
}
}
I would like to know how to read the json request string from "ws.send(request);" at the server side(javax.websocket).
I saw Encoder and Decoder, but in this case i am only sending the json request as a string which is not encoded as shown above.
Could any body tell me, how to read json string as a payload in Javax.websocket.
I guess that a simple JSON reader will do the trick:
#OnMessage
public void onMessage(Session session, String message) {
JsonObject json = Json.createReader(new StringReader(message)).readObject();
System.out.println("Received json: " + json);
// or do something more JSON-like:
// String myField = json.getString("key");
}
Encoder and decoder are not directly linked to payload but rather if you wish to directly manipulate object. If you're using decoders, your onMessage method can look like
#OnMessage
public void onMessage(Session session, MyMessageClass message){
String myInput = message.getInput();
String otherUsefulInformation = message.getInformation();
}
and when you're using encoder, it's about sending object instead of plain text:
#OnMessage
public void onMessage(Session session, MyMessageClass message){
// process input
MyAnswerClass answer = new MyAnswerClass(...);
session.getBasicRemote().sendObject(answer);
// without encoder, you are bound to use
// session.getBasicRemote().sendText(...)
// or
// session.getBasicRemote().sendBinary(...)
}
you can use annotation "ClientEndPoint" on your client side :
#ClientEndpoint(encoders = MessageEncoder.class, decoders = MessageDecoder.class)
use : Session.getBasicRemote().sendObject(message);
class MessageEncoder implements Encoder.Text<Message>
class MessageDecoder implements Decoder.Text<Message>
Oracle Using WebSocket Protocal in WebLogic Server
Oracle OnMessage Interface
Be sure to implement the OnMessage Interface
#OnMessage
public void handleMessage(String message, Session session) {
// message will contain the body content you sent
}