I have built a chat application using an Openfire (xmpp) server. One-to-one person chats are working fine and the messages are delivered instantly. But when we send a message inside a group, the first message gets delayed and the second message is delivered instantly.
MultiUserChatManager groupChat =
MultiUserChatManager.getInstanceFor(connection).getMultiUserChat("group_name");
groupChat.send("Message object");
Why is the first message getting delayed?
MUC Creation is
MultiUserChatManager mchatManager = MultiUserChatManager.getInstanceFor(xmpptcpConnection);
MultiUserChat mchat = mchatManager.getMultiUserChat(group);
if (!mchat.isJoined()) {
Log.d("CONNECT", "Joining room !! " + group + " and username " + username);
boolean createNow = false;
try {
mchat.createOrJoin(username);
createNow = true;
} catch (Exception e) {
Log.d("CONNECT", "Error while creating the room " + group + e.getMessage());
}
if (createNow) {
Form form = mchat.getConfigurationForm();
Form submitForm = form.createAnswerForm();
List<FormField> formFieldList = submitForm.getFields();
for (FormField formField : formFieldList) {
if(!FormField.Type.hidden.equals(formField.getType()) && formField.getVariable() != null) {
submitForm.setDefaultAnswer(formField.getVariable());
}
}
submitForm.setAnswer("muc#roomconfig_persistentroom", true);
submitForm.setAnswer("muc#roomconfig_publicroom", true);
mchat.sendConfigurationForm(submitForm);
//mchat.sendConfigurationForm(
// new Form(DataForm.Type.submit)); //this is to create the room immediately after join.
}
}
Log.d("CONNECT", "Room created!!");
return true;
} catch (SmackException e) {
e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
e.printStackTrace();
}
There's an issue about creation and a kind of side-effect propagated on sending.
I think simply that you need to join the chat the first time since you didn't before and the first message also activate the Groupchat on server, so the first message it's delayed because you didn't finalized the multiuserchat creation.
How to fix.
In creation phase, this part must be improved:
if (!mchat.isJoined()) {
Log.d("CONNECT", "Joining room !! " + group + " and username " + username);
boolean createNow = false;
try {
mchat.createOrJoin(username);
createNow = true;
} catch (Exception e) {
Log.d("CONNECT", "Error while creating the room " + group + e.getMessage());
}
With just:
boolean createNow
try
{
if (!mchat.isJoined())
{
createNow = mchat.createOrJoin(username);
}
}
catch (Exception e)
{
throw new Exception("ERROR!");
}
and after this invokation:
mchat.sendConfigurationForm(submitForm);
add:
if (!mchat.isJoined()) {
mchat.join(username);
}
creationOrJoin method it's about creation OR join (as name says): to activate the chat, you must join it after the creation phase.
However createOrJoin has maybe an unexpected behaviour due a double check about already joined rooms to keep syncro between session in client and session on server, so the mchat.join() must be invoked after.
An explicit name can sounds like: mustCreateBeforeOrCanJoinDirectly()
Related
I am making a chat application with smack library and openfire as a server but everytime i exit the chat conversation activity between two users and come back, the whole chat gets erased. I have already enabled archive settings to store one to one messages in the server but i do not know how to implement it in the app.
I want to show chats history in recyclerview by the sender and the receiver in the recyclerview.
currently i have implemented this function which caused error
private void setChatHistory(String entityBareId) {
EntityBareJid jid = null;
try {
jid = JidCreate.entityBareFrom(entityBareId);
} catch (XmppStringprepException e) {
e.printStackTrace();
}
MamManager manager = MamManager.getInstanceFor(mConnection);
MamManager.MamQueryResult r = null;
try {
try {
r = manager.mostRecentPage(jid, 10);
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (XMPPException.XMPPErrorException e) {
e.printStackTrace();
} catch (SmackException.NotLoggedInException e) {
e.printStackTrace();
} catch (SmackException.NoResponseException e) {
e.printStackTrace();
}
if (r.forwardedMessages.size() >= 1) //printing first of them
{
Message message = (Message) r.forwardedMessages.get(0).getForwardedStanza();
Log.i("mam", "message received" + message.getBody());
MessagesData data = new MessagesData("send",message.getBody());
mMessagesData.add(data);
mAdapter = new ConversationAdapter(mMessagesData);
recyclerView.setAdapter(mAdapter);
}
}
Error was
Attempt to read from field 'java.util.List org.jivesoftware.smackx.mam.MamManager$MamQueryResult.forwardedMessages' on a null object reference
At r.forwardedmessages.size()>=1.
Thanks in advance
If you want to keep history of conversation, you must save them in database. MAM just for fetching old conversation from server like when you uninstall or logout the app and decide to reinstall and get old messages.
For getting messages from server be sure you already enabled it, then forwarded messages shouldnt be null. here is a guide to enable it.
I am developing chat application for one to one chat and group chat.
I have successfully done one to one chat.
Using the below link I have created Group chat.
Link to create Group chat in smack 4.2.0-beta1
I can see the group in admin panel but There is only a single user available, But I have created this group with three members.
Here I have added my code.
public void createGroupChat() {
String DomainName = "conference."+ServiceAddress;
// Create a MultiUserChat using a Connection for a room
// Get the MultiUserChatManager
MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
try {
EntityBareJid jid = JidCreate.entityBareFrom("mychatroom3" + "#"
+ DomainName);
// Create a MultiUserChat using an XMPPConnection for a room
MultiUserChat muc = manager.getMultiUserChat(jid);
// Prepare a list of owners of the new room
Set<Jid> owners = JidUtil.jidSetFrom(new String[]{"admin" + "#"
+ DomainName, "dev1" + "#"
+ DomainName, "dev2" + "#"
+ DomainName});
// Create the room
Resourcepart nickname = Resourcepart.from("admin");
muc.create(nickname).getConfigFormManager().setRoomOwners(owners).submitConfigurationForm();
muc.join(nickname);
Log.e("Group chat", "Created");
Toast.makeText(context,
"Group chat" + "Created",
Toast.LENGTH_SHORT).show();
} catch (XmppStringprepException e) {
e.printStackTrace();
} catch (MultiUserChatException.MucAlreadyJoinedException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
e.printStackTrace();
} catch (MultiUserChatException.MissingMucCreationAcknowledgeException e) {
e.printStackTrace();
} catch (NotConnectedException e) {
e.printStackTrace();
} catch (SmackException.NoResponseException e) {
e.printStackTrace();
} catch (MultiUserChatException.NotAMucServiceException e) {
e.printStackTrace();
} catch (MultiUserChatException.MucConfigurationNotSupportedException e) {
e.printStackTrace();
}
}
Exception that I got
08-01 05:58:14.589 917-917/com.agarangroup.hello W/System.err: org.jivesoftware.smackx.muc.MultiUserChatException$MucConfigurationNotSupportedException: The MUC configuration 'muc#roomconfig_roomowners' is not supported by the MUC service
08-01 05:58:14.590 917-917/com.agarangroup.hello W/System.err: at org.jivesoftware.smackx.muc.MucConfigFormManager.setRoomOwners(MucConfigFormManager.java:137)
08-01 05:58:14.590 917-917/com.agarangroup.hello W/System.err: at com.agarangroup.hello.Services.MyXMPP.createGroupChat(MyXMPP.java:331)
08-01 05:58:14.590 917-917/com.agarangroup.hello W/System.err: at com.agarangroup.hello.slidingtab.chats.GroupChatActivity.onCreate(GroupChatActivity.java:99)
There are 2 cases:
1) Your conference service does not supports owners (depends by server, Ejabber in your case, and this doesn't sounds normal)
2) Your config form it's not completed as documentation says and you need to create a full form.
How to fix: substitute this line:
muc.create(nickname).getConfigFormManager().setRoomOwners(owners).submitConfigurationForm();
with:
muc.create(nickname);
Form form = muc.getConfigurationForm().createAnswerForm();
form.setAnswer("muc#roomconfig_roomowners", owners);
muc.sendConfigurationForm(form);
pay attention to names:
your DomainName it's the Service conference name + Server Domain Name.
An owner can be a JID (foo#myserver) and not related on service (so foo#service.myserver it's not a valid user, even if server will accept it).
Fix your owners with:
"admin" + "#" + ServiceAddress, "dev1" + "#" + ServiceAddress, "dev2" + "#" + ServiceAddress
I am using the below code to create Multi user group but getting Timeout error, even if my timeout error is 10sec.
public void createGroup() {
String roomId = "Group_test003" + "#icoveri.com";
String nick = "Grouptest";
try {
MultiUserChatManager manager = multiUserChatManager.getInstanceFor(connection);
MultiUserChat muc = manager.getMultiUserChat(roomId);
muc.create(nick);
Form form = muc.getConfigurationForm();
Form submitForm = form.createAnswerForm();
List<FormField> fields = form.getFields();
for (int i = 0; i < fields.size(); i++) {
FormField field = (FormField) fields.get(i);
if (!FormField.Type.hidden.equals(field.getType()) && field.getVariable() != null) {
submitForm.setDefaultAnswer(field.getVariable());
}
}
List owners = new ArrayList();
owners.add(user1234 + "#icoveri.com");
submitForm.setAnswer("muc#roomconfig_roomowners", owners);
muc.sendConfigurationForm(submitForm);
} catch (XMPPException e) {
e.printStackTrace();
} catch (SmackException.NoResponseException e) {
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
} catch (SmackException e) {
e.printStackTrace();
}
}
The error which I am getting is
org.jivesoftware.smack.SmackException$NoResponseException: No response
received within reply timeout. Timeout was 10000ms (~10s). Used
filter: AndFilter: (FromMatchesFilter (full):
Group_test003#iscoveri.com/Grouptest, StanzaTypeFilter:
org.jivesoftware.smack.packet.Presence).
at
org.jivesoftware.smack.PacketCollector.nextResultOrThrow(PacketCollector.java:229)
at
org.jivesoftware.smackx.muc.MultiUserChat.enter(MultiUserChat.java:311)
at
org.jivesoftware.smackx.muc.MultiUserChat.createOrJoin(MultiUserChat.java:400)
at
org.jivesoftware.smackx.muc.MultiUserChat.createOrJoin(MultiUserChat.java:376)
I have got the solution. The problem was in my service i.e. iscoveri.com. I had to use different service name to create the group.
I also have spent a couple hours trying to correct the same error; in my case, the problem happened when I used XMPPBOSHConnection, but not when using XMPPTCPConnection.
I am trying to get the details of no.of messages, no.of deleted messages and no.of total messages using javamail api in android. But i am always getting -1 for no.of deleted messages. I couldn't find what is the reason/bug is so please help me with this. Here is my code
class Readmails extends AsyncTask{
Folder inbox;
Folder inbox2;
Properties props = System.getProperties();
#Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
props.setProperty("mail.store.protocol", "imaps");
try
{
/* Create the session and get the store for read the mail. */
Session session = Session.getDefaultInstance(props, null);
Store store = session.getStore("imaps");
store.connect("imap.gmail.com","test123#gmail.com", "testmycode12345");
/* Mention the folder name which you want to read. */
inbox = store.getFolder("Inbox");
System.out.println("No of Unread Messages : " + inbox.getUnreadMessageCount());
System.out.println("No of New Messages : " + inbox.getNewMessageCount());
System.out.println("No of Deleted Messages : " +inbox.getDeletedMessageCount());
System.out.println("No of total Messages : " + inbox.getMessageCount());
System.out.println("No of Type Messages : " + inbox.getType());
/*Open the inbox using store.*/
inbox.open(Folder.READ_ONLY);
/* Get the messages which is unread in the Inbox*/
Message messages[] = inbox.search(new FlagTerm(new Flags(Flag.SEEN), false));
/* Use a suitable FetchProfile */
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
fp.add(FetchProfile.Item.CONTENT_INFO);
inbox.fetch(messages, fp);
try
{
inbox.close(true);
store.close();
}
catch (Exception ex)
{
System.out.println("Exception arise at the time of read mail");
ex.printStackTrace();
}
}
catch (NoSuchProviderException e)
{
e.printStackTrace();
System.exit(1);
}
catch (MessagingException e)
{
e.printStackTrace();
System.exit(2);
}
return null;
}
}
You are calling getDeletedMessageCount() before you open the inbox.
See this comment in the code, it says it returns -1 on closed folders. Move your call to inbox.open() above your println's
Has anyone been able to add custom commands in the ChromeCast API? I was successful in getting the TicTacToe example working with my developer ID as well as modified Protocol string (changed on both the client and server).
On the Android side, I have the existing "join" command which works, and I am adding a new "image" command:
public final void join(String name) {
try {
Log.d(TAG, "join: " + name);
JSONObject payload = new JSONObject();
payload.put(KEY_COMMAND, KEY_JOIN);
payload.put(KEY_NAME, name);
sendMessage(payload);
} catch (JSONException e) {
Log.e(TAG, "Cannot create object to join a game", e);
} catch (IOException e) {
Log.e(TAG, "Unable to send a join message", e);
} catch (IllegalStateException e) {
Log.e(TAG, "Message Stream is not attached", e);
}
}
public final void sendImage(String sURL) {
try {
Log.d(TAG, "sendImage");
JSONObject payload = new JSONObject();
payload.put(KEY_COMMAND, KEY_IMAGE);
payload.put(KEY_URL, sURL);
sendMessage(payload);
} catch (JSONException e) {
Log.e(TAG, "Cannot create object to send image", e);
} catch (IOException e) {
Log.e(TAG, "Unable to send an image message", e);
} catch (IllegalStateException e) {
Log.e(TAG, "Message Stream is not attached", e);
}
}
If I call the join command, it works fine and I can see the message logged through the console in the browser. But if I call the sendImage function, I get the following error:
"onEnded failed to connect channel: protocol error"
On the ChromeCast side, I can see when a valid command is received. This function is getting called when I send the join command, but not when I send my custom "image" command.
/**
* Message received event; determines event message and command, and
* choose function to call based on them.
* #param {event} event the event to be processed.
*/
onMessage: function(event) {
console.log('***== pre onMessage ==***');
var message = event.message;
var channel = event.target;
console.log('********onMessage********' + JSON.stringify(message));
console.log('mPlayer1: ' + this.mPlayer1);
console.log('mPlayer2: ' + this.mPlayer2);
if (message.command == 'join') {
this.onJoin(channel, message);
} else if (message.command == 'leave') {
this.onLeave(channel);
} else if (message.command == 'move') {
this.onMove(channel, message);
} else if (message.command == 'queue_layout_request') {
this.onQueueLayoutRequest(channel);
} else if (message.command == 'image') {
this.onImage(channel, message);
} else if (message.command == 'video') {
this.onVideo(channel, message);
} else if (message.command == 'song') {
this.onSong(channel, message);
} else {
cast.log.error('Invalid message command: ' + message.command);
}
},
Any ideas? Is there somewhere else where I need to define my custom commands?
EDITED: also showing the onImage prototype:
/**
* Image event: display an image
* #param {cast.receiver.channel} channel the source of the move, which
* determines the player.
* #param {Object|string} message contains the URL of the image
*/
onImage: function(channel, message) {
console.log('****onImage: ' + JSON.stringify(message));
//Hide video and show image
mVideo.style.visibility='hidden';
mImage.style.visibility='visible';
mImage.src = message.url;
},
That usually means there was a JavaScript error in your receiver. Open Chrome on port 9222 at the IP address of your ChromeCast device and use the Chrome developer tools to debug the issue.
Did you declare a new function "onImage" in your receiver prototype for the message handler?