google cloud messaging - xmpp server side using smack not working - java

when taking the code below for sending a message to a device with using smack libary 3.3.0
Getting an error
SASL authentication PLAIN failed: text:
at org.jivesoftware.smack.SASLAuthentication.authenticate(SASLAuthentication.java:342)
at org.jivesoftware.smack.XMPPConnection.login(XMPPConnection.java:221)
at org.jivesoftware.smack.Connection.login(Connection.java:366)
at com.test.xmpp.SmackCcsClient.connect(SmackCcsClient.java:335)
at com.test.xmpp.SmackCcsClient.main(SmackCcsClient.java:345)
When switching to HTTP server side, the messaging is working
/**
* Sample Smack implementation of a client for GCM Cloud Connection Server.
*
* <p>For illustration purposes only.
*/
public class SmackCcsClient {
Logger logger = Logger.getLogger("SmackCcsClient");
public static final String GCM_SERVER = "gcm.googleapis.com";
public static final int GCM_PORT = 5235;
public static final String GCM_ELEMENT_NAME = "gcm";
public static final String GCM_NAMESPACE = "google:mobile:data";
static Random random = new Random();
XMPPConnection connection;
ConnectionConfiguration config;
/**
* XMPP Packet Extension for GCM Cloud Connection Server.
*/
class GcmPacketExtension extends DefaultPacketExtension {
String json;
public GcmPacketExtension(String json) {
super(GCM_ELEMENT_NAME, GCM_NAMESPACE);
this.json = json;
}
public String getJson() {
return json;
}
#Override
public String toXML() {
return String.format("<%s xmlns=\"%s\">%s</%s>", GCM_ELEMENT_NAME,
GCM_NAMESPACE, json, GCM_ELEMENT_NAME);
}
#SuppressWarnings("unused")
public Packet toPacket() {
return new Message() {
// Must override toXML() because it includes a <body>
#Override
public String toXML() {
StringBuilder buf = new StringBuilder();
buf.append("<message");
if (getXmlns() != null) {
buf.append(" xmlns=\"").append(getXmlns()).append("\"");
}
if (getLanguage() != null) {
buf.append(" xml:lang=\"").append(getLanguage()).append("\"");
}
if (getPacketID() != null) {
buf.append(" id=\"").append(getPacketID()).append("\"");
}
if (getTo() != null) {
buf.append(" to=\"").append(StringUtils.escapeForXML(getTo())).append("\"");
}
if (getFrom() != null) {
buf.append(" from=\"").append(StringUtils.escapeForXML(getFrom())).append("\"");
}
buf.append(">");
buf.append(GcmPacketExtension.this.toXML());
buf.append("</message>");
return buf.toString();
}
};
}
}
public SmackCcsClient() {
// Add GcmPacketExtension
ProviderManager.getInstance().addExtensionProvider(GCM_ELEMENT_NAME,
GCM_NAMESPACE, new PacketExtensionProvider() {
#Override
public PacketExtension parseExtension(XmlPullParser parser)
throws Exception {
String json = parser.nextText();
GcmPacketExtension packet = new GcmPacketExtension(json);
return packet;
}
});
}
/**
* Returns a random message id to uniquely identify a message.
*
* <p>Note:
* This is generated by a pseudo random number generator for illustration purpose,
* and is not guaranteed to be unique.
*
*/
public String getRandomMessageId() {
return "m-" + Long.toString(random.nextLong());
}
/**
* Sends a downstream GCM message.
*/
public void send(String jsonRequest) {
Packet request = new GcmPacketExtension(jsonRequest).toPacket();
connection.sendPacket(request);
}
/**
* Handles an upstream data message from a device application.
*
* <p>This sample echo server sends an echo message back to the device.
* Subclasses should override this method to process an upstream message.
*/
public void handleIncomingDataMessage(Map<String, Object> jsonObject) {
String from = jsonObject.get("from").toString();
// PackageName of the application that sent this message.
String category = jsonObject.get("category").toString();
// Use the packageName as the collapseKey in the echo packet
String collapseKey = "echo:CollapseKey";
#SuppressWarnings("unchecked")
Map<String, String> payload = (Map<String, String>) jsonObject.get("data");
payload.put("ECHO", "Application: " + category);
// Send an ECHO response back
String echo = createJsonMessage(from, getRandomMessageId(), payload, collapseKey, null, false);
send(echo);
}
/**
* Handles an ACK.
*
* <p>By default, it only logs a INFO message, but subclasses could override it to
* properly handle ACKS.
*/
public void handleAckReceipt(Map<String, Object> jsonObject) {
String messageId = jsonObject.get("message_id").toString();
String from = jsonObject.get("from").toString();
logger.log(Level.INFO, "handleAckReceipt() from: " + from + ", messageId: " + messageId);
}
/**
* Handles a NACK.
*
* <p>By default, it only logs a INFO message, but subclasses could override it to
* properly handle NACKS.
*/
public void handleNackReceipt(Map<String, Object> jsonObject) {
String messageId = jsonObject.get("message_id").toString();
String from = jsonObject.get("from").toString();
logger.log(Level.INFO, "handleNackReceipt() from: " + from + ", messageId: " + messageId);
}
/**
* Creates a JSON encoded GCM message.
*
* #param to RegistrationId of the target device (Required).
* #param messageId Unique messageId for which CCS will send an "ack/nack" (Required).
* #param payload Message content intended for the application. (Optional).
* #param collapseKey GCM collapse_key parameter (Optional).
* #param timeToLive GCM time_to_live parameter (Optional).
* #param delayWhileIdle GCM delay_while_idle parameter (Optional).
* #return JSON encoded GCM message.
*/
public static String createJsonMessage(String to, String messageId, Map<String, String> payload,
String collapseKey, Long timeToLive, Boolean delayWhileIdle) {
Map<String, Object> message = new HashMap<String, Object>();
message.put("to", to);
if (collapseKey != null) {
message.put("collapse_key", collapseKey);
}
if (timeToLive != null) {
message.put("time_to_live", timeToLive);
}
if (delayWhileIdle != null && delayWhileIdle) {
message.put("delay_while_idle", true);
}
message.put("message_id", messageId);
message.put("data", payload);
return JSONValue.toJSONString(message);
}
/**
* Creates a JSON encoded ACK message for an upstream message received from an application.
*
* #param to RegistrationId of the device who sent the upstream message.
* #param messageId messageId of the upstream message to be acknowledged to CCS.
* #return JSON encoded ack.
*/
public static String createJsonAck(String to, String messageId) {
Map<String, Object> message = new HashMap<String, Object>();
message.put("message_type", "ack");
message.put("to", to);
message.put("message_id", messageId);
return JSONValue.toJSONString(message);
}
/**
* Connects to GCM Cloud Connection Server using the supplied credentials.
*
* #param username GCM_SENDER_ID#gcm.googleapis.com
* #param password API Key
* #throws XMPPException
*/
public void connect(String username, String password) throws XMPPException {
config = new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
config.setSecurityMode(SecurityMode.enabled);
config.setReconnectionAllowed(true);
config.setRosterLoadedAtLogin(false);
config.setSendPresence(false);
config.setSocketFactory(SSLSocketFactory.getDefault());
// NOTE: Set to true to launch a window with information about packets sent and received
config.setDebuggerEnabled(true);
// -Dsmack.debugEnabled=true
XMPPConnection.DEBUG_ENABLED = true;
connection = new XMPPConnection(config);
connection.connect();
connection.addConnectionListener(new ConnectionListener() {
#Override
public void reconnectionSuccessful() {
logger.info("Reconnecting..");
}
#Override
public void reconnectionFailed(Exception e) {
logger.log(Level.INFO, "Reconnection failed.. ", e);
}
#Override
public void reconnectingIn(int seconds) {
logger.log(Level.INFO, "Reconnecting in %d secs", seconds);
}
#Override
public void connectionClosedOnError(Exception e) {
logger.log(Level.INFO, "Connection closed on error.");
}
#Override
public void connectionClosed() {
logger.info("Connection closed.");
}
});
// Handle incoming packets
connection.addPacketListener(new PacketListener() {
#Override
public void processPacket(Packet packet) {
logger.log(Level.INFO, "Received: " + packet.toXML());
Message incomingMessage = (Message) packet;
GcmPacketExtension gcmPacket =
(GcmPacketExtension) incomingMessage.getExtension(GCM_NAMESPACE);
String json = gcmPacket.getJson();
try {
#SuppressWarnings("unchecked")
Map<String, Object> jsonObject =
(Map<String, Object>) JSONValue.parseWithException(json);
// present for "ack"/"nack", null otherwise
Object messageType = jsonObject.get("message_type");
if (messageType == null) {
// Normal upstream data message
handleIncomingDataMessage(jsonObject);
// Send ACK to CCS
String messageId = jsonObject.get("message_id").toString();
String from = jsonObject.get("from").toString();
String ack = createJsonAck(from, messageId);
send(ack);
} else if ("ack".equals(messageType.toString())) {
// Process Ack
handleAckReceipt(jsonObject);
} else if ("nack".equals(messageType.toString())) {
// Process Nack
handleNackReceipt(jsonObject);
} else {
logger.log(Level.WARNING, "Unrecognized message type (%s)",
messageType.toString());
}
} catch (ParseException e) {
logger.log(Level.SEVERE, "Error parsing JSON " + json, e);
} catch (Exception e) {
logger.log(Level.SEVERE, "Couldn't send echo.", e);
}
}
}, new PacketTypeFilter(Message.class));
// Log all outgoing packets
connection.addPacketInterceptor(new PacketInterceptor() {
#Override
public void interceptPacket(Packet packet) {
logger.log(Level.INFO, "Sent: {0}", packet.toXML());
}
}, new PacketTypeFilter(Message.class));
connection.login(username, password);
}
public static void main(String [] args) {
final String userName = "124079202908" + "#gcm.googleapis.com";
final String password = "AIzaSyAMt1y_xILk72wiQybuqVEdiq7uGXBEUhQ";
SmackCcsClient ccsClient = new SmackCcsClient();
try {
ccsClient.connect(userName, password);
} catch (XMPPException e) {
e.printStackTrace();
}
}
}
Also I submitted a request for using the API over a week ago and didn't recieve a reply yet.

The problem is resolved. The issue was indeed that the project wasn't registered. I received an email from Google 2 weeks after asking for the API receiving confirmation.
The error in this case really should be improved and it would be nice if Google wrote approximately how long to receive the email.
Just wanted to update anyone else encountering the problem.

#user2679041 i guess you are saying right. I have register my gcm project id just today and i haven't receive any confirmation email yet. That's really annoying, who else is going to wait for a 2 weeks? I have saw few queries # stackoverflow that people says there request approved by google after 3 months too.
I have followed the this link
and its has a note saying :
After you have created your GCM enabled project in the API Console you must fill out this form and become a trial partner to use upstream messaging and user notifications via CCS. Access is limited to those that fill out the form. You will receive an email from Google informing you that you now have access; Google will also send you the address of an echo server that you can use to bounce messages back to your application.
So we might say Google has released beta version with limited no. of access.

Related

FCM android client randomly stops receiving data messages

I've implemented FCM on my server with an Android client, and it worked fine for a while. All of a sudden, the client stopped receiving notifications for 5-10 minutes at a time, after which it would get all the pending notifications at once. The logs show that the server is sending the messages correctly.
When the message queue gets stuck, not even test messages from the Firebase console get through.
The only relevant thing I've found in the official documentation was regarding the lifetime of a message:
If the device is not connected to FCM, the message is stored until a connection is established (again respecting the collapse key rules). When a connection is established, FCM delivers all pending messages to the device.
But my network is working fine, and this issue has arisen on other networks and clients as well. When I freshly install the app, a new token is being generated and successfully received by my server. It's just the server-to-client messages that aren't going through.
How can I determine if the connection is established and fix it? Or what else could be the cause of this?
This is my client-side code
AndroidManifest.xml
<application
android:name=".App"
android:allowBackup="false"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:largeHeap="true"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
android:usesCleartextTraffic="true"
tools:ignore="GoogleAppIndexingWarning">
<service
android:name=".service.NotificationService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
NotificationService.java
public class NotificationService extends FirebaseMessagingService {
private static final String TAG = "NotificationService";
private static String token;
public NotificationService() {
token = PreferenceManager
.getDefaultSharedPreferences(App.getContext())
.getString("firebase-token", null);
}
#Override
public void onNewToken(#NonNull String s) {
super.onNewToken(s);
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(#NonNull Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
Log.w(TAG, "getInstanceId failed", task.getException());
return;
}
token = task.getResult().getToken();
Log.d(TAG, "onComplete: token = " + token);
PreferenceManager
.getDefaultSharedPreferences(App.getContext())
.edit()
.putString("firebase-token", token)
.apply();
}
});
}
#Override
public void onMessageReceived(final RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.d(TAG, "Received message of size " + remoteMessage.getData().size());
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
Handler h = new Handler(Looper.getMainLooper());
h.post(new Runnable() {
public void run() {
int left = -1, right = -1;
if (remoteMessage.getData().get("left") != null) {
left = Integer.parseInt(Objects.requireNonNull(remoteMessage.getData()
.get("left")));
}
if (remoteMessage.getData().get("right") != null) {
right = Integer.parseInt(Objects.requireNonNull(remoteMessage.getData()
.get("right")));
}
if (remoteMessage.getData().get("REFRESH") != null) {
Util.sendTitleBroadcast(getApplicationContext(),
left, right,
Util.REFRESH_TITLE);
} else {
Util.sendTitleBroadcast(getApplicationContext(),
left, right,
Util.TITLE_DATA_RECEIVED);
}
}
});
}
}
public static String getToken() {
if (token == null) {
token = PreferenceManager
.getDefaultSharedPreferences(App.getContext())
.getString("firebase-token", null);
}
return token;
}
}
Code for server-side
FirebaseMessagingService.java
public class FirebaseMessagingService {
private static final Logger logger = Logger
.getLogger(FirebaseMessagingService.class);
private static FirebaseMessagingService instance;
/**
* Path to resource file that contains the credentials for Admin SDK.
*/
private final String keyPath = "firebase-adminsdk.json";
/**
* Maps a token list to each topic Object.
*/
private static Map<Object, List<String>> topicTokenMap;
public synchronized static FirebaseMessagingService getInstance() {
if (instance == null) {
instance = new FirebaseMessagingService();
}
return instance;
}
private FirebaseMessagingService() {
init();
}
/**
* Initializes the Firebase service account using the credentials from the
* json file found at keyPath.
*/
private void init() {
try {
InputStream serviceAccount
= getClass().getClassLoader().getResourceAsStream(keyPath);
if (serviceAccount != null) {
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials
.fromStream(serviceAccount))
.setDatabaseUrl(databaseUrl)
.build();
FirebaseApp.initializeApp(options);
logger.debug("FirebaseMessagingService: init successful");
} else {
logger.debug("FirebaseMessagingService: Input stream null from"
+ " path: " + keyPath);
}
} catch (IOException ex) {
logger.debug("FirebaseMessagingService: Failed to get credentials "
+ "from inputStream." + ex.getMessage());
}
}
/**
* Sends the messages given as parameters to the list of tokens mapped to
* the given topic Object.
*
* #param topic
* #param messages
*/
public void sendMessage(Object topic,
Map<String, String> messages) {
logger.debug("FirebaseMessagingService: sending Message "
+ messages.toString());
try {
if (topicTokenMap != null) {
List<String> tokenList = topicTokenMap.get(topic);
if (tokenList != null) {
tokenList.removeAll(Collections.singleton(null));
MulticastMessage message = MulticastMessage.builder()
.putAllData(messages)
.addAllTokens(tokenList)
.build();
FirebaseMessaging.getInstance().sendMulticast(message);
logger.debug("FirebaseMessagingService: message sent successfully");
}
}
} catch (FirebaseMessagingException ex) {
logger.debug(ex.getMessage());
}
}
/**
* Registers the token given as a parameter to the topic Object.
*
* #param topic
* #param token
*/
public void registerTokenToTopic(Object topic, String token) {
if (topicTokenMap == null) {
topicTokenMap = new HashMap<Object, List<String>>();
}
List<String> tokens = topicTokenMap.get(topic);
if (tokens == null) {
tokens = new ArrayList<String>();
}
if (!tokens.contains(token)) {
tokens.add(token);
}
topicTokenMap.put(topic, tokens);
}
/**
* Unregisters all instances of the token given as a parameter from the topic
* given.
*
* #param topic
* #param token
*/
public void unregisterTokenFromTopic(Object topic, String token) {
if (topicTokenMap != null) {
List<String> tokens = topicTokenMap.get(topic);
if (tokens != null) {
tokens.removeAll(Collections.singleton(token));
}
}
}
/**
* Looks for a topic that has a field with the name equal to topicFieldName
* and the value equal to topicFieldValue and sends a notification to the
* tokens subscribed to that topic, telling them to ask for an update.
*
* #param topicFieldName
* #param topicFieldValue
*/
public void notifyChangeForTopicField(String topicFieldName,
Object topicFieldValue) {
logger.debug("FirebaseMessagingService: notifyChangeForTopicField: "
+ "topicFieldValue = " + topicFieldValue.toString());
Map<String, String> messageMap = new HashMap<String, String>();
messageMap.put("REFRESH", "true");
if (topicTokenMap != null
&& topicTokenMap.entrySet() != null
&& topicTokenMap.entrySet().size() > 0) {
Iterator it = topicTokenMap.entrySet().iterator();
while (it.hasNext()) {
try {
Map.Entry pair = (Map.Entry) it.next();
Object topic = pair.getKey();
logger.debug("FirebaseMessagingService: "
+ "notifyChangeForTopicField topic = " + topic.toString());
Field field = topic.getClass().getDeclaredField(topicFieldName);
logger.debug("FirebaseMessagingService: "
+ "notifyChangeForTopicField field = " + field.toString());
field.setAccessible(true);
logger.debug("FirebaseMessagingService: "
+ "notifyChangeForTopicField field contains topic: "
+ (field.get(topic) != null ? "true" : "false"));
if (field.get(topic) != null
&& field.get(topic).equals(topicFieldValue)) {
sendMessage(topic, messageMap);
break;
}
it.remove();
} catch (NoSuchFieldException ex) {
java.util.logging.Logger.getLogger(FirebaseMessagingService.class.getName()).log(Level.SEVERE, null, ex);
} catch (SecurityException ex) {
java.util.logging.Logger.getLogger(FirebaseMessagingService.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalArgumentException ex) {
java.util.logging.Logger.getLogger(FirebaseMessagingService.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(FirebaseMessagingService.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
EDIT: after a few more tests I've found that when one client stops working, the others receive the messages just fine
Your onMessageReceived() looks a bit overkill to me. I do not think you have to create your own Handler to process data. Just stick to the Firebase example: FirebaseExample
override fun onMessageReceived(remoteMessage: RemoteMessage) {
if (remoteMessage.data.isNotEmpty()) {
Log.d(TAG, "Message data payload: ${remoteMessage.data}")
if (/* Check if data needs to be processed by long running job */ true) {
// For long-running tasks (10 seconds or more) use WorkManager.
scheduleJob()
} else {
// Handle message within 10 seconds
handleNow()
}
}
}
I've found the answer here: https://stackoverflow.com/a/23902751/10702209
What happened was that I was getting router timeouts after 5 minutes, randomly. I've fixed the issue by manually sending out heartbeats to FCM after 4 minutes, instead of the default 15 minutes.
context.sendBroadcast(new Intent("com.google.android.intent.action.GTALK_HEARTBEAT"));
context.sendBroadcast(new Intent("com.google.android.intent.action.MCS_HEARTBEAT"));
I've implemented this fix a couple of months ago and haven't had the issue come up again since.

Data fetching from an API in android

I have tried to fetch data from an API which has a key. But in the output it says "app key not found".
I have tested it on Postman and it works properly.
Here is my code:
public class fetchData extends AsyncTask<Void,Void,Void> {
String data="";
#Override
protected Void doInBackground(Void... voids) {
try {
URL url=new URL("https://app.inyek.com/app_api/api_extra/all_order.php?");
HttpURLConnection con=(HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded/json;charset=UTF-8");
con.setRequestProperty("app_key","whatever");
con.setDoOutput(true);
}
I strongly suggest you make an Abstract HttpRequestTask which extends AsyncTask. In this abstract ancestor you can make some helper methods for reading your input, something like so:
/**
* HttpRequestTask is an abstract extension of an AsyncTask for HTTP Requests.
*
* #param <P>
* Type for parameter(s) to doInBackground (can be Void if none provided)
* #param <R>
* Type for result of request (can be Void if ignored, or using listeners.)
*/
public abstract class HttpRequestTask<P, R> extends AsyncTask<P, Integer, R>
{
private static final String TAG = "HttpRequestTask";
// Post form encoded requests, get back JSON response
private static final RequestMethod DEFAULT_REQUEST_METHOD = RequestMethod.POST;
private static final String DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded;charset=UTF-8;";
private static final String DEFAULT_ACCEPT = "application/json;";
private static final int DEFAULT_TIMEOUT = 8000; // 8 seconds
private static final String CHARSET = "UTF-8";
protected static final String NULL_CONTEXT = "Context is null.";
protected static final String INVALID_RESPONSE = "The server did not send back a valid response.";
// Request methods supported by back-end
protected enum RequestMethod
{
GET("GET"),
POST("POST");
private final String method;
RequestMethod(String method)
{
this.method = method;
}
#Override
public String toString()
{
return this.method;
}
}
/**
* ALWAYS use application context here to prevent memory leaks.
*
*/
protected HttpRequestTask(#NonNull final Context context)
{
this.context = context;
}
protected void verifyConnection() throws IOException
{
if (!SystemUtil.isInternetAvailable(context))
{
throw new IOException("Internet is unavailable.");
}
}
/**
* Creates and opens a URLConnection for the url parameter, as well as setting request options.
*
* #param url
* to connect to.
*
* #return opened HTTPURLConnection for POSTing data to ctservices.
*/
protected HttpURLConnection getURLConnection(URL url) throws IOException
{
return this.getURLConnection(url, DEFAULT_REQUEST_METHOD, DEFAULT_CONTENT_TYPE,
DEFAULT_ACCEPT, DEFAULT_TIMEOUT);
}
/**
* Creates and opens a URLConnection for the url parameter, as well as setting request options.
*
* #param url
* to connect to.
*
* #return opened HTTPURLConnection
*/
protected HttpURLConnection getURLConnection(#NonNull final URL url,
#NonNull final RequestMethod requestMethod,
#NonNull final String contentType,
#Nullable final String accept, final int timeout)
throws IOException
{
verifyConnection();
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod(requestMethod.toString());
urlConnection.setRequestProperty("Content-Type", contentType);
if (accept != null && !accept.isEmpty())
{
urlConnection.setRequestProperty("Accept", accept);
}
urlConnection.setReadTimeout(timeout);
urlConnection.setConnectTimeout(timeout);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
return urlConnection;
}
/**
* Creates and opens a URLConnection for the url parameter, but does not set any request options.
*
* #param url
* to connect to.
*
* #return opened HTTPURLConnection without parameters set.
*/
protected HttpURLConnection getBasicURLConnection(URL url) throws IOException
{
if (!SystemUtil.isInternetAvailable(applicationContext.get()))
{
throw new IOException("Internet is unavailable.");
}
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
return urlConnection;
}
/**
* Write a JSONObject of request parameters to the output stream as form-encoded data.
*
* #param urlConnection
* opened urlConnection with output enabled (done by getURLConnection).
* #param params
* to write to request.
*
* #throws IOException
* problem writing to output stream
*/
protected void writeParams(HttpURLConnection urlConnection, JSONObject params) throws IOException
{
OutputStream outputStream = urlConnection.getOutputStream();
BufferedWriter outWriter = new BufferedWriter(new OutputStreamWriter(outputStream,
StandardCharsets.UTF_8));
String urlParams = this.encodeJSONObject(params);
outWriter.write(urlParams);
outWriter.flush();
outWriter.close();
outputStream.close();
}
/**
* Reads the response of a URLConnection from the input stream and puts it in a string.
*
* #param urlConnection
* opened urlConnection with input enabled (done by getURLConnection).
*
* #return response string
*
* #throws IOException
* problem reading input stream
*/
protected String readResponse(HttpURLConnection urlConnection) throws IOException
{
InputStream inputStream = null;
try
{
/* If we failed to connect will throw a SocketResponseTimeoutException,
* which is an IOException. */
int responseCode = urlConnection.getResponseCode();
if (HttpURLConnection.HTTP_OK != responseCode)
{
throw new IOException("Bad response code - " + responseCode);
}
inputStream = urlConnection.getInputStream();
final String response = parseInputStream(inputStream);
urlConnection.disconnect();
return response;
}
finally
{
if (inputStream != null)
{
try
{
inputStream.close();
}
catch (Exception e) {}
}
}
}
protected Context getContext()
{
return this.context;
}
protected String getString(final int resId)
{
return getContext().getString(resId);
}
/**
* Encodes a JSONObject as a form-data URL string.
*
* #param jo
* to encode
*
* #return encoded URL string
*/
private String encodeJSONObject(JSONObject jo)
{
StringBuilder sb = new StringBuilder();
boolean first = true;
Iterator<String> itr = jo.keys();
String key;
Object val;
try
{
while (itr.hasNext())
{
key = itr.next();
val = jo.get(key);
if (first)
{
first = false;
}
else
{
sb.append('&');
}
sb.append(URLEncoder.encode(key, CHARSET));
sb.append('=');
sb.append(URLEncoder.encode(val.toString(), CHARSET));
}
}
catch (JSONException | UnsupportedEncodingException e) {}
return sb.toString();
}
private String parseInputStream(InputStream is) throws IOException
{
BufferedReader br = null;
try
{
br = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null)
{
sb.append(line);
}
return sb.toString();
}
finally
{
if (br != null)
{
try
{
br.close();
}
catch (Exception e) {}
}
}
}
/**
* Merges any properties of b into a that don't already have a key match in a.
*
* #param a
* merging to
* #param b
* merging from
*
* #return a with any unique values from b
*/
protected JSONObject mergeJSONObjects(JSONObject a, JSONObject b)
{
if (b == null)
{
return a;
}
if (a == null)
{
return b;
}
try
{
Iterator<String> bItr = b.keys();
String key;
while (bItr.hasNext())
{
key = bItr.next();
if (!a.has(key))
{
a.put(key, b.get(key));
}
}
return a;
}
catch (Exception ex)
{
Log.e(TAG, ex.getClass().getSimpleName() + " in mergeJSONObjects: " + ex.getMessage() +
'\n' + Log.getStackTraceString(ex));
return a;
}
}
}
Then you can extend your HttpRequestTask to easily make network requests:
public class ExampleNetworkTask extends HttpRequestTask<Void, Void>
{
private static final String TAG = "ExampleNetworkTask";
private final SimpleListener successListener;
private final StringListener errorListener;
private final String servicesUrl;
public static void start(#NonNull final Context context,
#Nullable final SimpleListener successListener,
#Nullable final StringListener errorListener)
throws IllegalArgumentException
{
if (context == null)
{
throw new IllegalArgumentException(NULL_CONTEXT);
}
new ExampleNetworkTask(context, successListener, errorListener).execute();
}
private ExampleNetworkTask(#NonNull final Context context,
#Nullable final SimpleListener successListener,
#Nullable final StringListener errorListener)
{
super(context);
this.servicesUrl = SystemUtil.getServiceUrl(getContext(), R.string.example_service);
this.successListener = successListener;
this.errorListener = errorListener;
}
#Override
protected Void doInBackground(Void... voids)
{
try
{
final HttpURLConnection urlConnection = super.getURLConnection(new URL(servicesUrl));
final JSONObject params = new JSONObject();
// Add params
params.put("app_key", appKey);
params.put("order_number", orderNumber);
// ...
// Send request, read parse response
super.writeParams(urlConnection, params);
final String response = super.readResponse(urlConnection);
final JSONObject responseObj = new JSONObject(response);
// Handle response
}
catch (Exception ex)
{
final String msg = ex.getLocalizedMessage();
Log.e(TAG, ex.getClass().getSimpleName() + ": " + msg + '\n' +
Log.getStackTraceString(ex));
// Handle network exceptions and other exceptions here.
}
return null;
}
}
In PostMan, how did you specify the app key? was it through an HTTP header?
(Sorry, I would have added a comment, but I do not have enough reputation)
Or was it specified as a GET parameter?
In the latter case, try something like:
URL url=new URL("https://app.inyek.com/app_api/api_extra/all_order.php?app_key=YOUR_KEY");
Welcome to Stack Exchange! Firstly I'd suggest you don't put your API Key within questions and/or images, as they might be sensitive and can be abused by malicious users. Feel free to edit your question and remove them.
To answer your query, I think you need to write the contents to the http request body in a json format. This can be done as per the guide on the following webpage:
https://www.baeldung.com/httpurlconnection-post
In summary, you need to create an output stream and write the contents to it directly.
Thank you guys! finally i got the answer using OkHttpClient. here is the code:
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "app_key=whatever");
Request request = new Request.Builder()
.url("https://app.inyek.com/app_api/api_extra/all_order.php")
.post(body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("key", "whatever")
.addHeader("cache-control", "no-cache")
.addHeader("Postman-Token", "whatever")
.build();
Response response = client.newCall(request).execute();

Iphone emoji Unicode decode issue for push notification dispatch by APNs

My web service publish push notification to APNs and APNs send to destination IOS device.
When apns contain Unicode emoji on alert body push notification and Iphone os can't decode my Unicode emoji '\uD83D\uDE0A' app already kill.
Push notification show same '\uD83D\uDE0A', No emoji shown on banner notification bar on top.
Android application works fine by GCM dispatches push notification But IOS not support.
Iphone-Ios supports only this format '\ue415'
Here code that from ActiveMQ subscribe chat payload get into web-service
public void onPublish(UTF8Buffer topic, Buffer msg, Runnable ack) {
try {
String body = msg.utf8().toString();
if (logger.isInfoEnabled()) {
logger.info("MQTT connection.listener.onPublish(), msg Received ["
+ body + "]");
}
if (body.contains("\"cmd\":\"chat\"")
&& body.contains("\"is_sender_msg\":true")) {
QueueMgr.addToChatQueue(body); //Changed true to false
}
else if(body.contains("\"cmd\":\"msg_seen\"")){
QueueMgr.addToChatReadSeenQueue(body);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
ack.run();
}
}
My code for create push notification on java
public static JSONObject constructePushJson(JSONObject jsonObject,String[] cloudkeyWithDevice) throws JSONException {
if(cloudkeyWithDevice[0] != null){
JSONObject pnAPIdata = new JSONObject();
if(cloudkeyWithDevice[1].equals("a") || cloudkeyWithDevice[1].equals("d")){
pnAPIdata.put(com.anyorg.constants.AppConstants.FLD_CMD, com.anyorg.constants.AppConstants.CMD_ANDROID_PUSH);
}
else{
pnAPIdata.put(com.anyorg.constants.AppConstants.FLD_CMD, com.anyorg.constants.AppConstants.CMD_IOS_PUSH);
}
pnAPIdata.put(com.anyorg.constants.AppConstants.FLD_APP_TOKEN, com.anyorg.constants.AppConstants.DEFAULT_APP_TOKEN);
pnAPIdata.put(com.anyorg.constants.AppConstants.FLD_DEVICE_TOKEN, cloudkeyWithDevice[0]);
pnAPIdata.put(com.anyorg.constants.AppConstants.FLD_USER_ID, jsonObject.getInt(com.anyorg.constants.AppConstants.FLD_TO_USER_ID));
pnAPIdata.put(com.anyorg.constants.AppConstants.FLD_DEVICE_ID, 0);
String alertMsg=StringEscapeUtils.unescapeJava(jsonObject.getString(com.anyorg.constants.AppConstants.FLD_BODY));
jsonObject.put(com.anyorg.constants.AppConstants.FLD_BODY,alertMsg);
pnAPIdata.put(com.anyorg.constants.AppConstants.FLD_ALERT_MSG, "AryaConnect: "+alertMsg);//(jsonObject.isNull("body")) ? jsonObject.getString("from_user_name")+": Sent a file" : jsonObject.getString("from_user_name")+": "+jsonObject.getString("body")
pnAPIdata.put(com.anyorg.constants.AppConstants.FLD_MSG, jsonObject);//jsonObject.getString(com.anyorg.constants.AppConstants.FLD_BODY)
pnAPIdata.put(com.anyorg.constants.AppConstants.FLD_CALLBACK_URL, callbackUrl);
pnAPIdata.put(com.anyorg.constants.AppConstants.MAC_ADDRESS_ID, jsonObject.getString("mobile_rec_id"));
return pnAPIdata;
}
else{
return null;
}
}
Publish to APNs code
public class ANSNotificationDispatcher implements NotificationDispatcher {
protected static final Logger logger = Logger
.getLogger(ANSNotificationDispatcher.class);
public static final String OS_NAME = AppConstants.OS_TYPE_IPHONE;
String keystore;
String password;
boolean production;
public ANSNotificationDispatcher() {
try {
keystore = AppConfig.getAPNKeystore();
password = AppConfig.getAPNKeystorePassword();
PushyAPNMgr.init(keystore, password, AppConfig.isAPNProdcution());
} catch (Throwable e) {
e.printStackTrace();
}
}
private void push(Payload payload, String token, String userId,
String deviceId) throws ConfigurationException,
DeviceUnregisteredException {
// QueueManager.addToIOsQueue(payLoad, token, userId, ivUserDeviceId);
long stime = System.currentTimeMillis();
try {
PushyAPNMgr.push(token, payload.toString());
if (logger.isInfoEnabled())
logger.info("push(): APN PN userId [" + userId
+ "], device id [" + deviceId + "] payoad [" + payload
+ "] Response time ["
+ (System.currentTimeMillis() - stime) + "]ms");
} catch (Exception e) {
e.printStackTrace();
throw new ConfigurationException();
}
}
public static Payload createComplexPayload(JSONObject jsonObject) {
PushNotificationPayload complexPayload = null;
try {
complexPayload = createPayload(jsonObject);
String msg = Common.getStringAsNull(jsonObject,
AppConstants.FLD_MSG);
if (!Common.isEmpty(msg)) {
complexPayload.addCustomDictionary(AppConstants.FLD_MSG, msg);
}
if (logger.isInfoEnabled()) {
logger.info("createComplexPayloadV2(): payload ["
+ complexPayload.getPayload().toString() + "]");
}
} catch (JSONException e) {
e.printStackTrace();
}
return complexPayload;
}
public void dispatch(JSONObject jsonObject, String jsonData)
throws NotificationException, DeviceUnregisteredException,
MultipleRegistartionIdException, ConfigurationException {
String deviceToken = Common.getStringAsNull(jsonObject,
AppConstants.FLD_DEVICE_TOKEN);
if (Common.isEmpty(deviceToken)) {
logger.error("dispatch(): device token is null, cmd [" + jsonData
+ "]");
return;
}
Payload payload = createComplexPayload(jsonObject);
String userId = Common.getStringAsNull(jsonObject,
AppConstants.FLD_USER_ID);
String deviceId = Common.getStringAsNull(jsonObject,
AppConstants.FLD_DEVICE_ID);
push(payload, deviceToken, userId, deviceId);
}
public static void handleInvalidTokeException(String token) {
}
public static void handleDeviceUnregisteredException(String token) {
}
}
Ios push notification managed by Ios OS
My Apache Catalina log
I am a web service cloud developer faceing this issue last one days for only Ios app. So please, if some body have knowledge or done before. please advise and refer me some idea.
Emoji in my push notifications link.
https://mixpanel.com/help/questions/articles/how-do-i-send-custom-parameters-like-emoji-in-my-push-notifications
Thanks
Finally, APNs issue resolve in (Ios app) on java web service code by this Unicode encode and decode process. (unescapeJava and escapeJava) from lib commons-lang-2.6.jar and class org.apache.commons.lang.StringEscapeUtils
emojiBytes = alertMsg.getBytes("UTF-8"); text = new String(emojiBytes, "UTF-8");
private static PushNotificationPayload createPayload(JSONObject jsonObject)
throws JSONException {
String alertMsg = Common.getStringUnicodeAsNull1(jsonObject,
AppConstants.FLD_ALERT_MSG);
byte[] emojiBytes=null;
String text=null;
try {
emojiBytes = alertMsg.getBytes("UTF-8");
text = new String(emojiBytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//String emojiAsString = new String(emojiBytes, Charset.forName("UTF-8"));
//System.out.println("#####alertMsg: "+text);
Integer badgeCnt;
if (jsonObject.has(AppConstants.FLD_BADGE_CNT)){
badgeCnt = Common.getIntegerAsNull(jsonObject,
AppConstants.FLD_BADGE_CNT);
}else{
badgeCnt = AppConstants.VAL_ZERO;
}
PushNotificationPayload payload = createPayload(badgeCnt, text);
return payload;
}
String alertMsg = Common.getStringUnicodeAsNull1(jsonObject,
AppConstants.FLD_ALERT_MSG);
public static String getStringUnicodeAsNull1(JSONObject jsonObject,
String key) {
try {
if(jsonObject.isNull(key))
return null;
else
return StringEscapeUtils.unescapeJava(jsonObject.getString(key));
} catch (JSONException je) {
return null;
}
}
Respected sir and ma'am, If there is any other solution of java APNs emoji Unicode on IOS Push Notification.
Then please give me some hints.Thanks
you shouldn't need to mess about with html decoding. As you say the code point for smiling face is \u263A. In PHP you can represent that in a UTF8-encoded string as "\xE2\x98\xBA"
Lightning bolt (actually 'high voltage sign') is \u26A1 or "\xE2\x9A\xA1" in UTF-8.
Both these characters are present in some non-emoji fonts as regular Unicode symbols. You can see with:
<?php
header('Content-type: text/html; charset=utf-8');
echo "\xE2\x9A\xA1";
echo "\xE2\x98\xBA";
or other things...
for the googlers. json_encode() adds double \
$message = "\ue04a";
$body['aps'] = array(
'alert' => $message,
'sound' => 'default',
'type' => $type,
'param' => $param
);
$payload = json_encode($body);
$payload = str_replace("\", "\\", $payload);
Please check with this two way... i think this is helpfull for you.

Microsoft Cognitive Speech Service - Android

I am using Microsoft Cognitive Services - Speech Recognition on an Android application. Everything works fine when the code is in my main activity, but when I want to move the part corresponding to speech recognition to a new class, it throws an error.
Here are the code samples:
In the main activity
int m_waitSeconds = 0;
MicrophoneRecognitionClient micClient = null;
FinalResponseStatus isReceivedResponse = FinalResponseStatus.NotReceived;
Boolean speechIntent = false;
SpeechRecognitionMode speechMode = SpeechRecognitionMode.ShortPhrase;
public enum FinalResponseStatus { NotReceived, OK }
/**
* Gets the primary subscription key
*/
public String getPrimaryKey() {
return this.getString(R.string.primaryKey);
}
/**
* Gets the secondary subscription key
*/
public String getSecondaryKey() {
return this.getString(R.string.secondaryKey);
}
/**
* Gets the LUIS application identifier.
* #return The LUIS application identifier.
*/
private String getLuisAppId() {
return this.getString(R.string.luisAppID);
}
/**
* Gets the LUIS subscription identifier.
* #return The LUIS subscription identifier.
*/
private String getLuisSubscriptionID() {
return this.getString(R.string.luisSubscriptionID);
}
/**
* Gets the default locale.
* #return The default locale.
*/
private String getDefaultLocale() {
return "en-us";
}
/**
* Handles the Click event of the _startButton control.
*/
private void StartButton_Click(View v) {
this.m_waitSeconds = this.speechMode == SpeechRecognitionMode.ShortPhrase ? 20 : 200;
if (this.micClient == null) {
if (this.speechIntent) {
this.WriteLine("--- Start microphone dictation with Intent detection ----");
this.micClient = SpeechRecognitionServiceFactory.createMicrophoneClientWithIntent(
this,
this.getDefaultLocale(),
this,
this.getPrimaryKey(),
this.getSecondaryKey(),
this.getLuisAppId(),
this.getLuisSubscriptionID());
}
else
{
this.micClient = SpeechRecognitionServiceFactory.createMicrophoneClient(
this,
this.speechMode,
this.getDefaultLocale(),
this,
this.getPrimaryKey(),
this.getSecondaryKey());
}
}
this.micClient.startMicAndRecognition();
}
public void onFinalResponseReceived(final RecognitionResult response) {
boolean isFinalDicationMessage = this.speechMode == SpeechRecognitionMode.LongDictation &&
(response.RecognitionStatus == RecognitionStatus.EndOfDictation ||
response.RecognitionStatus == RecognitionStatus.DictationEndSilenceTimeout);
if (null != this.micClient && ((this.speechMode == SpeechRecognitionMode.ShortPhrase) || isFinalDicationMessage)) {
// we got the final result, so it we can end the mic reco. No need to do this
// for dataReco, since we already called endAudio() on it as soon as we were done
// sending all the data.
this.micClient.endMicAndRecognition();
}
if (isFinalDicationMessage) {
this.isReceivedResponse = FinalResponseStatus.OK;
}
Confidence cMax = Confidence.Low;
int iMax = 0;
if (!isFinalDicationMessage && response.Results.length != 0) {
for (int i = 0; i < response.Results.length; i++) {
//get the text with highest confidence:
if(response.Results[i].Confidence.getValue() > cMax.getValue()){
cMax = response.Results[i].Confidence;
iMax = i;
}
}
this.WriteLine(response.Results[iMax].DisplayText);
}
}
/**
* Called when a final response is received and its intent is parsed
*/
public void onIntentReceived(final String payload) {
this.WriteLine("--- Intent received by onIntentReceived() ---");
this.WriteLine(payload);
this.WriteLine();
}
public void onPartialResponseReceived(final String response) {
this.WriteLine("--- Partial result received by onPartialResponseReceived() ---");
this.WriteLine(response);
this.WriteLine();
}
public void onError(final int errorCode, final String response) {
this.WriteLine("--- Error received by onError() ---");
this.WriteLine("Error code: " + SpeechClientStatus.fromInt(errorCode) + " " + errorCode);
this.WriteLine("Error text: " + response);
this.WriteLine();
}
/**
* Called when the microphone status has changed.
* #param recording The current recording state
*/
public void onAudioEvent(boolean recording) {
if (!recording) {
this.micClient.endMicAndRecognition();
}
}
/**
* Writes the line.
*/
private void WriteLine() {
this.WriteLine("");
}
/**
* Writes the line.
* #param text The line to write.
*/
private void WriteLine(String text) {
System.out.println(text);
}
In a separate class
public class SpeechRecognition implements ISpeechRecognitionServerEvents
{
int m_waitSeconds = 0;
private MicrophoneRecognitionClient micClient = null;
private FinalResponseStatus isReceivedResponse =FinalResponseStatus.NotReceived;
private Boolean speechIntent = false;
private SpeechRecognitionMode speechMode=SpeechRecognitionMode.ShortPhrase;
public enum FinalResponseStatus { NotReceived, OK }
/**
* Gets the primary subscription key
*/
public String getPrimaryKey() {
return Integer.toString(R.string.primaryKey);
}
/**
* Gets the secondary subscription key
*/
public String getSecondaryKey() {
return Integer.toString(R.string.secondaryKey);
}
/**
* Gets the LUIS application identifier.
* #return The LUIS application identifier.
*/
private String getLuisAppId() {
return Integer.toString(R.string.luisAppID);
}
/**
* Gets the LUIS subscription identifier.
* #return The LUIS subscription identifier.
*/
private String getLuisSubscriptionID() {
return Integer.toString(R.string.luisSubscriptionID);
}
/**
* Gets the default locale.
* #return The default locale.
*/
private String getDefaultLocale() {
return "en-us";
}
public void startSpeechRecognition() {
this.m_waitSeconds = this.speechMode == SpeechRecognitionMode.ShortPhrase ? 20 : 200;
if (this.micClient == null) {
if (this.speechIntent) {
this.micClient = SpeechRecognitionServiceFactory.createMicrophoneClientWithIntent(
this.getDefaultLocale(),
this,
this.getPrimaryKey(),
this.getSecondaryKey(),
this.getLuisAppId(),
this.getLuisSubscriptionID());
}
else
{
this.micClient = SpeechRecognitionServiceFactory.createMicrophoneClient(
this.speechMode,
this.getDefaultLocale(),
this,
this.getPrimaryKey(),
this.getSecondaryKey());
}
}
this.micClient.startMicAndRecognition();
}
public void endSpeechRecognition(){
this.micClient.endMicAndRecognition();
}
public void onFinalResponseReceived(final RecognitionResult response) {
boolean isFinalDicationMessage = this.speechMode == SpeechRecognitionMode.LongDictation &&
(response.RecognitionStatus == RecognitionStatus.EndOfDictation ||
response.RecognitionStatus == RecognitionStatus.DictationEndSilenceTimeout);
if (null != this.micClient && ((this.speechMode == SpeechRecognitionMode.ShortPhrase) || isFinalDicationMessage)) {
// we got the final result, so it we can end the mic reco. No need to do this
// for dataReco, since we already called endAudio() on it as soon as we were done
// sending all the data.
this.micClient.endMicAndRecognition();
}
if (isFinalDicationMessage) {
this.isReceivedResponse = FinalResponseStatus.OK;
}
Confidence cMax = Confidence.Low;
int iMax = 0;
if (!isFinalDicationMessage && response.Results.length != 0) {
for (int i = 0; i < response.Results.length; i++) {
//get the text with highest confidence:
if(response.Results[i].Confidence.getValue() > cMax.getValue()){
cMax = response.Results[i].Confidence;
iMax = i;
}
}
System.out.println("Action to take: " + response.Results[iMax].DisplayText);
}
}
/**
* Called when a final response is received and its intent is parsed
*/
public void onIntentReceived(final String payload) {
System.out.println("--- Intent received by onIntentReceived() ---");
System.out.println(payload);
}
public void onPartialResponseReceived(final String response) {
System.out.println("--- Partial result received by onPartialResponseReceived() ---");
System.out.println(response);
}
public void onError(final int errorCode, final String response) {
System.err.println("--- Error received by onError() ---");
System.err.println("Error code: " + SpeechClientStatus.fromInt(errorCode) + " " + errorCode);
System.err.println("Error text: " + response);
}
/**
* Called when the microphone status has changed.
* #param recording The current recording state
*/
public void onAudioEvent(boolean recording) {
System.out.println("--- Microphone status change received by onAudioEvent() ---");
System.out.println("********* Microphone status: " + recording + " *********");
if (recording) {
System.out.println("Please start speaking.");
}
if (!recording) {
this.micClient.endMicAndRecognition();
}
}
}
You can clearly see that it is basically the same code but it gives me this error in the onError function after i call this.micClient.startMicAndRecognition();
:
Error code: LoginFailed -1910505470
I solved the problem.
I was getting a wrong Primary key in this line of code:
public String getPrimaryKey() {
return Integer.toString(R.string.primaryKey);
}
It is because the primary key is too long to be read by the processor as an integer then transformed to a String. I had to get the primary key from the main activity via getString(R.string.primaryKey) then pass it as a parameter to the constructor of the SpeechRecognition class.

Neither getting downstream message nor getting echo message using CCS

I downloaded the code from the below link for android which has option to send echo, broadcast as well as user notification message.
Link for Android
Then I tried to use many codes for server side without any success so I studied and wrote the below code for the server side which I have hosted on Tomcat Server and there is a servlet which activates the client.
public class CcsServlet extends HttpServlet
{
private static Logger logger = Logger.getLogger(CcsServlet.class.getName());
private static final String USERNAME = "855350893195" + "#gcm.googleapis.com";
private static final String PASSWORD = "AIzaSyA9DQTcggUtABVC9lnV_Xb5VEQ8iKBEaP4";//AIzaSyAxDKiYUkU8EvtOgaCeZMypVJpzcYgyjhw-server
public void init(ServletConfig config) throws ServletException
{
SmackCcsClient ccsManager = SmackCcsClient.getInstance();
try
{
ccsManager.connect(USERNAME,PASSWORD);
}
catch (Exception e)
{
logger.warning("Cannot connect to CCS server.");
e.printStackTrace();
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException{
}
}
Code for the SmackCcsClient
public class SmackCcsClient {
private static Logger log = LoggerFactory.getLogger(SmackCcsClient.class);
private static SmackCcsClient sInstance = null;
XMPPConnection connection;
ConnectionConfiguration config;
public SmackCcsClient() {
// Add GcmPacketExtension
ProviderManager.getInstance().addExtensionProvider(
GCMConstants.GCM_ELEMENT_NAME,
GCMConstants.GCM_NAMESPACE,
new PacketExtensionProvider() {
#Override
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
String json = parser.nextText();
GcmPacketExtension packet = new GcmPacketExtension(json);
return packet;
}
});
}
/**
* Returns a random message id to uniquely identify a message.
*
*/
public String getRandomMessageId() {
return UUID.randomUUID().toString();
}
/**
* Sends a downstream GCM message.
*/
public void send(String jsonRequest) {
Packet request = new GcmPacketExtension(jsonRequest).toPacket();
connection.sendPacket(request);
}
public static SmackCcsClient getInstance()
{
if (sInstance == null)
sInstance = new SmackCcsClient();
return sInstance;
}
/**
* Handles an upstream data message from a device application.
*
* <p>
* This sample echo server sends an echo message back to the device.
* Subclasses should override this method to process an upstream message.
*/
public void handleIncomingDataMessage(Map<String, Object> jsonObject) {
String from = jsonObject.get("from").toString();
// PackageName of the application that sent this message.
String category = jsonObject.get("category").toString();
// Use the packageName as the collapseKey in the echo packet
String collapseKey = "echo:CollapseKey";
#SuppressWarnings("unchecked")
Map<String, String> payload = (Map<String, String>) jsonObject.get("data");
payload.put("ECHO", "Application: " + category);
// Send an ECHO response back
String echo = createJsonMessage(from, getRandomMessageId(), payload, collapseKey, null, false);
send(echo);
}
/**
* Handles an ACK.
*
* <p>
* By default, it only logs a INFO message, but subclasses could override it
* to properly handle ACKS.
*/
public void handleAckReceipt(Map<String, Object> jsonObject) {
String messageId = jsonObject.get("message_id").toString();
String from = jsonObject.get("from").toString();
log.debug("handleAckReceipt from: {}, messageId: {}", from, messageId);
}
/**
* Handles a NACK.
*
* <p>
* By default, it only logs a INFO message, but subclasses could override it
* to properly handle NACKS.
*/
public void handleNackReceipt(Map<String, Object> jsonObject) {
String messageId = jsonObject.get("message_id").toString();
String from = jsonObject.get("from").toString();
log.debug("handleNackReceipt() from: {}, messageId: {}",from, messageId);
}
/**
* Creates a JSON encoded GCM message.
*
* #param to
* RegistrationId of the target device (Required).
* #param messageId
* Unique messageId for which CCS will send an "ack/nack"
* (Required).
* #param payload
* Message content intended for the application. (Optional).
* #param collapseKey
* GCM collapse_key parameter (Optional).
* #param timeToLive
* GCM time_to_live parameter (Optional).
* #param delayWhileIdle
* GCM delay_while_idle parameter (Optional).
* #return JSON encoded GCM message.
*/
public static String createJsonMessage(String to, String messageId,
Map<String, String> payload, String collapseKey, Long timeToLive,
Boolean delayWhileIdle) {
Map<String, Object> message = new HashMap<String, Object>();
message.put("to", to);
if (collapseKey != null) {
message.put("collapse_key", collapseKey);
}
if (timeToLive != null) {
message.put("time_to_live", timeToLive);
}
if (delayWhileIdle != null && delayWhileIdle) {
message.put("delay_while_idle", true);
}
message.put("message_id", messageId);
message.put("data", payload);
return JSONValue.toJSONString(message);
}
/**
* Creates a JSON encoded ACK message for an upstream message received from
* an application.
*
* #param to
* RegistrationId of the device who sent the upstream message.
* #param messageId
* messageId of the upstream message to be acknowledged to CCS.
* #return JSON encoded ack.
*/
public static String createJsonAck(String to, String messageId) {
Map<String, Object> message = new HashMap<String, Object>();
message.put("message_type", "ack");
message.put("to", to);
message.put("message_id", messageId);
return JSONValue.toJSONString(message);
}
/**
* Connects to GCM Cloud Connection Server using the supplied credentials.
*
* #param username
* GCM_SENDER_ID#gcm.googleapis.com
* #param password
* API Key
* #throws XMPPException
*/
public void connect(String username, String password) throws XMPPException {
config = new ConnectionConfiguration(GCMConstants.GCM_SERVER, GCMConstants.GCM_PORT);
config.setSecurityMode(SecurityMode.enabled);
config.setReconnectionAllowed(true);
config.setRosterLoadedAtLogin(false);
config.setSendPresence(false);
config.setSocketFactory(SSLSocketFactory.getDefault());
// NOTE: Set to true to launch a window with information about packets
// sent and received
config.setDebuggerEnabled(true);
// -Dsmack.debugEnabled=true
XMPPConnection.DEBUG_ENABLED = true;
connection = new XMPPConnection(config);
connection.connect();
//**code used to send downstream message**
String toRegId = "APA91bECAx_1rzceJbPwas5FyRGPmpYFvWSJ0hfUlT30DSsrsXmBC5W-VmYTI0p8Gg9VZh598iNBcVki-H1dloBnaETfvZlJUZskTxHKE7DoDAgapH_X_DJE3toyZwXS4SHIdt5lYLty6OU_tmAOTZN4n88jlmSaR2_MrNmY1HuAMlddMfqAr10";
String messageId = sInstance.getRandomMessageId();
Map<String, String> payload = new HashMap<String, String>();
payload.put("Hello", "World");
payload.put("CCS", "Dummy Message");
payload.put("EmbeddedMessageId", messageId);
String collapseKey = "sample";
Long timeToLive = 10000L;
Boolean delayWhileIdle = true;
sInstance.send(createJsonMessage(toRegId, messageId, payload,
collapseKey, timeToLive, delayWhileIdle));
connection.addConnectionListener(new ConnectionListener() {
#Override
public void reconnectionSuccessful() {
log.info("Reconnecting..");
}
#Override
public void reconnectionFailed(Exception e) {
log.info( "Reconnection failed.. ", e);
}
#Override
public void reconnectingIn(int seconds) {
log.info( "Reconnecting in %d secs", seconds);
}
#Override
public void connectionClosedOnError(Exception e) {
log.info( "Connection closed on error.");
}
#Override
public void connectionClosed() {
log.info("Connection closed.");
}
});
// Handle incoming packets
connection.addPacketListener(new PacketListener() {
#Override
public void processPacket(Packet packet) {
log.info( "Received: " + packet.toXML());
Message incomingMessage = (Message) packet;
GcmPacketExtension gcmPacket = (GcmPacketExtension) incomingMessage.getExtension(GCMConstants.GCM_NAMESPACE);
String json = gcmPacket.getJson();
try {
#SuppressWarnings("unchecked")
Map<String, Object> jsonObject = (Map<String, Object>) JSONValue
.parseWithException(json);
// present for "ack"/"nack", null otherwise
Object messageType = jsonObject.get("message_type");
if (messageType == null) {
// Normal upstream data message
handleIncomingDataMessage(jsonObject);
// Send ACK to CCS
String messageId = jsonObject.get("message_id")
.toString();
String from = jsonObject.get("from").toString();
String ack = createJsonAck(from, messageId);
send(ack);
} else if ("ack".equals(messageType.toString())) {
// Process Ack
handleAckReceipt(jsonObject);
} else if ("nack".equals(messageType.toString())) {
// Process Nack
handleNackReceipt(jsonObject);
} else {
// logger.log(Level.WARNING,
// "Unrecognized message type (%s)",
messageType.toString();
}
} catch (Exception e) {
// logger.log(Level.SEVERE, "Couldn't send echo.", e);
}
}
}, new PacketTypeFilter(Message.class));
// Log all outgoing packets
connection.addPacketWriterInterceptor(new PacketInterceptor() {
#Override
public void interceptPacket(Packet packet) {
log.info( "Sent: {0}", packet.toXML());
}
}, new PacketTypeFilter(Message.class));
connection.login(username, password);
}
}
Code for GcmPacketExtension
class GcmPacketExtension extends DefaultPacketExtension {
String json;
public GcmPacketExtension(String json) {
super(GCMConstants.GCM_ELEMENT_NAME, GCMConstants.GCM_NAMESPACE);
this.json = json;
}
public String getJson() {
return json;
}
#Override
public String toXML() {
return String.format("<%s xmlns=\"%s\">%s</%s>", GCMConstants.GCM_ELEMENT_NAME,
GCMConstants.GCM_NAMESPACE, json, GCMConstants.GCM_ELEMENT_NAME);
}
#SuppressWarnings("unused")
public Packet toPacket() {
return new Message() {
// Must override toXML() because it includes a <body>
#Override
public String toXML() {
StringBuilder buf = new StringBuilder();
buf.append("<message");
if (getXmlns() != null) {
buf.append(" xmlns=\"").append(getXmlns()).append("\"");
}
if (getDefaultLanguage() != null) {
buf.append(" xml:lang=\"").append(getDefaultLanguage())
.append("\"");
}
if (getPacketID() != null) {
buf.append(" id=\"").append(getPacketID()).append("\"");
}
if (getTo() != null) {
buf.append(" to=\"")
.append(StringUtils.escapeForXML(getTo()))
.append("\"");
}
if (getFrom() != null) {
buf.append(" from=\"")
.append(StringUtils.escapeForXML(getFrom()))
.append("\"");
}
buf.append(">");
buf.append(GcmPacketExtension.this.toXML());
buf.append("</message>");
return buf.toString();
}
};
}
}
Code for GcmConstants
public class GCMConstants {
public static final String GCM_SERVER = "gcm.googleapis.com";
public static final int GCM_PORT = 5235;
public static final String GCM_ELEMENT_NAME = "gcm";
public static final String GCM_NAMESPACE = "google:mobile:data";
}
Now when I try to send a downstream message using the code in connect that does not reach the device which device id I have given or Echo message from device also does not echoed by server.
Is it required to sign up thing for CCS required because I have already signed up, however did not get any response.
Second question is why neither of the communication is working.
Now I have cleared up all the issues and now my servlet is running and making a connection however it is returning "No Response from the server", which I am getting as exception while connecting.

Categories