I'm having trouble establishing a proper chat in the Smack messaging library for Java. It works just fine if the chat was started locally, but if the chat is started from another client then two different chat threads are created, instead of just the one that is needed. My code for sending a message is below:
public void sendMessage(String input) throws XMPPException
{
Chat chat = connection.getChatManager().getThreadChat("test#server");
if(chat != null)
{
System.out.println("Chat exists!");
chat.addMessageListener(messageListener);
}
else
{
System.out.println("Create new chat");
chat = connection.getChatManager().createChat("test#server", "test#server", messageListener);
System.out.println(chat.getThreadID());
}
chat.sendMessage(input);
}
Below I have my listener class which processes incoming messages. It is originally set up when the program is initialized so that messages can be recieved straight after log in, and chats established. It is also called by the messageListener variable in the sendMessage function you can see above.
class MyMessageListener implements MessageListener {
#Override
public void processMessage(Chat chat, Message message) {
String from = message.getFrom();
String body = message.getBody();
System.out.println(chat.getThreadID());
System.out.println(String.format("Received message '%1$s' from %2$s", body, from));
}
}
I'm very new to the Smack library and finding the available documentation and examples a bit vague. Anyone have any pointers as to how I could check if a chat was created on another client and somehow fetch the thread ID of this chat or find a chat object from the ChatManager by knowing the name of the user that sent the message?
You need to register a ChatManagerListener to listen for incoming chats, as described in the Incoming Chats section in documentation. A listener on a chat created this way will receive the incoming messages, assuming they are responding with the same thread id (not all clients use a thread id).
By the way, you are looking up an existing chat by thread, but that is not a the thread id of an incoming chat. The code snippet you have shown will only match on the chat that you have created yourself, so there is no point in setting the message listener every time you are going to send a message, you may as well just hold a reference to it once it is create.
You will have to retrieve the thread id from the incoming chat to have this work properly, and that is assuming that the incoming chat actually has a chat id.
Related
I'm creating an app that there's a button that says "Join the room" and when you click on it you join an imaginary room where you can see more users entering.
My idea is to create a topic for instance nameRoom and every time a user joins the room it automatically subscribe to them, so if there's another update he/she'll receive the update for instance one joined or one left.
The thing where I'm stuck is:
The "Administrator" can create a "Room" so every time the Administrator creates a Room should it be a new topic, right? So, my question is once I'm inside a room, I'd like to create like a countdown let's say 30 seconds, and when those 30 seconds are done, it starts to ask me questions and everyone can answer the question and I need to see how many users have answered and how many does not, this is another topic?
The flow is :
Administrator creates a room --> Room1
User1 joins the Room1 and sees only you are in this room
User2 joins the Room and sees there are 2 guys in this room (And so on until user 5)
Then the timer goes down 30 to 0
Then as a User1 I see "How old is Michael Jordan" and 4 checkbox and everyone can answer
Also there's a field saying how many answers already have been posted so if the time of the question is 30 seconds and they are 5 users and they answer in less than 30 seconds the question has to be moved to the next screen that is
Top 3 who answered faster and score
To be clear :
I'd like to know how to create topic and then publish to them using Spring. For example to create the room is not necessary MQTT but to check who joins and this stuff it is, so I'm asking this, how could I create this with MQTT?
Also, MQTT would be responsible to say all of the info? I mean every room has some questions so it's necessary to via MQTT know the ranking etc?
1) You need to create database that suits your application needs
Database name : ChatRoom
Tables:
Topics(To store all mqtt room topic names)
Room (Each room is associated with a topic)
User (Each user is associated with a room)
2) Setup an mqtt server which allows connection both on mqtt and websockets (To support javascript application)
3) Now create a spring boot application with following api and web pages
Web pages:
chatroom.html
chatroom.js
Api:
create chatroom (for admin)
list chatroom
join chatroom (for new users)
Steps:
The admin uses the chatroom.html web page to create new chatroom.On creation it calls create chatroom api to create new chatroom. In the api it will subscribe to a new topic for new chatroom.
When normal users visit chatroom.html it will list available chatrooms (use list chatroom api). Once you click on chatroom it will call join chatroom api to update the details in database. The javascript from browser can connect to mqtt topic for the specific chatroom.
For managing questions you need to have your own logic in backend as well as frontend side. You can use Mqtt topic for transferring messages
Refer the following links
For javascript
http://www.steves-internet-guide.com/using-javascript-mqtt-client-websockets/
For java
https://www.eclipse.org/paho/clients/java/
public final class MessageQueueClient implements MqttCallback
{
private MqttClient mqttClient;
private MessageQueueClient()
{
}
public static MessageQueueClient getInstance()
{
return messageQueueClient;
}
#Override
public void connectionLost(Throwable cause)
{
}
#Override
public void messageArrived(String topic, MqttMessage message)
{
}
#Override
public void deliveryComplete(IMqttDeliveryToken token)
{
}
//Call this method on server startup to connect to mqtt server(spring boot app start)
public boolean connect(String hostname, String clientuniqueid)
{
try
{
if (mqttCredentialsDTO != null)
{
MqttConnectOptions options = new MqttConnectOptions();
options.setAutomaticReconnect(true);
options.setCleanSession(true);
mqttClient = new MqttClient(hostname, clientuniqueid);
mqttClient.connect(options);
return true;
}
}
catch (Exception e)
{
e.printStacktrace();
}
return false;
}
//Call this method on server shutdown to disconnect from mqtt server
public boolean disconnect()
{
try
{
if (mqttClient != null)
{
mqttClient.disconnect();
mqttClient.close();
return true;
}
}
catch (MqttException e)
{
e.printStacktrace();
}
return false;
}
//call this method after mqtt connection established to subscribe to any topic
public boolean subscribe(String topicName, int qos)
{
try
{
if (topicName != null)
{
mqttClient.subscribe(topicName, qos);
return true;
}
}
catch (MqttException e)
{
e.printStacktrace();
}
return false;
}
//call this method after mqtt connection established to publish to any topic
public boolean publish(String topicName, String message, int qos)
{
try
{
if (topicName != null)
{
MqttMessage mqttMessage = new MqttMessage();
mqttMessage.setPayload(message.getBytes());
mqttMessage.setQos(qos);
mqttClient.publish(topicName, mqttMessage);
return true;
}
}
catch (MqttException e)
{
e.printStacktrace();
}
return false;
}
}
In my old project I created something similar to what you need.
I'm still sure Google (and Apple) notification systems are better. In any case here what you need.
You can use Eclipse Paho in order to produce and consume MQTT messages.
In my android app build.gradle file I added:
compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.0.2'
Now there is a newer version of the library
This library offers to you all the needed API in order to consume and produce MQTT messages in and from an Android device.
In the documentation section you can find a sample application. You can start from there
On server side I used Apache ActiveMQ as broker. It offers an embedded implementation of MQTT handler and you can create topics and queues in order to handle MQTT messages.
I hope it's useful
Angelo
EDIT SECTION
Let's suppose you want to use ActiveMQ on server side.
You must download and install activemq. In the activemq.xml file inside the directory ${activemq_home}/conf you'll find the mqtt configuration. It's this line:
<transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
This means that activemq handles mqtt protocol messages on port 1883 (the mqtt default TCP/IP port).
On the admin console of activemq you can create topic or queue you want to use for your messages. In the app you must connect the paho service to the created topic or queue.
Please note that by default activemq uses in memory DB. I suggest to yuo to configure it in order to use normal RDBMS or even NoSQL DB. The most important thing is that you configure it in order to store all messages not in memory otherwise you can risk messages will be lost.
Moreover if you expose on internet activemq I strongly suggest to you to protect it by secure credentials or by using SSL certificates.
I am creating an chat app with android and spring using stomp over websocket. when i send more than one message to a specific client, it shows only the last message from the queue not all the previous messages. I want to see all the messages will from the queue.
Client side:
mStompClient =Stomp.over(WebSocket.class, "url");
mStompClient.connect();
mStompClient.topic("/topic/queue"+clientid).subscribe(topicMessage -> {
textView.setText(topicMessage.getPayload());
});
Server side:
#MessageMapping("/chat")
#SendTo("/topic/queue")
public String sendMessage(String msg) {
simpMessagingTemplate.convertAndSend("/topic/queue"+clientid,msg );
return "";
}
In my vision, you should persist the data which sent before, then append the new incoming messages from the queue and feed data store asynchronously.
Step: User opens chat windows, then get data from database.
Step: Send message to queue and consumers should listen the queue and feed new message to chat window and data store.
Step: If user exit from application, No matter what happened. You can present data from data store.
say you have multiple agents(each of them is it's own process) which can communicate to each other(agents communicate only in pairs); how do you ensure that once two agents start communicating, no other agent can interrupt them?
Here's the important part of the code:
class Agent {
private void send(int to, byte[] message) {...};
private void receive(int from, byte[] message) {...};
}
The send method sends the message to the specified agent and receive method processes the received message, that comes from other agents. So let's say agents with id=1 and id=2 exchange a few messages: how do I ensure that neither of the agents processes(in it's receive method) messages from any other agent during their exchange? I tried filtering messages based on agent's id(by storing them in int variable) but it doesn't seems to work properly?
With processes and using TCP for the IPC, at any time let every agent have at most one socket open. Then a second agent will never be able to talk with an already talking agent.
You can give receivers a token. When an agent want to send to a receiver, it should get the receiver's token at first. After finishing the whole communication, the sender will release the token, and then other's can send to the receiver.
I'm creating an instant messaging client using Smack 3.1.0 and Java. The problem I'm running in to has to do with sending messages to the user on a specific domain.
For example, I have two users, 1#gmail.com and 2#gmail.com. 1#gmail.com logs in to XMPP through my IM client. 2#gmail.com logs in to GChat through gmail.com AND a second time through pidgin. So now I have one instance of 1#gmail.com and 2 instances of 2#gmail.com.
The way gmail works, if 1#gmail.com sends a message to 2#gmail.com, the gmail and the pidgin client both get the initial message. But then if the gmail instance responds to the message, every message from then on only goes between 1#gmail.com and the gmail instance of 2#gmail.com.
I would like to mimic this behavior with my IM client. I would think the way to do it would be to set up a Chat, send the initial IM to all instances of the recipient. Then I'd set up a MessageListener to listen for a response. When I get the response, I'd have to create a new chat, specifying the 2#gmail.com/resource. But then I'd have to write the MessageListener twice. Any ideas? Here's some sample code that I'm using (the method AddText() simply appends the message to my conversation pane):
recipient = buddy;
setTitle("Instant Message - "+recipient);
chat = com.andreaslekas.pim.PIM.connection.getChatManager().createChat(recipient.getUser(), new MessageListener() {
public void processMessage(Chat chat, Message msg) {
//if(chat.getParticipant().indexOf('/')!=-1)
addText(msg.getBody(), chat.getParticipant(), true);
}
});
UPDATE
I wanted to supplement the answer below with actual code that I used to make this work:
chat = com.andreaslekas.pim.PIM.connection.getChatManager().createChat(recipient.getUser(), new MessageListener() {
public void processMessage(Chat new_chat, Message msg) {
if(msg.getFrom().replaceFirst("/.*", "").equals(recipient.getUser()))
{
if(buddy_resource==null || !msg.getFrom().replaceFirst(".*?/", "").equals(buddy_resource.getResource()))
{
buddy_resource = recipient.getResource(msg.getFrom().replaceFirst(".*?/", ""));
chat = null;
chat = com.andreaslekas.pim.PIM.connection.getChatManager().createChat(recipient.getUser()+"/"+buddy_resource.getResource(), new MessageListener(){
public void processMessage(Chat new_chat2, Message msg) {
addText(msg.getBody(), new_chat2.getParticipant(), true);
}
});
}
addText(msg.getBody(), chat.getParticipant(), true);
}
}
});
To summarize, I send the first message to all resources of the recipient's address and wait for a response. When I get the response, I replace the current Chat object with a new one that specifies the individual resource that responded to the initial message. The code is a little messy with two different MessageListener objects that could probably be combined into a new class. But it works.
So far I understood Message Carbon (XEP - 0280) will solve your problem.
If you enable carbon it will distribute messages to all logged resources of a user. In your case if 1#gmail.com send message to 2#gmail.com it will be distributed to all logged resources of 2#gmail.com.
Here's a code sample using smack,
CarbonManager cm = CarbonManager.getInstanceFor(connection);
cm.enableCarbons();
cm.sendCarbonsEnabled();
First make sure that your server is supported Message Carbon.
Then send message as usual.
In your MessageListener why not always respond to the sender? I think you get it by calling something like msg.getSender() or getFrom() (I'm on mobile right now, cannot check)
I first need to apologize for my earlier questions. (You can check my profile for them)They seemed to ask more questions than give answers. Hence, I am laying down the actual question that started all them absurd questions.
I am trying to design a chat applet. Till now, I have coded the applet, servlet and communication between the applet and the servlet. The code in the servlet side is such that I was able to establish chatting between clients using the applets, but the code was more like a broadcast all feature, i.e. all clients would be chatting with each other. That was my first objective when I started designing the chat applet. The second step is chatting between only two specific users, much like any other chat application we have. So this was my idea for it:
I create an instance of the servlet that has the 'broadcast-all' code.
I then pass the address of this instance to the respective clients.
2 client applets use the address to then chat. Technically the code is 'broadcast-all', but since only 2 clients are connected to it, it gives the chatting between two clients feature. Thus, groups of 2 clients have different instances of the same servlet, and each instance handles chatting between two clients at a max.
However, as predicted, the idea didn't materialize!
I tried to create an instance of the servlet but the only solution for that was using sessions on the servlet side, and I don't know how to use this session for later communications.
I now know how to use the request.getSession(). So I set the session for an applet in its param tag and use it for further communications with the servlet. But how do I use this data to establish chatting between two clients? As I wrote earlier, I have the code for broadcast_all chatting as follows:
public class CustomerServlet extends HttpServlet {
public String getNextMessage() {
// Create a message sink to wait for a new message from the
// message source.
return new MessageSink().getNextMessage(source);
}
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ObjectOutputStream dout = new ObjectOutputStream(response.getOutputStream());
String recMSG = getNextMessage();
dout.writeObject(recMSG);
dout.flush();
}
public void broadcastMessage(String message) {
// Send the message to all the HTTP-connected clients by giving the
// message to the message source
source.sendMessage(message);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
ObjectInputStream din= new ObjectInputStream(request.getInputStream());
String message = (String)din.readObject();
ObjectOutputStream dout = new ObjectOutputStream(response.getOutputStream());
dout.writeObject("1");
dout.flush();
if (message != null) {
broadcastMessage(message);
}
// Set the status code to indicate there will be no response
response.setStatus(response.SC_NO_CONTENT);
} catch (Exception e) {
e.printStackTrace();
}
}
MessageSource source = new MessageSource();
}
class MessageSource extends Observable {
public void sendMessage(String message) {
setChanged();
notifyObservers(message);
}
}
class MessageSink implements Observer {
String message = null; // set by update() and read by getNextMessage()
// Called by the message source when it gets a new message
synchronized public void update(Observable o, Object arg) {
// Get the new message
message = (String)arg;
// Wake up our waiting thread
notify();
}
// Gets the next message sent out from the message source
synchronized public String getNextMessage(MessageSource source) {
// Tell source we want to be told about new messages
source.addObserver(this);
// Wait until our update() method receives a message
while (message == null) {
try {
wait();
} catch (Exception e) {
System.out.println("Exception has occured! ERR ERR ERR");
}
}
// Tell source to stop telling us about new messages
source.deleteObserver(this);
// Now return the message we received
// But first set the message instance variable to null
// so update() and getNextMessage() can be called again.
String messageCopy = message;
message = null;
return messageCopy;
}
}
On the applet side, I have a thread that will connect to the servlet above using GET method to get new messages. It uses a while loop, and blocks until it gets a message from the servlet. The main thread communicates with the servlet using POST method whenever the client has entered the message. Currently all clients chat with everyone. I want to use the same methods used above (or if possible any other way) to establish chatting between two clients and two clients only. I could possibly have another thread in the applet to check if any other user wishes to chat with it and then exchange some data so that only those two user chat...
I then tried to modify my broadcast-all code. In that code, I was using classes that implemented Observer and Observable interfaces. So the next idea that I got was:
Create a new object of the Observable class(say class_1). This object be common to 2 clients.
2 clients that wish to chat will use same object of the class_1.
2 other clients will use a different object of class_1.
But the problem here lies with the class that implements the Observer interface(say class_2). Since this has observers monitoring the same type of class, namely class_1, how do I establish an observer monitoring one object of class_1 and another observer monitoring another object of the same class class_1 (Because notifyObservers() would notify all the observers and I can't assign a particular observer to a particular object)?
I first decided to ask individual problems, like how to create instances of servlets, using objects of observable and observer and so on in stackoverflow... but I got confused even more. Can anyone give me an idea how to establish chatting between two clients only?(I am using Http and not sockets or RMI).
Regards,
Mithun.
P.S. Thanks to all who replied to my previous (absurd) queries. I should have stated the purpose earlier so that you guys could help me better.
You need to store all connected users in a Map<String, User> in the application scope using ServletContext#setAttribute(). The String denotes the unique user identifier (chat nickname?). You need to store the specific chat User as well in the session scope using HttpSession#setAttribute(). You also need to store the other user in individual chats in a Map<String, User> in the session scope of the users in question. You can obtain the attribute by the getAttribute() method.
This way you know which users are all available and which user is in the current session and with which users it is individually chatting.
This is a crude way to do it, but I just couldn't find a feasible solution. What I did was that I made all users connect to the servlet that had the broadcastAll code. Each user would be aware of which other user it is chatting with. Hence, while sending a message, the user would append his name and the name of the user that he is chatting with to the message. Since it is a broadcastAll code, every connected user would receive the message. After receiving the message, the user would parse the message to get the user who sent the message, and the name of the user for whom the message was intended. It would compare these two names with its records - see the statement in bold earlier. If matched it would display the message, else ignore it.
Again, its a crude way to do it and I am sure there are better solution out there.