I use below code to send messages.
// Assume we've created an XMPPConnection name "connection".
ChatManager chatmanager = connection.getChatManager();
Chat newChat = chatmanager.createChat("jsmith#jivesoftware.com", new MessageListener() {
public void processMessage(Chat chat, Message message) {
System.out.println("Received message: " + message);
}
});
try {
newChat.sendMessage("Howdy!");
}
catch (XMPPException e) {
System.out.println("Error Delivering block");
}
And below for receiving messages sent to my JabberID, asynchronously.
// Create a packet filter to listen for new messages from a particular
// user. We use an AndFilter to combine two other filters.
PacketFilter filter = new AndFilter(new PacketTypeFilter(Message.class),
new FromContainsFilter("mary#jivesoftware.com"));
// Assume we've created an XMPPConnection name "connection".
// First, register a packet collector using the filter we created.
PacketCollector myCollector = connection.createPacketCollector(filter);
// Normally, you'd do something with the collector, like wait for new packets.
// Next, create a packet listener. We use an anonymous inner class for brevity.
PacketListener myListener = new PacketListener() {
public void processPacket(Packet packet) {
// Do something with the incoming packet here.
}
};
// Register the listener.
connection.addPacketListener(myListener, filter);
Sending message is ok.
But receiving message from another JabberID don't achived until I send a message to that JabberID.
And after that I receive messages sent by it properly.
Note that I often need to receive messages from jabberIDs that are not in my list and often My application is not the side that begins a chat.
Upper codes are smack samples but my code is completely same except I don't create PacketListener implementation inline.
My problem solved when I stopped using Jabber Client with the same user logined during I test my program.
In other words code is correct but Jabber client catches sent messages and remain no things for my program to catch.
It's been quite a while since I worked with smack, but I managed to start chats based on incoming messages.
If I remember well, I had some sort of "ChatRegistry", a simple Map<String, Chat> where the key was equal to the chat partners id. Then I listened to incoming messages, extracted the jabber id and looked up the active chat session with this partner. If there wasn't an active session, I created a new Chat and added the new key/vale pair to the registry.
Just a bit confused. You say
Upper codes are smack samples but my code is completely same except I don't create PacketListener implementation inline.
How do you receive messages without having a PacketListener implementation? I would think that you would always receive messages from chats you started because of the code below
Chat newChat = chatmanager.createChat("jsmith#jivesoftware.com", new MessageListener() {
public void processMessage(Chat chat, Message message) {
System.out.println("Received message: " + message);
}
});
But in order to asynchronously wait for incoming messages, I would think you will need a PacketListener.
I might have totally misunderstood the problem you are facing though
(This should have been a comment, but I can't figure how to add one)
It's been a while, did you manage to solve this? why are you creating FromContainsFilter? In that way, your listeners processes only packets from the given user, not all packets.
Related
This is my current setup for an Undertow websocket server:
Undertow server = Undertow.builder()
.addHttpListener(8080, "localhost")
.setHandler(path()
.addPrefixPath("/", websocket((exchange, channel) -> {
channel.getReceiveSetter().set(new AbstractReceiveListener() {
#Override
protected void onFullTextMessage(WebSocketChannel channel, BufferedTextMessage message) {
final String messageData = message.getData();
for (WebSocketChannel session : channel.getPeerConnections()) {
WebSockets.sendText(messageData, session, null);
}
}
});
channel.resumeReceives();
}))).build();
This is copied from one of their demo files. I believe onFullTextMessage here broadcasts any messages it receives to all clients.
I want to be able to trigger this behavior on demand. So instead of having to receive a message and using an event handler to send out more messages, I want to be able to arbitrarily do server.send() and send a message to all connected clients.
I've looked around and haven't found anything that seems capable of achieving this. I don't relish the idea of tracking all WebSocketChannels and sending to each client manually. Surely, there's a method somewhere that I've overlooked?
I'd appreciate some pointers if it's not something that's just not possible!
You can broadcast the message to all the clients on the channel by getting all the connections to this canal and sending the message :
channel.getPeerConnections().forEach(connection -> {
WebSockets.sendText(messageData, connection, null);
});
I am sending some messages to a JMS queue. What are the possible ways to search for a particular message in a queue to consume?
I tried out in the following way: I am setting the JMSCorrelationID while sending a message to the queue:
public void createDQueue(String queuename, String json, Integer userid) {
try {
QueueSession.AUTO_ACKNOWLEDGE );
Queue queue = session.createQueue(queuename);
ObjectMessage objectMessage = session.createObjectMessage();
objectMessage.setJMSCorrelationID(String.valueOf(userid));
objectMessage.setObject(json);
session.createSender(queue).send(objectMessage);
session.close();
connection.close();
}catch(Exception e){
e.printStackTrace();
}
}
In the consumer code I want to get that particular message based on the JMSCorrelationID. I am not able to get that particular message. Can you suggest a solution?
public void getSpecificMessage(String queuename, Integer userid) {
try {
QueueConnectionFactory connectionFactory = new ActiveMQConnectionFactory( "tcp://localhost:61616");
((ActiveMQConnectionFactory) connectionFactory).setUseAsyncSend(true);
QueueConnection connection = connectionFactory.createQueueConnection();
connection.start();
QueueSession session = connection.createQueueSession( false,
QueueSession.AUTO_ACKNOWLEDGE );
String id = String.valueOf(userid);
Queue queue = session.createQueue(queuename);
QueueReceiver receiver = session.createReceiver(queue, "JMSCorrelationID="+id);
Message message = receiver.receive();
} catch (JMSException e) {
e.printStackTrace();
}
}
Your first problem is that you are trying to think about the message broker as a database, you must always remember this sage piece of advice, "A message broker is not a database".
There are certain limits on how deep a consumer or Queue browser can go into a destination before the broker will not page in more messages from disk, so you need to check your depth and see if its large than you maxPageSize setting and adjust as needed, but remember that messages paged in remain in memory until consumed.
Just wrap the id value in single quotes
"JMSCorrelationID='"+id+"'"
This functionality is not recommended to be used , there are lot more complications as explained by Tim , but if you want to obsolutely work with it make the change
You can search messages using the MeessageID of a message. This would be fast as messaging providers index messages on message id. There are other way to search based on CorrelationId, meta data etc.
But please remember the primary objective of using a messaging provider is to connect applications in a time independent manner. The receiving application must get messages as soon as possible. If messages are piling up in a queue, it indicates a problem that must be addressed.
I'm trying to hook up a message listener to an MQ.
Queue primaryQueue = session.createQueue("Q1");
MessageConsumer primaryConsumer = session.createConsumer(primaryQueue);
primaryConsumer.setMessageListener(new MessageListener() {
#Override
public void onMessage(Message message) {
ObjectMessage objectMessage = (ObjectMessage) message;
try {
Payload payload = (Payload) objectMessage.getObject();
System.out.println("Payload\n" + payload);
} catch (JMSException e) {
e.printStackTrace();
}
}
});
It's just a simple console app that's connecting to a queue. What happens though is, after i start the application and attach the listener, it reads the current set of messages and just... stops. If i send another message into the queue a couple of seconds later, the listener isn't even up and ready to receive it. I'm working with a Websphere MQ that i'm running locally.
I was kinda expecting the app to like hang on and wait to be triggered again right? The point of hooking up a listener is so that it can react to incoming messages rather than me physically doing a recieve() on it.
I'm really new to messaging and queues, so i guess i'm missing something obvious. Appreciate the help.
For an example if I try to build a file transfer mechanism on the server program to whack one file bytes from sender A to user B by capitalizing on their own existing connecting socket, so how could avoid it interleaving with all the ongoing chat stream coming in, i.e to keep clear wait and notify between this two threads apart from creating an extra serversocket at server side …
Many thanks
Kev
create a message protocol for your app which distinguishes between various message types. then create a "file chunk" message and a "chat" message and whatever other messages you need.
pseudo code:
// sending method
public synchronized void send(Message msg) {
// write message to socket ...
}
// receiving method
while(true) {
Message msg = readMessage(); // read message from socket
handleMessage(msg); // may want to push this work to another thread
}
I am writing a java based chat server and currently my design is based on following :-
when a person in a chat room sends a message, the chatroom class at the server side, sends the same message to every participant in the room in a loop. Obviously , this is a poor design because networks calls are being made to individual participants in a loop. Hence, for example, consider there are 10 people in a chat room. When one user sends a message, the chatroom class will send the same message in a loop to all 10 people. if lets say, the 5th person in a loop has a crappy connection, the time when the sixth .. 10th person will see the message will be affected.
if i move from unicast to multicast per room, then how do i get a private multicast group ip per chat room? Also, it seems overkill to have individual groups per chat room.
One of the main problem is that when i replied to users in a room via a loop, the method that sent data over socket connection was blocking. Hence, i am thinking if i use non blocking NIO sockets, and then send the message to recipients in a loop, would that solve the problem ?
Are there other clever tricks that can be done to optimize sending of data to recipients in the room?
The simple implementation is to use two threads per client. One thread to read from the socket the other to write to the socket. If you have few clients this will be fine. You will have to get to know NIO to handle many of clients. ('many' meaning when the threaded model does not work well.)
The Client's reading thread reads an entire message from the socket and puts it on a queue in the ChatRoom object. The chat room has a thread that takes messages off the queue and puts them on the Client's queue. The clients writing thread polls its queue and writes the message to the socket.
The ChatRoom has a thread to accept connections and create Client objects and puts them in a Collection. It has another thread to poll its message queue and distribute the messages to the Client queues.
Apache Mina has an example using NIO
I agree that serially looping over your recipients would be a bad idea. For this, you could consider using a ThreadPool to help. However, I would think that Multicast would be your best bet. It is well suited to the chatroom model. You would only need to send once and your iterative approach will be solved. You can get a unique group id by specifying a different port in your address.
The simple approach is to use two threads per client connection. One thread handles reading messages from the client the other for sending messages, thereby can send/receive messages from the client simultaneously.
To avoid network calls when looping over the client connections to broadcast a message, the server thread should add the messages into a queue to send to the client. LinkedBlockingQueue in java.util.concurrent is perfect for this. Below is an example:
/**
* Handles outgoing communication with client
*/
public class ClientConnection extends Thread {
private Queue<String> outgoingMessages = new LinkedBlockingQueue<String>(MAX_OUTGOING);
// ...
public void queueOutgoing(String message) {
if (!outgoingMessages.offer(message)) {
// Kick slow clients
kick();
}
}
public void run() {
// ...
while (isConnected) {
List<String> messages = new LinkedList<String>();
outgoingMessages.drainTo(messages);
for (String message : messages) {
send(message);
}
// ...
}
}
}
public class Server {
// ...
public void broadcast(String message) {
for (ClientConnection client : clients) {
client.queueOutgoing(message);
}
}
}