How to send a XMPP IQ Package to a PHP JAXL-Script? - android

ive a problem. Im using asmack for connecting and sending Data between Android and OpenFire.
Now i'ld like to get this data with PHP and Jaxl (which is working fine).
The problem is that i modify the sent message (to JSON and XML) and add a HEADER to the XML/JSON. This seems to work well but its not a proper solution.
Now i'm thinking about sending IQ Packages which hold the Header information already.
This is the Part in Android/Java.
CommandIQPacket iq1 = new CustomIQPacket();
iq1.setTo(to);
iq1.setType(IQ.Type.GET);
iq1.setCommand("test");
iq1.setPriority(1);
iq1.setJid(message.getMessage());
iq1.setDate(new Date(System.currentTimeMillis()));
mConnection.sendPacket(iq1);
The CustomIQPacket class extends IQ and add the required data by overriding getChildElementXML().
Sample:
public class CommandIQPacket extends IQ {
private int priority;
private String jid, command;
//some getter and setter
#Override
public CharSequence getChildElementXML() {
StringBuilder builder = new StringBuilder("<query xmlns=\"urn:xmpp:ts\">");
builder.append("<jid command=\"");
builder.append(command).append("\"");
builder.append(" date=\"");
builder.append(date).append("\"");
builder.append(" priority=\"");
builder.append(priority).append("\"");
builder.append(">");
builder.append(jid);
builder.append("</jid>");
builder.append("</query>");
return builder.toString();
}
}
Now i've my PHP CLI Script with JAXL. This looks like that.
<?php
// configs, stuff, etc.
$client = new JAXL(array(
'jid' => "myopenfireuser",
'pass' => "myopenfirepass",
'bosh_url' => "http://url-to-bosh.com:7070/http-bind/",
'log_level' => JAXL_INFO,
'strict' => TRUE
));
$client->require_xep(array(
'0115', // Entity Capabilities
'0203', // Delayed Delivery
'0114', // jabber component protocol
'1337'
));
ive added 1337 here, which should be the XEP for parsing the IQ package.
$client->add_cb('on_chat_message', function($stanza) {
global $client;
$iq = $client->xeps['1337']->get_raw_iq_pkt();
// some more stuff
}
Now it seems to be that $iq does not hold any rawdata. I cant access the XML which means that i cant parse the IQ Package.
The 1337 XEP looks like that.
class XEP_1337 extends XMPPXep {
public function init() {
return array(
'on_get_iq' => 'on_xmpp_iq'
);
}
public function get_raw_iq_pkt() {
$attrs = array(
'type' => 'get',
'from' => $this->jaxl->full_jid->to_string(),
'to' => $this->jaxl->full_jid->domain
);
return $this->jaxl->get_iq_pkt(
$attrs, new JAXLXml('query', "ts")
);
}
}
I couldnt find any good tutorial about JAXL and IQ Packages. This is the only readme ive found about it (https://media.readthedocs.org/pdf/jaxl/latest/jaxl.pdf)
The sent data is for example
<iq id='qEfml-14' to='openfirebot#openfirebot.com/Ressource' type='get'><query xmlns="ts"><jid command="test" date="Mon Jul 28 12:36:15 MESZ 2014" priority="1">...</query></iq>
the return value from openfire (jaxl) is
<iq type="error" id="NP3HP-12" from="bot..#myopenfire.com" to="maclient#ts.com/Ressource"><query xmlns="ts" action="create"><jid command="test" date="Mon Jul 28 23:04:22 MESZ 2014" priority="1">...</jid></query><error code="503" type="cancel"><service-unavailable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error></iq>
OpenFire error=
at org.apache.mina.filter.executor.ExecutorFilter$ProcessEventsRunnable.run(ExecutorFilter.java:283)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:51)
at java.lang.Thread.run(Thread.java:701)
2014.07.29 15:56:33 org.jivesoftware.openfire.nio.ConnectionHandler - Closing connection due to error while processing message: <iq id="769-83772" to="ts.com" from="ts.com/4140f14a" type="result"></iq>
java.lang.NullPointerException
at org.jivesoftware.openfire.IQRouter.route(IQRouter.java:115)
at org.jivesoftware.openfire.spi.PacketRouterImpl.route(PacketRouterImpl.java:76)
at org.jivesoftware.openfire.net.StanzaHandler.processIQ(StanzaHandler.java:330)
at org.jivesoftware.openfire.net.ClientStanzaHandler.processIQ(ClientStanzaHandler.java:93)
at org.jivesoftware.openfire.net.StanzaHandler.process(StanzaHandler.java:295)
at org.jivesoftware.openfire.net.StanzaHandler.process(StanzaHandler.java:187)
at org.jivesoftware.openfire.nio.ConnectionHandler.messageReceived(ConnectionHandler.java:181)
at org.apache.mina.common.support.AbstractIoFilterChain$TailFilter.messageReceived(AbstractIoFilterChain.java:570)
at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
at org.apache.mina.common.IoFilterAdapter.messageReceived(IoFilterAdapter.java:80)
at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
at org.apache.mina.filter.codec.support.SimpleProtocolDecoderOutput.flush(SimpleProtocolDecoderOutput.java:58)
at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:185)
at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
at org.apache.mina.filter.executor.ExecutorFilter.processEvent(ExecutorFilter.java:239)
at org.apache.mina.filter.executor.ExecutorFilter$ProcessEventsRunnable.run(ExecutorFilter.java:283)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:51)
at java.lang.Thread.run(Thread.java:701)

This is what ive found out now:
Its important that to has the fullname with ressource. user#domain/Ressource
And.. the Receiving client must be online. Offline messages dont get accepted for IQ PAckets from OpenFire (by default)
And.. regarding this article it must be registered somehow. How can this be done in jaxl? i thought adding the XEP and using init() is enough.
Sending and Receiving custom XMPP IQs with aSmack on Android
And.. ive modified the PAcketListener but still same result.
PacketFilter filter = new PacketFilter() {
#Override
public boolean accept(Packet packet) {
return true;
}
};
mConnection.addPacketListener(mPacketListener, filter);
ProviderManager.addIQProvider("query", "ts", new CommandIQProvider());
while mPacketListener is a class which extends from PacketListener.
public class ChatPacketListener implements PacketListener {
public void processPacket(Packet packet) {
if (packet instanceof Message) {
Message message = (Message) packet;
String from = message.getFrom();
if (message.getBody() != null) {
Log.d("ChatPacketLsitener", "XMPP packet received - sending Intent: " + XmppService.ACTION_XMPP_MESSAGE_RECEIVED);
XmppService.maybeAcquireWakeLock();
XmppTools.startSvcXMPPMsg(mCtx, message.getBody(), from);
}
} else {
Log.e("Packet", "Packet is not from type Message. Its from type " + packet.getClass());
}
}

Related

GraphQL server returns a 422 Error when request sent from Android app via Apollo Client

Hi I've been trying to set up a simple Android app to send a query to a GraphQL server I set up on my localhost via Springboot. If I don't use the app to send a request, either through GraphiQL or Postman, everything is fine and I have absolutely no issues. It's only when I send the request in the app through an Apollo Client that I get a 422 error.
I've set up log statements in Springboot that hosts the GraphQL server to log the payload.
Here's the schema as defined in Springboot.
type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
Here's the query as defined in AndroidStudio for the Apollo Client to work with.
query BookById($id : ID) {
bookById(id : $id){
name
author{
firstName
lastName
}
}}
Here's the code in Android Studio.
public class MainActivity extends AppCompatActivity {
private static final String BASE_URL = "http://xxx.xxx.xxx.xxx:8080/graphql";
private static final String TAG = "MainActivity";
private TextView textBox;
private Button queryButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textBox = (TextView) findViewById(R.id.plainbox);
queryButton = (Button) findViewById(R.id.queryButton);
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
ApolloClient apolloClient = ApolloClient.builder()
.serverUrl(BASE_URL)
.okHttpClient(okHttpClient)
.build();
// To make requests to our GraphQL API we must use an instance
// of a query or mutation class generated by Apollo.
Input<String> id = Input.fromNullable("book-1");
BookByIdQuery bq = BookByIdQuery.builder()
.id("book-1")
.build();
queryButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d(TAG, "REGISTERED CLICK");
Log.d(TAG, "Book Query: " + bq.queryDocument());
apolloClient.query(bq).enqueue(new
ApolloCall.Callback<BookByIdQuery.Data>() {
#Override
public void onResponse(#NotNull com.apollographql.apollo.api.Response<BookByIdQuery.Data> dataResponse){
Log.d(TAG, "Got Response: \n" + dataResponse.toString());
// changing UI must be on UI thread
textBox.setText(dataResponse.data().toString());
}
#Override
public void onFailure(#NotNull ApolloException a){
Log.d(TAG, "Failed, ApolloException " + a);
}
}); // end apolloClient query
}
});
}
Here's the log on the server side I get if making a request via GraphiQL or Postman.
DEBUG 13749 --- [nio-8080-exec-8] o.s.w.f.CommonsRequestLoggingFilter : Before request [uri=/graphql]
Here's the log when the request comes from Apollo in the app.
DEBUG 13749 --- [io-8080-exec-10] o.s.w.f.CommonsRequestLoggingFilter : Before request [uri=/graphql]
DEBUG 13749 --- [io-8080-exec-10] o.s.w.f.CommonsRequestLoggingFilter : REQUEST DATA : uri=/graphql;payload={"operationName":"BookById","variables":{"id":"book-1"},"query":"query BookById($id: ID) { bookById(id: $id) { __typename name author { __typename firstName lastName } }}"}]
Could the issue be related to the __typename attribute that Apollo is adding? Or could it be due to "id" being defined as a simple parameter in the server side schema but it being a variable in the Android Studio definition of the query?
I just expected to receive the response back with no issues since it seems to work every other way. Even if I type in the query manually into my web browser I have no issues getting the right response, it's only when working with Apollo Client in G̶r̶a̶p̶h̶Q̶L̶ Android Studio that this issue pops up and I'm at a complete loss as to why. I appreciate any help people can offer. Thanks in advance.
Update: So looking around some more it looks like when sending a query via ApolloClient it sends the query as an object instead of as a JSON string. Now I'm thinking that's probably the cause of the 422 error. I've also read that allowing my GraphQL server to accept objects in addition to JSON strings is something I must enable. I'm not really sure how to go about that though, so does anyone with experience with Spring Boot have any advice on how I could go about doing that? Thanks.

How to get 'to' field in firebase could messaging JSON?

I can succesfully send Firebase cloud messages to my Android sample project. As described in here, I apply step 2 and it works so far.
My JSON body:
{
"to": "/topics/testTopic",
"data": {
"key1" : "val1",
"key2" : true
}
}
has a data field which I can access properly in my onMessageReceived() method:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
String toVal = remoteMessage.getTo();
Map<String, String> data = remoteMessage.getData();
}
But the getTo() method gets null.
How can I access the 'to' field in my originating JSON?
I was expecting to have "/topics/testTopic" in im variable toVal.
I think you're looking for RemoteMessage.getFrom():
Get the sender of this message.
This will be the sender ID or the topic for topic messages.

Fetching additional data from AWS SNS Push Notification

I have a problem regarding my SNS Push Notifications. I have the following lambda code:
db.scan(params, function(err, data) {
if (err) {
console.log(err); // an error occurred
}
else {
data.Items.forEach(function(record) {
var receiverID = record.userDeviceToken.S;
var message = "You have a new invitation to the event";
var topic = "Friend's invitation";
var eventText = JSON.stringify(event);
console.log("Received event:", eventText);
var sns = new AWS.SNS();
var params = {
Message: message,
Subject: "Friend's invitation",
TargetArn: receiverID,
};
sns.publish(params, function(err, data) {
if (err) {
console.log('Failed to publish SNS message');
context.fail(err);
}
else {
console.log('SNS message published successfully');
context.succeed(data);
}
});
});
//context.succeed(data.Items); // data.Items
}
});
};
Now my goal is to get the "Subject" or "topic" sometimes, if it is possible. I cannot find it in documentation, and I need it to customize my notification title depending on the push message sent (I have few functions).
When I used sample amazon app I found this cound in Push Listener Service:
public static String getMessage(Bundle data) {
// If a push notification is sent as plain text, then the message appears in "default".
// Otherwise it's in the "message" for JSON format.
return data.containsKey("default") ? data.getString("default") : data.getString(
"message", "");
}
This works, but the "data" itself has the following data:
Bundle[{google.sent_time=1480364966070, google.message_id=0:1480364966079787%22269524f9fd7ecd, default=You have a new invitation to the event, collapse_key=do_not_collapse}]
Therefore, it is just providing some internal data and the "message" itself. I cannot access the topic.
My question is: how to get other variables in the Android code so I can use them further on? Can I add custom variables by myself through data bundle?
I have notifications in JSON format. I just wonder, whether the only way is to put the data I want in JSON format inside the message, and then read the message accordingly, or maybe I can attach the required data from lambda function to the push notification already?

Accessing JSON object inside Message Stanza using Smack Library

my addAsyncStanzaListner is being called when an ack message is received from Firebase Cloud Messaging services. I need to ack this messages according to the docs. The problem that I am having is I can't reach the "message_type" "key"/"value" pair inside the JSON object that arrives inside the message stanza that's received. Could you please help me in accessing this important value/pair. I am using Smack Library 4.1. I've been following this post answer for this setup, but somehow It doesn't work:
GCM XMPP Server using Smack 4.1.0
Here's how the code is looking like:
other_connection.addAsyncStanzaListener(new StanzaListener() {
#Override
public void processPacket(Stanza packet) throws SmackException.NotConnectedException {
//how should i convert this stanza into a message stanza
//I have tried Message message = (Message)packet; IT DOESNT WORK
//I have tried getting the extension with the GCM Namespace. It doesnt
//return a json string
In your code you just recive a Stanza as Java Object.
Stanza has a method to output an XML.
You can use this method to obtain a JSON if you need, just add some custom functionality.
Following this example
your code can looks like this:
#Override
public void processPacket(Stanza packet) throws SmackException.NotConnectedException {
JSONObject jsonObj = XML.toJSONObject(packet.toXML());
String json = jsonObj.toString();
//foo
Note: This answer is for the general problem of extracting JSON from a message. In the case of FCM, it's possible that there's another method that's more appropriate.
Suppose your have a Stanza object that corresponds to the following XML:
<message from='a#example.com' to='b#example.com' type='normal'>
<json xmlns='urn:xmpp:json:0'>{ "key1" : "value1", "key2": "value2" }</json>
<body/>
</message>
To extract the JSON string, you need to do:
import org.jivesoftware.smackx.json.packet.JsonPacketExtension;
...
JsonPacketExtension jsonPacketExtension = JsonPacketExtension.from(stanza);
String contentJson = jsonPacketExtension.getJson();

XMPP IQ result parsing issue

I am building a XMPP chat client app with eclipse, java and asmack. Using tutorials and many many google searches I managed to get the buddy list working, actual chatting also works fine.
My problem is with searching for more buddies to add to my contacts list. The XML to send is exemplified here : http://xmpp.org/extensions/xep-0055.html
My request is :
<iq
id="search123"
from="name3#webserv.xxx.com/name3"
to="search.xxx.zzz.com"
type="set" >
<query xmlns="jabber:iq:search" >
<nick>
android
</nick>
</query>
</iq>
the response I thought I was getting was/is this:
<iq
id="search123"
from="search.xxx.zzz.com"
to="name3#webserv.telebroad.com/Smack"
type="result" >
</iq>
But using
connConfig.setDebuggerEnabled(true);
(and an online Telnet Client) I managed to find out that the server IS actually working correctly and it's sending the requested results, but I'm just getting what you see above.
I have been at this for 4 days and my self esteem is quite low :P
Here is my code concerning the IQ request and response:
Packet asdf = new Packet() {
#Override
public String toXML() {
return "<iq type='set'"+
" from='name3#webserv.xxx.com/name3'"+
" to='search.xxx.zzz.com'"+
" id='search2'"+
" xml:lang='en'>"+
" <query xmlns='jabber:iq:search'>"+
" <nick>Android</nick>"+
" </query>"+
" </iq>";
}
};
ChatList.connection.sendPacket(asdf);
Log.e("packet", "request = "+ asdf.toXML());
PacketFilter filter = new IQTypeFilter(IQ.Type.RESULT);
ChatList.connection.addPacketListener(new PacketListener() {
public void processPacket(Packet packet) {
IQ iq = (IQ)packet;
Log.e("response","incoming packet : "+ packet.toXML());
Log.e("response","incoming packet2 : "+ packet.toString());
}
}, filter);
I've tried lots of TypeFilters to no avail. I'm stumped!!
Bottom line:
1.request is being accepted correctly by server;
2.server response is correct(so says the debugger);
3.any response.toString or toXML prints out the type result XML from above(without the actual items after type='result'>.
4.I am about a week overdue on my final build for this app...help! :)
Try adding
ProviderManager pm = ProviderManager.getInstance();
pm.addIQProvider( "query","jabber:iq:search",new UserSearch.Provider());
pm.addExtensionProvider("x","jabber:x:data", new DataFormProvider());
before establishing connection.
This spec is already implemented via the UserSearchManager. Try using that instead.
As for your own case, I would guess that you haven't registered an appropriate provider for this specific element and namespace (like org.jivesoftware.smackx.search.UserSearch$Provider). In a normal Java environment, this would already be registered, but you will have to code it yourself in Android.
https://stackoverflow.com/a/14214622/1688731
This...just works!!!! I have no idea why. maybe Iterator iterator = row.getValues("jid"); does the trick. But everything else, I've tried a LOT of times!!

Categories

Resources