I am setting up the Backend code of a chat messaging system for an app my group is creating using WebSockets. My goal is for our app to be able to send and receive messages in a public group chat, and also specifically Direct Message (DM) specific people with an # symbol, in front of the recipient's username.
I managed to get the public group messaging component working perfectly fine. However, I am running into an issue with the DM functionality. Let's say for example a person named "test" wrote a message to someone named "teacher" and here was what they typed: "#teacher testMessage". Ideally, I would want the program to send the message "testMessage" to "teacher" only. However, every time I would test the program using Postman, I would end up with the following error:
java.lang.NullPointerException: Cannot invoke "javax.websocket.Session.getBasicRemote()" because the return value of "java.util.Map.get(Object)" is null
From my understanding, the error means that the variable type the method is supposed to receive (in this case a String), is not what it is actually getting.
Here is the code below:
private static Map < Session, String > sessionUsernameMap = new Hashtable<>();
private static Map < String, Session > usernameSessionMap = new Hashtable<>();
#OnMessage
public void onMessage(Session session, String message) throws IOException { //The message is the the entire thing that the person types (ex: #teacher testMessage)
logger.info("Message Received: " + message); //String message = #teacher testMessage
String username = sessionUsernameMap.get(session); //String username = "test" This is the username of the person who wrote the message
if (message.startsWith("#")) {
String destUsername = message.split(" ")[0].substring(1); //destUsername = "teacher"
String realMessage = message.substring(message.lastIndexOf(" ") + 1); //realMessage = "testMessage"
sendMessageToParticularUser(destUsername, "[DM] " + username + ": " + realMessage); //puts in "teacher" for destUsername and "testMessage" for realMessage
sendMessageToParticularUser(username, "[DM] " + username + ": " + message);
}
else {
broadcast(username + ": " + message);
}
msgRepo.save(new Message(username, message));
}
private void sendMessageToParticularUser(String username, String message) {
System.out.println(message);
try {
usernameSessionMap.get(username).getBasicRemote().sendText(message); //PROBLEM RIGHT HERE WITH .get(username)
} catch (IOException e) {
logger.info("Exception: " + e.getMessage().toString());
e.printStackTrace();
}
}
I have been working on this issue for a few hours now with no luck. I would very much appreciate any help or input on this. Thank you.
Related
I'm currently trying to code a discord bot and am working on the onMessageReaction events so that whenever someone were to react to a message it would notify in this format. "user reacted to a message with "happy face" in the #general channel!"
However, I'm getting this error(title name) when trying to use the .getReactionEmote() method call in the event class. Am I calling the method incorrectly?
Cheers.
#Override
public void onMessageReactionAdd(#NotNull MessageReactionAddEvent event) {
// B-Nard reacted to a message with "happy face" in the #general channel
User user = event.getUser();
String emoji = event.getReaction().getReactionEmote().getAsReactionCode();
String channelName = event.getChannel().getAsMention();
String jumpLink = event.getJumpUrl();
String message = user.getAsTag() + " reacted to a message with " + emoji + " in the " + channelName + " channel!";
}
This is how my code is looking :
public void onGuildVoiceJoin(GuildVoiceJoinEvent event) {
String channelId = event.getChannelJoined().getId();
if (channelId.equals("904375329764814870")) {
Member member = event.getMember();
String memberName = event.getMember().getEffectiveName();
Category category = event.getGuild().getCategoryById("904364634507706468");
event.getGuild().createVoiceChannel("Coaching " + memberName).setParent(category).complete();
List<VoiceChannel> channelList = event.getGuild().getVoiceChannelsByName("Coaching " + memberName, true);
VoiceChannel channel = channelList.get(0);
event.getGuild().moveVoiceMember(member, channel).queue();
while (true){
event.getGuild().getTextChannelById("904364671467929610").sendMessage(
"Number of people currently on the channel : " + channel.getMembers().size()
).queue();
wait(3000);
}
My goal is to get the number of people currently inside the channel.
I thought the getMembers() method was the good method, but it's not working
I use the infinite while to see if the channel.getMembers().size() changes when i join/leave the channel but it still return 0.
How can i fix this ? And get the correct amount of people inside the channel as return.
The final goal of my code is to delete the channel when he's empty of user
This can be achieved by just checking the member count in the GuildVoiceUpdateEvent:
public void onGuildVoiceUpdate(GuildVoiceUpdateEvent event) {
if (channel.getName().startsWith("Coaching ")) { // check if name matches the desired name
if (channel.getMembers().isEmpty()) { // check if channel is empty
channel.delete().queue(); // delete channel
}
}
}
I got an error in my quickfixj Application. First, I got an error like this:
Out of order repeating group members
After that, I added this text into my initiator.config:
ValidateUserDefinedFields=N
ValidateIncomingMessage=N
But now I got another error in my application:
quickfix.FieldNotFound: Field was not found in message, field=55
at quickfix.FieldMap.getField(FieldMap.java:223)
at quickfix.FieldMap.getString(FieldMap.java:237)
at com.dxtr.fastmatch.marketdatarequestapps.TestMarketdataRequest.fromApp(TestMarketdataRequest.java:38)
at quickfix.Session.fromCallback(Session.java:1847)
at quickfix.Session.verify(Session.java:1791)
at quickfix.Session.verify(Session.java:1862)
at quickfix.Session.next(Session.java:1047)
at quickfix.Session.next(Session.java:1204)
at quickfix.mina.SingleThreadedEventHandlingStrategy$SessionMessageEvent.processMessage(SingleThreadedEventHandlingStrategy.java:163)
at quickfix.mina.SingleThreadedEventHandlingStrategy.block(SingleThreadedEventHandlingStrategy.java:113)
at quickfix.mina.SingleThreadedEventHandlingStrategy.lambda$blockInThread$1(SingleThreadedEventHandlingStrategy.java:145)
at quickfix.mina.SingleThreadedEventHandlingStrategy$ThreadAdapter$RunnableWrapper.run(SingleThreadedEventHandlingStrategy.java:267)
at java.lang.Thread.run(Thread.java:748)
My code for get value of symbols is :
public void fromApp(quickfix.Message message, SessionID sessionID)
throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType {
try {
String symbol = message.getString(Symbol.FIELD);
System.out.println(" FromApp " + message);
message.getString(TransactTime.FIELD);
// String seqNo = message.getString(MsgSeqNum.FIELD);
double bid = message.getDouble(MDEntryPx.FIELD);
double ask = message.getDouble(MDEntryPx.FIELD);
// System.out.println(seqNo + " " + message);
} catch (FieldNotFound fieldNotFound) {
fieldNotFound.printStackTrace();
}
}
I have also using this code
public void onMessage (MarketDataIncrementalRefresh message, SessionID sessionID) throws FieldNotFound{
try
{
MDReqID mdreqid = new MDReqID();
SendingTime sendingtime = new SendingTime();
NoMDEntries nomdentries = new NoMDEntries();
quickfix.fix42.MarketDataIncrementalRefresh.NoMDEntries group
= new quickfix.fix42.MarketDataIncrementalRefresh.NoMDEntries();
MDUpdateAction mdupdateaction = new MDUpdateAction();
DeleteReason deletereason = new DeleteReason();
MDEntryType mdentrytype = new MDEntryType();
MDEntryID mdentryid = new MDEntryID();
Symbol symbol = new Symbol();
MDEntryOriginator mdentryoriginator = new MDEntryOriginator();
MDEntryPx mdentrypx = new MDEntryPx();
Currency currency = new Currency();
MDEntrySize mdentrysize = new MDEntrySize();
ExpireDate expiredate = new ExpireDate();
ExpireTime expiretime = new ExpireTime();
NumberOfOrders numberoforders = new NumberOfOrders();
MDEntryPositionNo mdentrypositionno = new MDEntryPositionNo();
message.getField(nomdentries);
message.getField(sendingtime);
message.getGroup(1, group);
int list = nomdentries.getValue();
for (int i = 0; i < list; i++)
{
message.getGroup(i + 1, group);
group.get(mdupdateaction);
if (mdupdateaction.getValue() == '2')
System.out.println("Enter");
group.get(deletereason);
group.get(mdentrytype);
group.get(mdentryid);
group.get(symbol);
group.get(mdentryoriginator);
if (mdupdateaction.getValue() == '0')
group.get(mdentrypx);
group.get(currency);
if (mdupdateaction.getValue() == '0')
group.get(mdentrysize);
}
System.out.printf("Got Symbol {0} Price {1}",
symbol.getValue(), mdentrypx.getValue());
}catch (Exception ex)
{
System.out.println("error" + ex);
}
but i also get error like this
quickfix.FieldNotFound: Field was not found in message, field=55
at quickfix.FieldMap.getField(FieldMap.java:223)
at quickfix.FieldMap.getString(FieldMap.java:237)
at com.dxtr.fastmatch.marketdatarequestapps.TestMarketdataRequest.fromApp(TestMarketdataRequest.java:39)
at quickfix.Session.fromCallback(Session.java:1847)
at quickfix.Session.verify(Session.java:1791)
at quickfix.Session.verify(Session.java:1862)
at quickfix.Session.next(Session.java:1047)
at quickfix.Session.next(Session.java:1204)
at quickfix.mina.SingleThreadedEventHandlingStrategy$SessionMessageEvent.processMessage(SingleThreadedEventHandlingStrategy.java:163)
at quickfix.mina.SingleThreadedEventHandlingStrategy.block(SingleThreadedEventHandlingStrategy.java:113)
at quickfix.mina.SingleThreadedEventHandlingStrategy.lambda$blockInpacket_write_wait: Connection to 3.13.235.241 port 22: Broken pipe
and here the value i check in my message.log
8=FIX.4.2^A9=0217^A35=X^A34=7291^A49=Fastmatch1^A52=20200401-10:47:59.833^A56=MDValueTrade2UAT1^A262=VT_020^A268=02^A279=2^A55=GBP/CHF^A269=0^A278=1140851192^A270=1.19503^A271=02000000^A279=0^A55=GBP/CHF^A269=0^A278=1140851194^A270=1.19502^A271=06000000^A10=114^A
my broker have send to me the price and etc
My question is: how to fix my problem from this code ?
First, I got an error like this:
Out of order repeating group members
Your data dictionary doesn't match your counterparty's. Fix that and this will go away.
After that, I added this text into my initiator.config:
ValidateUserDefinedFields=N
ValidateIncomingMessage=N
This did not fix anything -- it HIDES your actual problem and has you looking at a new fake problem.
What you need to do:
Your configuration has this, right?
UseDataDictionary=Y
DataDictionary=path/to/FIXnn.xml
# or if FIX5:
AppDataDictionary=path/to/FIX5n.xml
TransportDataDictionary=path/to/FIXT.xml
Find your counterparty's documentation, and make sure your xml file's messages and fields match what they say they're going to send you. Make sure all repeating groups have the same fields in the same order.
Here is some documentation about how the Data Dictionary xml file is structured. It's pretty easy.
could someone help me. Here is my problem :
I try to send an object with jms (this part works) and receive it with jms.
My object is quite simple. 3 String, 3 int, and a boolean.
There are no problem of connexion or anything like this. I receive the object but it's as if I received every things one by one.
Here is my MessageListener :
MessageListener listner = new MessageListener() {
public void onMessage(Message message) {
ObectToSend yo=null;
try {
if (message instanceof ObjectMessage) {
ObjectMessage myMessage = (ObjectMessage) message;
System.err.println("test");
yo = (ObectToSend) myMessage.getObject();
System.err.println("test2");
System.err.println(yo.entite + " " + yo.error + " " + yo.idGloreg + " " + yo.indPerso + " " + yo.nom + " " + yo.prenom + " " + yo.nom);
}
} catch (JMSException e) {
System.out.println("Caught:" + e);
e.printStackTrace();
}
}
};
And that my sending part :
Serializable ObectTest = new ObectToSend("pro", "enc", 134, 10, true, "yayaya", 0);
MessageProducer producer = session.createProducer(topic);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
ObjectMessage message = session.createObjectMessage();
message.setObject(ObectTest);
connection.start();
producer.send(message);
Finally here is what I want to send (in receiver.java and sender.java) :
public static class ObectToSend implements Serializable{
private static final long serialVersionUID = 1L;
String prenom;
String nom;
int idGloreg;
int indPerso;
boolean ok;
String entite;
int error;
ObectToSend(String prenomP, String nomP, int idGloregP, int indPersoP, boolean okP, String entiteP, int errorP){
prenom = prenomP ;
nom= nomP;
idGloreg = idGloregP;
indPerso = indPersoP;
ok = okP;
entite= entiteP;
error = errorP;
}
}
My console :
test
test
test
test
test
test
test
If someone could tell me what's the problem that would be great. I don't get it. My textmessage with topic/queue/sync/async are working so nicely. It comes to object and....
It seems the problem is here :
yo = (ObectToSend) myMessage.getObject();
but.....
For future users of JMS I will answer my own question.
It was really hard to find any information as it's not explained in JMS documentation.
I found a lot of people asking how to do it but never had any answer. That's because it's not releated to JMS but to Java.
So here it goes :
If you want to use a same classe (object) like
ObectToSend yo = (ObectToSend) myMessage.getObject();
My first object (yo) is from the class ObectToSend.java in the package com.test.jms and my second object (myMessage.getObject() ) is from the package com.test.jms2. So I have an exception like "notfoundclass". And cannot cast objects.
The class ObectToSend.java should be in both projects. But you can't just copy paste with the same name (what I stupidly did).
You need to create a jar of the class used in both projects/packages and add it to both projects.
That way you use EXACTLY the same class and not a copy of it. And your 2 objects are exactly the same.
You could also use a map message. Indeed, you only have strings, ints, and booleans. You actually don't need an object. MapMessage is here for you and is much much simpler.
Here is an exemple :
// create mapMessage
message = session.createMapMessage();
// Here insert variables in properties of the message
// This can be filtred with selector
message.setStringProperty("entity", entity);
message.setStringProperty("messageFrom", messageFrom);
// Here insert variables in body of the message
//This CAN'T be filtred (what you want I think)
message.setString("title", title);
message.setString("description", description);
// Get map message
MapMessage mapMessage = (MapMessage) message;
// Here get variables of your message
String title = mapMessage.getString("title");
String description = mapMessage.getString("description");
See how simple it is ?
I have been trying several approaches to retrieve all messages from the SQS queue by using AWS SDK for Java to no avail. I have read about the distributed nature of the AWS SQS and that messages are stored on the different servers. But what I do not understand is why this architecture is not hidden from the end user. What tricks do I have to apply in Java code to retrieve all messages and be 100% sure that no one was missed?
I tried this with the "Long Polling":
ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(myQueueUrl);
List<Message> messages = sqs.receiveMessage(receiveMessageRequest).getMessages();
for (Message message : messages) {
System.out.println(" Message");
System.out.println(" MessageId: " + message.getMessageId());
System.out.println(" ReceiptHandle: " + message.getReceiptHandle());
System.out.println(" MD5OfBody: " + message.getMD5OfBody());
System.out.println(" Body: " + message.getBody());
for (Entry<String, String> entry : message.getAttributes().entrySet()) {
System.out.println(" Attribute");
System.out.println(" Name: " + entry.getKey());
System.out.println(" Value: " + entry.getValue());
}
}
System.out.println();
And this with Request Batching / Client-Side Buffering:
// Create the basic Amazon SQS async client
AmazonSQSAsync sqsAsync = new AmazonSQSAsyncClient();
// Create the buffered client
AmazonSQSAsync bufferedSqs = new AmazonSQSBufferedAsyncClient(sqsAsync);
CreateQueueRequest createRequest = new CreateQueueRequest().withQueueName("MyTestQueue");
CreateQueueResult res = bufferedSqs.createQueue(createRequest);
SendMessageRequest request = new SendMessageRequest();
String body = "test message_" + System.currentTimeMillis();
request.setMessageBody( body );
request.setQueueUrl(res.getQueueUrl());
SendMessageResult sendResult = bufferedSqs.sendMessage(request);
ReceiveMessageRequest receiveRq = new ReceiveMessageRequest()
.withMaxNumberOfMessages(10)
.withQueueUrl(queueUrl);
ReceiveMessageResult rx = bufferedSqs.receiveMessage(receiveRq);
List<Message> messages = rx.getMessages();
for (Message message : messages) {
System.out.println(" Message");
System.out.println(" MessageId: " + message.getMessageId());
System.out.println(" ReceiptHandle: " + message.getReceiptHandle());
System.out.println(" MD5OfBody: " + message.getMD5OfBody());
System.out.println(" Body: " + message.getBody());
for (Entry<String, String> entry : message.getAttributes().entrySet()) {
System.out.println(" Attribute");
System.out.println(" Name: " + entry.getKey());
System.out.println(" Value: " + entry.getValue());
}
}
But I am still unable to retrieve all messages.
Any idea?
AWS Forum keeps silence on my post.
When receiving messages from an SQS queue, you need to repeatedly call sqs:ReceiveMessage.
On each call to sqs:ReceiveMessage, you will get 0 or more messages from the queue which you'll need to iterate through. For each message, you'll also need to call sqs:DeleteMessage to remove the message from the queue when you're done processing each message.
Add a loop around your "Long Polling" sample above to receive all messages.
for (;;) {
ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(myQueueUrl);
List<Message> messages = sqs.receiveMessage(receiveMessageRequest).getMessages();
for (Message message : messages) {
System.out.println(" Message");
System.out.println(" MessageId: " + message.getMessageId());
System.out.println(" ReceiptHandle: " + message.getReceiptHandle());
System.out.println(" MD5OfBody: " + message.getMD5OfBody());
System.out.println(" Body: " + message.getBody());
for (Entry<String, String> entry : message.getAttributes().entrySet()) {
System.out.println(" Attribute");
System.out.println(" Name: " + entry.getKey());
System.out.println(" Value: " + entry.getValue());
}
}
System.out.println();
}
Also note that you may receive the same message more than once. So allow your work to "reprocess" the same message, or detect a repeated message.
I too was facing same issue - only one message was getting returned , then i tried
receiveMessageRequest.setMaxNumberOfMessages(10) , which would help me in retrieving 10 messages in a loop,
since my queue has >500 records what i did was
List<String> messagelist = new ArrayList<>();
try
{
AmazonSQS sqs = new AmazonSQSClient(credentials);
Region usWest2 = Region.getRegion(Regions.US_WEST_2);
sqs.setRegion(usWest2);
boolean flag = true;
while(flag)
{
ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(queuename);
receiveMessageRequest.setMaxNumberOfMessages(number_of_message_);
receiveMessageRequest.withMaxNumberOfMessages(number_of_message_).withWaitTimeSeconds(wait_time_second_);
List<Message> messages = sqs.receiveMessage(receiveMessageRequest).getMessages();
for (Message message : messages)
{
// System.out.println(" Body: " + message.getBody());
messagelist.add( message.getBody());
String messageReceiptHandle = message.getReceiptHandle();
sqs.deleteMessage(new DeleteMessageRequest().withQueueUrl(queuename).withReceiptHandle(messageReceiptHandle));
}
if(messages.size()==0)
{
flag = false;
}
}
}
catch (AmazonServiceException ase) {
ase.printStackTrace();
} catch (AmazonClientException ace) {
ace.printStackTrace();
}
finally {
return messagelist ;
}
I am reading records from SQS then saving it into a String list and then deletion the record from queue.
so in the end i will have all the data from the queue in a list
An SQS queue is not a database. You can't read all the messages into a list like you are trying to do. There is no beginning and no end to the queue. You poll the queue and ask for some messages, it returns you some messages if they exist.
If you want a method that can return the entire dataset, then sqs is not the right tool - a traditional database might be better in that case.
Long polling will wait if there is no message in Queue. This means that if you call ReceiveMessage with long polling in loop you are guaranteed that you will get all messages. When there is 0 messages received in response, you've already received all messages.
You mentioned that you used also web console. Web console works in same way as calling API with SDK. This means that when you receive and see messages in console, messages are invisible to other clients until visibility timeout expires. That's probably reason why you don't see messages.
See more information about visibility timeout:
http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/AboutVT.html