How can I create, send and receive IQ packets using Smack 4.1 - smack

I need to send IQ packets to XMPP server for retrieving message archive.
How do i create, send and receive XMPP IQ packets?
Thanks
PS: This question may seem to be duplicate of How Can I create,send and receive iq packets using smack(java), its not. Smack API has been changed a lot in recent years.

MyCustomIQ iq = new MyCustomIQ();
iq.setType(IQ.Type.set);
mConnection.sendIqWithResponseCallback(iq, new PacketListener() {
#Override
public void processPacket(Packet packet) throws SmackException.NotConnectedException {
Log.i("Send IQ with Response", "****** message " + packet);
}
}, new ExceptionCallback() {
#Override
public void processException(Exception exception) {
exception.printStackTrace();
Log.i("IO archjieve Exception",""+ exception.getMessage());
}
}, 5000);
mConnection.sendPacket(new Presence(Presence.Type.available));
PacketTypeFilter filter=new PacketTypeFilter(org.jivesoftware.smack.packet.Message.class);
PacketListener myListener=new PacketListener(){
public void processPacket(Packet packet){
if(((Message) packet).getType().equals(Message.Type.chat))
{
((Message) packet).getBody();
}
else if(((Message) packet).getType().equals(Message.Type.normal))
{
DefaultPacketExtension pacExten=PacketUtil.packetExtensionfromCollection(packet.getExtensions(), "result", "urn:xmpp:mam:0");
String strMsg=pacExten.getValue("body");
}
}
}
;
mConnection.addPacketListener(myListener, filter);
//My Custom IQ
class MyCustomIQ extends IQ {
String token;
protected MyCustomIQ() {
super("query","urn:xmpp:mam:0");
}
#Override
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
// String queryId = prefix + Long.toString(new AtomicLong().incrementAndGet());
xml.attribute("queryid",queryId);
xml.rightAngleBracket();
return xml;
}
}
//You may get the response in PacketListerener sometimes so put debug that also

Related

mosquito MQTT message handler getting messages with some delay not real time

Following is the MQTT configuration to listening event.
For high message load around 100 message per second I noticed messages not received realtime on handler.
public class VehicleEventMqttConfig {
#Value("${mqtt.auto-startup.vehicleEvent:false}")
private boolean autoStartup;
#Value("${mqtt.completion-timeout.vehicleEvent:30000}")
private int completionTimeout;
#Bean
public MessageChannel vehicleMqttInputChannel() {
return new DirectChannel();
}
#Bean
public MessageProducer inboundVehicleEvent(
final MqttPahoClientFactory mqttPahoClientFactory,
final MqttAdapters adapters,
#Value("${mqtt.topic.vehicleEvent}") final String topic) {
log.info("Register vehicleEvent mqtt");
if (StringUtils.isEmpty(topic)) {
log.warn("vehicleEvent disabled!");
return null;
}
final MqttPahoMessageDrivenChannelAdapter adapter =
new MqttPahoMessageDrivenChannelAdapter(
getClientIdWithHost("inboundVehicleEvent"), mqttPahoClientFactory, topic);
adapter.setCompletionTimeout(completionTimeout);
adapter.setConverter(new DefaultPahoMessageConverter());
adapter.setOutputChannel(vehicleMqttInputChannel());
adapter.setAutoStartup(autoStartup);
adapter.setQos(1);
adapters.add(adapter);
return adapter;
}
#Bean
#ServiceActivator(inputChannel = "vehicleMqttInputChannel")
public MessageHandler vehicleEventHandler() {
return new VehicleEventMessageHandler();
}
}

Multiple rooms authorisation with Spring WebSocket and security

I'm making multi rooms chat with user authorization: users can have access only to some assigned rooms.
For every room I creating a topic with unique room id
How can I check permissions during the opening socket for reading?
On the server-side, for new inbound connection, I want to get room id from topic URL and check user access permissions for the room. But I didn't find how I can do it. I don't see the place, there it's possible.
AbstractSecurityWebSocketMessageBrokerConfigurer -- no way for dynamic check
#Configuration
class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
#Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry message) {
message.nullDestMatcher().permitAll()
.simpDestMatchers("/app/**").authenticated()
.anyMessage().hasRole("USER")
}
}
WebSocketMessageBrokerConfigurer -- can't get current url
#Configuration
class WebSocketSecurityConfig extends WebSocketMessageBrokerConfigurer {
#Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
#Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if (StompCommand.SUBSCRIBE.equals(accessor.getCommand())) {
...
}
return message
}
});
}
}
I know, how to check access during writing messages, but can't find, how to do it during opening a web socket for reading. What is the standard mechanism for this case?
Dependencies:
compile 'org.grails.plugins:grails-spring-websocket:2.5.0.RC1'
compile "org.springframework.security:spring-security-messaging"
compile "org.springframework.security:spring-security-config"
compile "org.springframework.security:spring-security-core:5.1.8.RELEASE"
compile "org.springframework:spring-messaging:5.1.6.RELEASE"
UPDATE
I can pass room id from the client as a header, but on the server in configureClientInboundChannel I can't be sure, that room id in header same with id in topic URL. I can use some hashes, generated on the server-side, but it looks too complex
var socket = new SockJS("${createLink(uri: '/stomp')}");
var client = webstomp.over(socket);
client.connect({room-id:"0"}, function() {
client.subscribe("/topic/room/1", function(message) {
console.log("/topic/room/1");
}, {roomId:"1"});
client.subscribe("/topic/room/2", function(message) {
console.log("/topic/room/2");
}, {roomId:"2"});
});
During debugging, I have checked headers of command with type StompCommand.CONNECT.
For StompCommand.SUBSCRIBE command current topic URL presented in simpDestination header
Final solution is:
#Configuration
class WebSocketSecurityConfig extends WebSocketMessageBrokerConfigurer {
#Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
#Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if (StompCommand.SUBSCRIBE.equals(accessor.getCommand())) {
def currentAuthentication = accessor.getHeader('simpUser') // from spring security
String destinationUrl = (String )accessor.getHeader('simpDestination')
// do check, and throw AuthenticationException
}
return message
}
});
}
}

Try to connect to MQTT Server with a Broadcast Receiver when WiFi is connected (Paho)

I have a Broadcast receiver that checks WIFI_STATE_CHANGE to see if I have connected to a certain WiFi network. For example if I am coming home, I want a certain MQTT message to be sent. The problem I have is that it connects and sends the MQTT message, only when run the app the first time.
Process:
If I build the application and run it on the device and it recognised my home WiFi it sends the message.
I turn off Wifi from the device, and turn it back on again.
I get "Failure" which is a message when the MQTT connection to the server could not be established.
What I would need is that after I reconnect to the network, instead of "Failure" to get "Connected" but somehow it never happens...what could be wrong?
PS. I think it has to do with the fact that when WiFi is detected, the Broadcast Receiver runs the connection code, although Internet is not available at that point of time (obtaining IP etc.)
Here is the code of the Broadcast receiver:
package me.app.comehomedemo;
import ...
public class SynchronizeBroadcastReceiver extends BroadcastReceiver {
MqttAndroidClient client;
static String MQTTHOST = "myhost";
static String USERNAME = "myusername";
static String PASSWORD = "mypassword";
static String topicStr = "/topic/mac/control";
static String payload = "1";
#Override
public void onReceive(final Context context, Intent intent) {
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (info.isConnected()) {
WifiManager wifiManager = ( WifiManager ) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ip = wifiInfo.getIpAddress();
Toast.makeText(context, String.valueOf(ip), Toast.LENGTH_SHORT).show();
String ssid = wifiInfo.getSSID();
if (ssid.equals("\"mySSID\"")) {
String clientId = MqttClient.generateClientId();
client = new MqttAndroidClient(context.getApplicationContext(), MQTTHOST, clientId);
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(USERNAME);
options.setPassword(PASSWORD.toCharArray());
// options.setAutomaticReconnect(true);
try {
IMqttToken token = client.connect(options);
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
// We are connected
Toast.makeText(context, "Connected", Toast.LENGTH_SHORT).show();
try {
client.publish(topicStr, payload.getBytes(), 0, false);
} catch (MqttException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
// Something went wrong e.g. connection timeout or firewall problems
Toast.makeText(context, "Failure", Toast.LENGTH_SHORT).show();
}
});
} catch (MqttException e) {
e.printStackTrace();
}
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
MediaPlayer mp = MediaPlayer.create(context.getApplicationContext(), notification);
mp.start();
}
}
}
}
I have managed to solve it by waiting 2 seconds and then running the task. Used this solution and it worked. I had to wait for the Internet connection to get ready!
Since waiting 2 seconds has solved your problem, then it might be that the Wifi broadcast comes too early, before there is a connection established (like DHCP gives your phone IP and establishes the routes) for the MQTT connect and publish packets to be properly delivered.
But what happens if some other user needs to wait 10 and not 2 seconds?
My suggestion is to set the automatic reconnect option in MqttConnectOptions and then use the connection callback to publish the needed info to the broker and finally disconnect in publish callback:
private IMqttActionListener mConnectCallback = new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken token) {
try {
client.publish(topicStr, new MqttMessage(payload.getBytes()), null, mPublishCallback);
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public void onFailure(IMqttToken token, Throwable ex) {
}
};
private IMqttActionListener mPublishCallback = new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken token) {
// TODO disconnect
}
#Override
public void onFailure(IMqttToken token, Throwable ex) {
}
};
MqttAndroidClient client = new MqttAndroidClient(context, MQTTHOST, "my_id");
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(USERNAME);
options.setPassword(PASSWORD.toCharArray());
options.setAutomaticReconnect(true);
client.connect(options, null, mConnectCallback);

OutboundMessageListener doesn't detect outgoing sms

The following piece of code should print out a message when an sms is sent from the device. I've tried it several times on the simulator but nothing gets printed when I send an sms. What am I doing wrong? Why doesn't the app pick up that an sms has been sent.
public class BackGroundApp extends UiApplication implements OutboundMessageListener, javax.wireless.messaging.MessageListener {
private MessageConnection messageConnection;
public static void main(String args[])
{
BackGroundApp theApp = new BackGroundApp();
theApp.enterEventDispatcher();
}
public BackGroundApp(){
try {
MessageConnection _mc = (MessageConnection)Connector.open("sms://");
_mc.setMessageListener(this);
} catch (IOException e) {}
}
public void notifyIncomingMessage(MessageConnection messageconnection){
}
public void notifyOutgoingMessage(javax.wireless.messaging.Message message) {
System.out.println("SMS just sent from your device!");
}
}
You need to register your listener with the MessageConnection per the API documentation.
The simulator can't really send SMS messages so you may have to do this on a device.

Tried to read incoming SMS content but getting Error in Blackberry

Hi friends i am trying to read incoming sms but getting warning like this . Invocation of questionable method: java.lang.String.(String) found in: mypackage.MyApp$ListeningThread.run()
Here is my code is
public class MyApp extends UiApplication {
//private ListeningThread listener;
public static void main(String[] args) {
MyApp theApp = new MyApp();
theApp.enterEventDispatcher();
}
public MyApp() {
invokeAndWait(new Runnable() {
public void run() {
ListeningThread listener = new ListeningThread();
listener.start();
}
});
pushScreen(new MyScreen());
}
private static class ListeningThread extends Thread {
private boolean _stop = false;
private DatagramConnection _dc;
public synchronized void stop() {
_stop = true;
try {
_dc.close(); // Close the connection so the thread returns.
} catch (IOException e) {
System.err.println(e.toString());
}
}
public void run() {
try {
_dc = (DatagramConnection) Connector.open("sms://");
for (;;) {
if (_stop) {
return;
}
Datagram d = _dc.newDatagram(_dc.getMaximumLength());
_dc.receive(d);
String address = new String(d.getAddress());
String msg = new String(d.getData());
if(msg.startsWith("START")){
Dialog.alert("hello");
}
System.out.println("Message received: " + msg);
System.out.println("From: " + address);
System.exit(0);
}
} catch (IOException e) {
System.err.println(e.toString());
}
}
}
}
Please correct me where i am wrong.Is possible give me some code to read incoming sms content in blackberry.
A few points about your code:
That invokeAndWait call to launch a thread makes no sense. It doesn't harm, but is kind of waste. Use that method only to perform UI related operations.
You should try using "sms://:0" as param for Connector.open. According to the docs, a parameter with the form {protocol}://[{host}]:[{port}] will open the connection in client mode (which makes sense, since you are on the receiving part), whereas not including the host part will open it in server mode.
Finally, if you can't get it working, you could use instead the third method specified in this tutorial, which you probably have already read.
The error you quoted is complaining about the use of the String constructor that takes a string argument. Since strings are immutable in Java-ME, this is just a waste. You can use the argument string directly:
Invocation of questionable method: java.lang.String.(String) found in: mypackage.MyApp$ListeningThread.run()
//String address = new String(d.getAddress());
String address = d.getAddress();
// getData() returns a byte[], so this is a different constructor
// However, this leaves the character encoding unspecified, so it
// will default to cp1252, which may not be what you want
String msg = new String(d.getData());

Resources