Problem Description
I'm writing chat application using XMPP and Smack Android library. I'm sending messages using code below and everything is working fine.
final ChatManager chatManager = ChatManager.getInstanceFor(connection);
chatManager.addChatListener(this);
....
#Override
public void chatCreated(Chat chat, boolean createdLocally) {
chat.addMessageListener(this);
}
#Override
public void processMessage(Chat chat, Message message) {
// Do something here.
}
Chat chat = ChatManager.getInstanceFor(connection).createChat(jid);
chat.sendMessage("message");
Question
Unfortunately the API above is deprecated org.jivesoftware.smack.chat.Chat and instead I should use org.jivesoftware.smack.chat2.Chat, so I am changing implementation as follows
final ChatManager chatManager = ChatManager.getInstanceFor(connection);
chatManager.addOutgoingListener(this);
chatManager.addIncomingListener(this);
....
Chat chat = ChatManager.getInstanceFor(connection).chatWith(jid);
chat.send("message");
In this case I can still get Incoming messages, but when I am trying to send message with chat.send("message"); server does not get anything and addOutgoingListener callback is not called.
Any ideas why?
There is an example with an older version of smack:
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManager;
import org.jivesoftware.smack.ChatManagerListener;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
public class Test {
public static void main(String args[]) throws XMPPException {
ConnectionConfiguration config = new ConnectionConfiguration("127.0.0.1", 5222);
XMPPConnection connection = new XMPPConnection(config);
connection.connect();
connection.login("userx", "123456");
ChatManager cm = connection.getChatManager();
Chat chat = cm.createChat("tongqian#tsw-PC", null);
/*
* add listener
*/
cm.addChatListener(new ChatManagerListener() {
#Override
public void chatCreated(Chat chat, boolean create) {
chat.addMessageListener(new MessageListener() {
#Override
public void processMessage(Chat chat, Message msg) {
System.out.println(chat.getParticipant() + ":" + msg.getBody());
}
});
}
});
chat.sendMessage("hello");
while(true);
//connection.disconnect();
}
}
Answer
Digging a bit deeper I found the answer, the code below will help to send a message
Sending Message Code
final Chat chat = ChatManager.getInstanceFor(connection).chatWith(jid);
Message newMessage = new Message(jid, Message.Type.chat);
newMessage.setBody(message);
chat.send(newMessage);
Conclusion
So instead of sending a string message, you need to create a Message object and I think what is more important is to specify Message.Type.chat in the constructor and also jid and then call chat.send(...)
You can refer to this code snippet:
public void sendMessage(String to, Message newMessage) {
if(chatManager!=null) {
Chat newChat = chatManager.createChat(to);
try {
if (connection.isConnected() && connection.isAuthenticated()) {
newChat.sendMessage(newMessage);
}
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
}
else
{
Log.d(TAG,”chatmanager is null”);
}
}
And the link is https://ramzandroidarchive.wordpress.com/2016/03/13/send-messages-over-xmpp-using-smack-4-1/ .
Related
I am using the AndroidAsync library from GitHub that is provided by koush. I need this library to create a WebSocket server and I was able to create it.
private static List<WebSocket> webSockets = new ArrayList<WebSocket>();
private static AsyncHttpServer httpServer = new AsyncHttpServer();
Here's the implementation:
public static void createWebSocket() {
httpServer.websocket("/", new AsyncHttpServer.WebSocketRequestCallback() {
#Override
public void onConnected(final WebSocket webSocket, AsyncHttpServerRequest request) {
webSockets.add(webSocket);
webSocket.setClosedCallback(new CompletedCallback() {
#Override
public void onCompleted(Exception ex) {
Log.d(TAG, "onCompleted");
}
});
webSocket.setStringCallback(new WebSocket.StringCallback() {
#Override
public void onStringAvailable(String s) {
Log.d(TAG, "onStringAvailable");
}
});
}
});
httpServer.listen(8080);
}
This implementation works completely fine.
But I want to use the wss protocol where I can use a JKS (Java KeyStore) certificate for the websocket.
Is there any way to do this? If not with this library, is there any other library I can use? Any example would be really appreciated.
Thank you!!
try this one. I haven't used it. However, it says it supports Java servers and Android clients with support for wss. Good luck!
Honestly, I don't know that I am right. I just happened into this.
Do you think you could do it with NanoHTTPD for java?
I imagine the basic structure is:
MyHTTPDTask
import java.io.IOException;
import java.util.Map;
import fi.iki.elonen.NanoHTTPD;
class MyHTTPDTask extends AsyncTask {
private MyServer mHTTPD;
#Override
protected Object doInBackground(Object... params) {
mHTTPD = new MyServer();
mHTTPD.makeSecure(NanoHTTPD.makeSSLSocketFactory(R.string.keystore.jks, "password".toCharArray()), null);
}
}
MyServer
import java.io.IOException;
import fi.iki.elonen.NanoHTTPD;
public class MyServer extends NanoHTTPD {
private final static int PORT = 8080;
public MyServer() throws IOException {
super(PORT);
start();
System.out.println( "\nRunning! Point your browers to http://localhost:8080/ \n" );
}
#Override
public Response serve(IHTTPSession session) {
String msg = "<html><body><h1>Hello server</h1>\n";
msg += "<p>We serve " + session.getUri() + " !</p>";
return newFixedLengthResponse( msg + "</body></html>\n" );
}
}
For the server side, why don't you use the standard API, javax.websocket? It's a part of Java EE.
For the Android side, see "Which WebSocket library to use in Android app?".
I'm trying to create a twitch bot, and the first thing I'm trying to make it do is respond to chat messages. However, when the bot connects to the chat room, it doesn't seem to stay connected. It sends chat messages fine, but it doesn't recieve them.
Here's the code if you want to look at it. I feel like I'm missing something basic that I should've remembered, so if you can figure out what that is I'd like to know.
package me.acezephyr.lavabot;
import java.io.IOException;
import org.jibble.pircbot.IrcException;
import org.jibble.pircbot.NickAlreadyInUseException;
import org.jibble.pircbot.PircBot;
public class LavaStreamBot extends PircBot {
private static LavaStreamBot INSTANCE = new LavaStreamBot();
public static void main(String[] args) {
INSTANCE.setVerbose(true);
INSTANCE.setName("LavaStreamBot");
try {
INSTANCE.connect("irc.twitch.tv", 6667,
"oauth:******************************");
} catch (NickAlreadyInUseException e) {
System.err
.println("Tried to join Twitch server, but someone else online already has the nick LavaStreamBot.");
} catch (IOException e) {
e.printStackTrace();
} catch (IrcException e) {
e.printStackTrace();
}
join("#AceLava");
}
public static void join(String channel) {
INSTANCE.joinChannel(channel);
INSTANCE.sendMessage(channel, "LavaStreamBot is now in this channel.");
}
#Override
public void onConnect() {
System.out.println("Connected to server");
super.onConnect();
}
#Override
public void onMessage(String channel, String sender, String login, String hostname, String message){
System.out.println("Got a message!");
super.onMessage(channel, sender, login, hostname, message);
}
}
You wrote the channel name ("#AceLava") with capitals. In IRC, this is a different channel than #acelava - Twitch always handles the channels with all lowercase. Just change that and you'll be all fine.
Not related to the question, but you might want to know about the fact that twitch will change their Background messaging service soon™ and it won't be done via IRC so you'll have to change your bot accordingly (as well as I'll have to do >.< ).
For more information and to keep up to date, visit http://discuss.dev.twitch.tv/
I am building a tool that can send CoAP messages to another peer (different implementation), but I am having difficulties. I am using the CoAP library called "Californium" and am developing the tool in java/eclipse. Here's the deal: I send a message over californium's "default endpoint", which allows the system to make up a source-port for the UDP "connection". I want to listen on this same source-port using californium's Server object, but I am getting the following error:
SEVERE: Could not start endpoint
java.net.BindException: Address already in use
So my question is: how do I first send a CoAP message and start listening for other CoAP messages on the same socket using Californium?
Below is the java code for the client. What it does is "register" using a certain protocol layered on top of CoAP. After registering I want it to re-use the UDP socket for listening for subsequent messages of the entity I registered with earlier.
NOTE: The server part of the client works when I explicitly tell it to listen to a certain port (e.g. 5683), leave out the register part and test it with the Firefox Addon "Copper" (i.e. Copper can get to the /1 /1/1 /1/1/0 resources).
package com.example.l2mwm.client;
import java.net.InetSocketAddress;
import ch.ethz.inf.vs.californium.coap.CoAP.Code;
import ch.ethz.inf.vs.californium.coap.CoAP.ResponseCode;
import ch.ethz.inf.vs.californium.coap.CoAP;
import ch.ethz.inf.vs.californium.coap.Request;
import ch.ethz.inf.vs.californium.coap.Response;
import ch.ethz.inf.vs.californium.network.Endpoint;
import ch.ethz.inf.vs.californium.network.EndpointManager;
import ch.ethz.inf.vs.californium.server.Server;
import ch.ethz.inf.vs.californium.server.resources.CoapExchange;
import ch.ethz.inf.vs.californium.server.resources.Resource;
import ch.ethz.inf.vs.californium.server.resources.ResourceBase;
public class Main {
public static void main(String[] args) {
Endpoint endpoint;
if ((endpoint = register()) != null) {
listen(endpoint);
} else {
System.out.println("Couldn't register!");
}
}
private static void listen(Endpoint endpoint) {
InetSocketAddress sockAddress = endpoint.getAddress();
int port = sockAddress.getPort();
Server server = new Server(port);
Resource topResource = new ResourceBase("1") {
#Override
public void handleGET(CoapExchange exchange) {
exchange.respond(ResponseCode.CONTENT, "this is /1's value!");
}
#Override
public String getPath() {
return "/";
}
};
Resource instanceResource = new ResourceBase("1") {
#Override
public void handleGET(CoapExchange exchange) {
exchange.respond(ResponseCode.CONTENT, "this is /1/1's value!");
}
#Override
public String getPath() {
return "/1/";
}
};
topResource.add(instanceResource);
instanceResource.add(new ResourceBase("0") {
#Override
public void handleGET(CoapExchange exchange) {
exchange.respond(ResponseCode.CONTENT, "this is /1/1/0's value!");
}
#Override
public String getPath() {
return "/1/1/";
}
});
server.add(topResource);
server.start();
}
private static Endpoint register() {
Request request = new Request(Code.POST);
request.setURI("localhost:5684/rd?ep=coapclient<=86400&b=U");
request.setPayload("</1/1/0>");
Endpoint endpoint = EndpointManager.getEndpointManager().getDefaultEndpoint();
request.send(endpoint);
Response response;
ResponseCode responseCode = null;
try {
response = request.waitForResponse();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
return null;
}
responseCode = response.getCode();
if (responseCode != CoAP.ResponseCode.CREATED) {
return null;
}
return endpoint;
}
}
You need to first bind your UDP socket and then start your LWM2M register.
Because what you do: create CoAP Endpoint (bind a udp server) and than you bind again in your listen method.
// list to the UDP post 5555
coapServer = new Server();
Endpoint endpoint = new CoAPEndpoint(new InetSocketAddress("localhost",5555);
coapServer.addEndpoint(endpoint);
// send a message to a LWM2M server:
request request = new Request(Code.POST);
request.setURI("iot.eclipse.org:5683/rd?ep=coapclient<=86400&b=U");
request.setPayload("</1/1/0>");
Endpoint endpoint = EndpointManager.getEndpointManager().getDefaultEndpoint();
request.send(endpoint);
You can still access to your client using copper on coap://localhost:5555
I'm using websockets to make a multiplayer game and I need to send multiple types of data across the server but when I connect to the server it's supposed to send back a name and number ("type") and ("data") respectively from the websocket library on connection. I don't need the type but ("data") is vital for the game logic to actually work.
Below is the code I have in my websockets onMessage() function:
#Override
public void onMessage(String message)
{
try
{
JSONObject json = new JSONObject(message);
if(json.has("type") && json.has("data"))
{
Log.d(TAG, json.getString("type"));
Log.d(TAG, json.getString("data"));
playerNum = Integer.parseInt(json.getString("data"));
Log.d(TAG,"Received... Type : " +json.getString("type")+" Data : "+json.getString("data"));
}
if(json.has("Player1TurnOver"))
{
player1TurnOver = json.getBoolean("Player1TurnOver");
}
if(json.has("Word"))
{
String b = json.getString("Word");
bWord = new char[b.length()];
for(int i = 0; i < b.length(); i++)
{
bWord[i] = b.charAt(i);
}
wordLength = bWord.length;
}
}
catch(JSONException e)
{
}
}
But this is never called from the server even though the client has a listener as such:
mClient = new WebSocketClient(URI.create("ws://some_ip:8080/wstest"), new WebSocketClient.Listener()){
And the listener is initialised within the websocket library class
public interface Listener {
public void onConnect();
public void onMessage(String message);
public void onMessage(byte[] data);
public void onDisconnect(int code, String reason);
public void onError(Exception error);
}
I can't seem to figure out why this isn't working properly. As it has worked before...
Sometimes it is not correctly detected when a device looses internet connection (Java is not that smart in this case ;) )
Apart from this. Could you maybe activate the debug printouts with WebSocketImpl.DEBUG = true;
The lib will automatically send pings to the endpoints at specific interval and if no ping was received it assumes that the endpoint got disconnected!
Hi I am new in Java. And its giving me a lot of stress. I need to chat with smack api and openfire server. For this my java code is below
import java.util.*;
import java.io.*;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
public class RunJabberSmackAPI implements MessageListener{
XMPPConnection connection;
public void login(String userName, String password) throws XMPPException {
ConnectionConfiguration config = new ConnectionConfiguration("127.0.0.1 ",5222,"localhost");
connection = new XMPPConnection(config);
connection.connect();
connection.login(userName, password);
}
public void sendMessage(String message, String to) throws XMPPException {
Chat chat = connection.getChatManager().createChat(to, this);
chat.sendMessage(message);
}
public void displayBuddyList()
{
Roster roster = connection.getRoster();
Collection<RosterEntry> entries = roster.getEntries();
System.out.println("\n\n" + entries.size() + " buddy(ies):");
for(RosterEntry r:entries) {
System.out.println(r.getUser());
}
}
public void disconnect() {
connection.disconnect();
}
public void processMessage(Chat chat, Message message) {
if(message.getType() == Message.Type.chat)
System.out.println(chat.getParticipant() + " says: " + message.getBody());
}
public static void main(String args[]) throws XMPPException, IOException {
// declare variables
RunJabberSmackAPI c = new RunJabberSmackAPI();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String msg;
// turn on the enhanced debugger
XMPPConnection.DEBUG_ENABLED = true;
// Enter your login information here
c.login("admin", "admin"); // I created this user with openfire.
c.displayBuddyList();
System.out.println("-----");
System.out.println("Who do you want to talk to? - Type contacts full email address:");
String talkTo = br.readLine();
System.out.println("-----");
System.out.println("All messages will be sent to " + talkTo);
System.out.println("Enter your message in the console:");
System.out.println("-----\n");
while( !(msg=br.readLine()).equals("bye")) {
c.sendMessage(msg, talkTo);
}
c.disconnect();
System.exit(0);
}
}
I run this code twice in my pc. Each for an individual user. I added these two users as friends in openfire by adding rooster.
But when they logged in by running the java code above they send there presence as available . But they can't send their presence to each other available. Instead they receives two error messages from their buddy .
First error message : www.freeimagehosting.net/image.php?eac15f606a.jpg
Second error message : www.freeimagehosting.net/image.php?b827058d07.jpg
I don't know what is wrong with my code. And i really need to solve this problem very soon. I posted this problem other forums too but can't find any answer. So if anyone can have any solution it would be a very big help. Thank You.
In many threads in IgniteRealtime's web you can see that you need to let Smack asynchronously retrieve Roster, so either you change the displayBuddyList() to use a RosterListener instead, or you simply use a Thread.sleep(5000) between the login and the displayBuddyList() function (if you don't want to use a listener, which is recommended) to let it have some time to populate the roster with updated presences.