I am working on a project to build a group chat app on socket server!
but when I start the server it get started and displays the following error:
HTTP Status 404- /GroupChat/
type Status report
message /GroupChat/
description The requested resource is not available.
I am using a J2EE eclipse where I have added a tomcat 7 server.
Below are my two files:
JSONUtils.java
package com.groupchat;
import org.json.JSONException;
import org.json.JSONObject;
public class JSONUtils {
// flags to identify the kind of json response on client side
private static final String FLAG_SELF = "self", FLAG_NEW = "new",
FLAG_MESSAGE = "message", FLAG_EXIT = "exit";
public JSONUtils() {
}
/**
* Json when client needs it's own session details
* */
public String getClientDetailsJson(String sessionId, String message) {
String json = null;
try {
JSONObject jObj = new JSONObject();
jObj.put("flag", FLAG_SELF);
jObj.put("sessionId", sessionId);
jObj.put("message", message);
json = jObj.toString();
} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
/**
* Json to notify all the clients about new person joined
* */
public String getNewClientJson(String sessionId, String name,
String message, int onlineCount) {
String json = null;
try {
JSONObject jObj = new JSONObject();
jObj.put("flag", FLAG_NEW);
jObj.put("name", name);
jObj.put("sessionId", sessionId);
jObj.put("message", message);
jObj.put("onlineCount", onlineCount);
json = jObj.toString();
} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
/**
* Json when the client exits the socket connection
* */
public String getClientExitJson(String sessionId, String name,
String message, int onlineCount) {
String json = null;
try {
JSONObject jObj = new JSONObject();
jObj.put("flag", FLAG_EXIT);
jObj.put("name", name);
jObj.put("sessionId", sessionId);
jObj.put("message", message);
jObj.put("onlineCount", onlineCount);
json = jObj.toString();
} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
/**
* JSON when message needs to be sent to all the clients
* */
public String getSendAllMessageJson(String sessionId, String fromName,
String message) {
String json = null;
try {
JSONObject jObj = new JSONObject();
jObj.put("flag", FLAG_MESSAGE);
jObj.put("sessionId", sessionId);
jObj.put("name", fromName);
jObj.put("message", message);
json = jObj.toString();
} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
}
SocketServer.java
#ServerEndpoint("/chat")
public class SocketServer {
// set to store all the live sessions
private static final Set<Session> sessions = Collections
.synchronizedSet(new HashSet<Session>());
// Mapping between session and person name
private static final HashMap<String, String> nameSessionPair = new HashMap<String, String>();
private JSONUtils jsonUtils = new JSONUtils();
// Getting query params
public static Map<String, String> getQueryMap(String query) {
Map<String, String> map = Maps.newHashMap();
if (query != null) {
String[] params = query.split("&");
for (String param : params) {
String[] nameval = param.split("=");
map.put(nameval[0], nameval[1]);
}
}
return map;
}
/**
* Called when a socket connection opened
* */
#OnOpen
public void onOpen(Session session) {
System.out.println(session.getId() + " has opened a connection");
Map<String, String> queryParams = getQueryMap(session.getQueryString());
String name = "";
if (queryParams.containsKey("name")) {
// Getting client name via query param
name = queryParams.get("name");
try {
name = URLDecoder.decode(name, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// Mapping client name and session id
nameSessionPair.put(session.getId(), name);
}
// Adding session to session list
sessions.add(session);
try {
// Sending session id to the client that just connected
session.getBasicRemote().sendText(
jsonUtils.getClientDetailsJson(session.getId(),
"Your session details"));
} catch (IOException e) {
e.printStackTrace();
}
// Notifying all the clients about new person joined
sendMessageToAll(session.getId(), name, " joined conversation!", true, false);
}
/**
* method called when new message received from any client
*
* #param message
* JSON message from client
* */
#OnMessage
public void onMessage(String message, Session session) {
System.out.println("Message from " + session.getId() + ": " + message);
String msg = null;
// Parsing the json and getting message
try {
JSONObject jObj = new JSONObject(message);
msg = jObj.getString("message");
} catch (JSONException e) {
e.printStackTrace();
}
// Sending the message to all clients
sendMessageToAll(session.getId(), nameSessionPair.get(session.getId()),
msg, false, false);
}
/**
* Method called when a connection is closed
* */
#OnClose
public void onClose(Session session) {
System.out.println("Session " + session.getId() + " has ended");
// Getting the client name that exited
String name = nameSessionPair.get(session.getId());
// removing the session from sessions list
sessions.remove(session);
// Notifying all the clients about person exit
sendMessageToAll(session.getId(), name, " left conversation!", false, true);
}
/**
* Method to send message to all clients
*
* #param sessionId
* #param message
* message to be sent to clients
* #param isNewClient
* flag to identify that message is about new person joined
* #param isExit
* flag to identify that a person left the conversation
* */
private void sendMessageToAll(String sessionId, String name,
String message, boolean isNewClient, boolean isExit) {
// Looping through all the sessions and sending the message individually
for (Session s : sessions) {
String json = null;
// Checking if the message is about new client joined
if (isNewClient) {
json = jsonUtils.getNewClientJson(sessionId, name, message,
sessions.size());
} else if (isExit) {
// Checking if the person left the conversation
json = jsonUtils.getClientExitJson(sessionId, name, message, sessions.size());
} else {
// Normal chat conversation message
json = jsonUtils
.getSendAllMessageJson(sessionId, name, message);
}
try {
System.out.println("Sending Message To: " + sessionId + ", " + json);
s.getBasicRemote().sendText(json);
} catch (IOException e) {
System.out.println("error in sending. " + s.getId() + ", "
+ e.getMessage());
e.printStackTrace();
}
}
}
}
main.js
#ServerEndpoint("/chat")
public class SocketServer {
// set to store all the live sessions
private static final Set<Session> sessions = Collections
.synchronizedSet(new HashSet<Session>());
// Mapping between session and person name
private static final HashMap<String, String> nameSessionPair = new HashMap<String, String>();
private JSONUtils jsonUtils = new JSONUtils();
// Getting query params
public static Map<String, String> getQueryMap(String query) {
Map<String, String> map = Maps.newHashMap();
if (query != null) {
String[] params = query.split("&");
for (String param : params) {
String[] nameval = param.split("=");
map.put(nameval[0], nameval[1]);
}
}
return map;
}
/**
* Called when a socket connection opened
* */
#OnOpen
public void onOpen(Session session) {
System.out.println(session.getId() + " has opened a connection");
Map<String, String> queryParams = getQueryMap(session.getQueryString());
String name = "";
if (queryParams.containsKey("name")) {
// Getting client name via query param
name = queryParams.get("name");
try {
name = URLDecoder.decode(name, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// Mapping client name and session id
nameSessionPair.put(session.getId(), name);
}
// Adding session to session list
sessions.add(session);
try {
// Sending session id to the client that just connected
session.getBasicRemote().sendText(
jsonUtils.getClientDetailsJson(session.getId(),
"Your session details"));
} catch (IOException e) {
e.printStackTrace();
}
// Notifying all the clients about new person joined
sendMessageToAll(session.getId(), name, " joined conversation!", true, false);
}
/**
* method called when new message received from any client
*
* #param message
* JSON message from client
* */
#OnMessage
public void onMessage(String message, Session session) {
System.out.println("Message from " + session.getId() + ": " + message);
String msg = null;
// Parsing the json and getting message
try {
JSONObject jObj = new JSONObject(message);
msg = jObj.getString("message");
} catch (JSONException e) {
e.printStackTrace();
}
// Sending the message to all clients
sendMessageToAll(session.getId(), nameSessionPair.get(session.getId()), msg, false, false);
}
/**
* Method called when a connection is closed
* */
#OnClose
public void onClose(Session session) {
System.out.println("Session " + session.getId() + " has ended");
// Getting the client name that exited
String name = nameSessionPair.get(session.getId());
// removing the session from sessions list
sessions.remove(session);
// Notifying all the clients about person exit
sendMessageToAll(session.getId(), name, " left conversation!", false, true);
}
/**
* Method to send message to all clients
*
* #param sessionId
* #param message
* message to be sent to clients
* #param isNewClient
* flag to identify that message is about new person joined
* #param isExit
* flag to identify that a person left the conversation
* */
private void sendMessageToAll(String sessionId, String name,
String message, boolean isNewClient, boolean isExit) {
// Looping through all the sessions and sending the message individually
for (Session s : sessions) {
String json = null;
// Checking if the message is about new client joined
if (isNewClient) {
json = jsonUtils.getNewClientJson(sessionId, name, message,
sessions.size());
} else if (isExit) {
// Checking if the person left the conversation
json = jsonUtils.getClientExitJson(sessionId, name, message, sessions.size());
} else {
// Normal chat conversation message
json = jsonUtils
.getSendAllMessageJson(sessionId, name, message);
}
try {
System.out.println("Sending Message To: " + sessionId + ", " + json);
s.getBasicRemote().sendText(json);
} catch (IOException e) {
System.out.println("error in sending. " + s.getId() + ", "
+ e.getMessage());
e.printStackTrace();
}
}
}
}
Firstly, the 404 code indicates that the element doesn't exist, then maybe your problem is the annotation #ServerEndpoint("/chat"), the HTTP request is looking for a /GroupChat/ element. Now, also you must review your settings files (web.xml, context.xml, application.xml, etc) because you could have an context attribute or display-name attribute misconfigured.
I hope this information helps you.
Good Luck.
Related
I am new in MQTT world. I have written a code to subscribe a topic and get message from topic and store it in database. Now my problem is how to put this code on server so that it will keep receiving message infinitely. I am trying to create a scheduler but in that case i am Getting Persistence Already in Use error from MQTT. I cannot change the clientId every time it connect. It is a fixed one in my case. Is there any way to get the persistence object which is already connected for a particular clientId?
Please help. Thanks and advance.
Please Find the code subscribe topic and messageArrived method of mqqt to get message from topic
public class AppTest {
private MqttHandler handler;
public void doApp() {
// Read properties from the conf file
Properties props = MqttUtil.readProperties("MyData/app.conf");
String org = props.getProperty("org");
String id = props.getProperty("appid");
String authmethod = props.getProperty("key");
String authtoken = props.getProperty("token");
// isSSL property
String sslStr = props.getProperty("isSSL");
boolean isSSL = false;
if (sslStr.equals("T")) {
isSSL = true;
}
// Format: a:<orgid>:<app-id>
String clientId = "a:" + org + ":" + id;
String serverHost = org + MqttUtil.SERVER_SUFFIX;
handler = new AppMqttHandler();
handler.connect(serverHost, clientId, authmethod, authtoken, isSSL);
// Subscribe Device Events
// iot-2/type/<type-id>/id/<device-id>/evt/<event-id>/fmt/<format-id>
handler.subscribe("iot-2/type/" + MqttUtil.DEFAULT_DEVICE_TYPE
+ "/id/+/evt/" + MqttUtil.DEFAULT_EVENT_ID + "/fmt/json", 0);
}
/**
* This class implements as the application MqttHandler
*
*/
private class AppMqttHandler extends MqttHandler {
// Pattern to check whether the events comes from a device for an event
Pattern pattern = Pattern.compile("iot-2/type/"
+ MqttUtil.DEFAULT_DEVICE_TYPE + "/id/(.+)/evt/"
+ MqttUtil.DEFAULT_EVENT_ID + "/fmt/json");
DatabaseHelper dbHelper = new DatabaseHelper();
/**
* Once a subscribed message is received
*/
#Override
public void messageArrived(String topic, MqttMessage mqttMessage)
throws Exception {
super.messageArrived(topic, mqttMessage);
Matcher matcher = pattern.matcher(topic);
if (matcher.matches()) {
String payload = new String(mqttMessage.getPayload());
// Parse the payload in Json Format
JSONObject contObj = new JSONObject(payload);
System.out
.println("jsonObject arrived in AppTest : " + contObj);
// Call method to insert data in database
dbHelper.insertIntoDB(contObj);
}
}
}
Code to connect to client
public void connect(String serverHost, String clientId, String authmethod,
String authtoken, boolean isSSL) {
// check if client is already connected
if (!isMqttConnected()) {
String connectionUri = null;
//tcp://<org-id>.messaging.internetofthings.ibmcloud.com:1883
//ssl://<org-id>.messaging.internetofthings.ibmcloud.com:8883
if (isSSL) {
connectionUri = "ssl://" + serverHost + ":" + DEFAULT_SSL_PORT;
} else {
connectionUri = "tcp://" + serverHost + ":" + DEFAULT_TCP_PORT;
}
if (client != null) {
try {
client.disconnect();
} catch (MqttException e) {
e.printStackTrace();
}
client = null;
}
try {
client = new MqttClient(connectionUri, clientId);
} catch (MqttException e) {
e.printStackTrace();
}
client.setCallback(this);
// create MqttConnectOptions and set the clean session flag
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(false);
options.setUserName(authmethod);
options.setPassword(authtoken.toCharArray());
//If SSL is used, do not forget to use TLSv1.2
if (isSSL) {
java.util.Properties sslClientProps = new java.util.Properties();
sslClientProps.setProperty("com.ibm.ssl.protocol", "TLSv1.2");
options.setSSLProperties(sslClientProps);
}
try {
// connect
client.connect(options);
System.out.println("Connected to " + connectionUri);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
Note:This is not a duplication or spammming since i have checked whole lot of searches.
Im currently developing an gcm integrated application and when i run on my emulator,it shows :
04-13 00:07:23.814: W/ActivityManager(366): Unable to start service
Intent { act=com.google.android.c2dm.intent.REGISTER
pkg=com.google.android.gms (has extras) } U=0: not found
My code is not similar to searches in here as I followed this tutorial https://github.com/erikswed/InstaChatX
In this tutorial,there are only 4 gcm client class,gcmbroadcast receiver,Gcm Util,Server Utilities and Constants.In those 4 classes havent mentioned about intent and in android manifest files also dont have permission:
Here is code for 4 gcm client class:
public class GcmBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "GcmBroadcastReceiver";
private Context ctx;
#Override
public void onReceive(Context context, Intent intent) {
ctx = context;
PowerManager mPowerManager = (PowerManager)
context.getSystemService(Context.POWER_SERVICE);
WakeLock mWakeLock =
mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mWakeLock.acquire();
try {
GoogleCloudMessaging gcm =
GoogleCloudMessaging.getInstance(context);
String messageType = gcm.getMessageType(intent);
if
(GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
sendNotification("Send error", false);
} else if
(GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
sendNotification("Deleted messages on server", false);
} else {
String msg = intent.getStringExtra(DataProvider.COL_MESSAGE);
String senderEmail =
intent.getStringExtra(DataProvider.COL_SENDER_EMAIL);
String receiverEmail =
intent.getStringExtra(DataProvider.COL_RECEIVER_EMAIL);
ContentValues values = new ContentValues(2);
values.put(DataProvider.COL_TYPE,
MessageType.INCOMING.ordinal());
values.put(DataProvider.COL_MESSAGE, msg);
values.put(DataProvider.COL_SENDER_EMAIL, senderEmail);
values.put(DataProvider.COL_RECEIVER_EMAIL, receiverEmail);
context.getContentResolver().insert
(DataProvider.CONTENT_URI_MESSAGES, values);
if (Common.isNotify()) {
sendNotification("New message", true);
}
}
setResultCode(Activity.RESULT_OK);
} finally {
mWakeLock.release();
}
}
private void sendNotification(String text, boolean launchApp) {
NotificationManager mNotificationManager = (NotificationManager)
ctx.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder notification = new
NotificationCompat.Builder(ctx);
notification.setContentTitle(ctx.getString(R.string.app_name));
notification.setContentText(text);
notification.setAutoCancel(true);
notification.setSmallIcon(R.drawable.ic_launcher);
if (!TextUtils.isEmpty(Common.getRingtone())) {
notification.setSound(Uri.parse(Common.getRingtone()));
}
if (launchApp) {
Intent intent = new Intent(ctx, Chat_List.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pi = PendingIntent.getActivity(ctx, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
notification.setContentIntent(pi);
}
mNotificationManager.notify(1, notification.build());
}
}
This is GcmUtil class:
public class GcmUtil {
private static final String TAG = "GcmUtil";
public static final String PROPERTY_REG_ID = "registration_id";
private static final String PROPERTY_APP_VERSION = "appVersion";
private static final String PROPERTY_ON_SERVER_EXPIRATION_TIME = "onServerExpirationTimeMs";
/**
* Default lifespan (7 days) of a reservation until it is considered expired.
*/
public static final long REGISTRATION_EXPIRY_TIME_MS = 1000 * 3600 * 24 * 7;
private static final int MAX_ATTEMPTS = 5;
private static final int BACKOFF_MILLI_SECONDS = 2000;
private static final Random random = new Random();
private Context ctx;
private SharedPreferences prefs;
private GoogleCloudMessaging gcm;
private AsyncTask registrationTask;
public GcmUtil(Context ApplicationContext) {
super();
ctx = ApplicationContext;
prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
String regid = getRegistrationId();
if (regid.length() == 0) {
registerBackground();
} else {
broadcastStatus(true);
}
gcm = GoogleCloudMessaging.getInstance(ctx);
}
/**
* Gets the current registration id for application on GCM service.
* <p>
* If result is empty, the registration has failed.
*
* #return registration id, or empty string if the registration is not
* complete.
*/
private String getRegistrationId() {
String registrationId = prefs.getString(PROPERTY_REG_ID, "");
if (registrationId.length() == 0) {
//Log.v(TAG, "Registration not found.");
return "";
}
// check if app was updated; if so, it must clear registration id to
// avoid a race condition if GCM sends a message
int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion();
if (registeredVersion != currentVersion || isRegistrationExpired()) {
//Log.v(TAG, "App version changed or registration expired.");
return "";
}
return registrationId;
}
/**
* Stores the registration id, app versionCode, and expiration time in the
* application's {#code SharedPreferences}.
*
* #param regId registration id
*/
private void setRegistrationId(String regId) {
int appVersion = getAppVersion();
//Log.v(TAG, "Saving regId on app version " + appVersion);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(PROPERTY_REG_ID, regId);
editor.putInt(PROPERTY_APP_VERSION, appVersion);
long expirationTime = System.currentTimeMillis() + REGISTRATION_EXPIRY_TIME_MS;
//Log.v(TAG, "Setting registration expiry time to " + new Timestamp(expirationTime));
editor.putLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, expirationTime);
editor.commit();
}
/**
* #return Application's version code from the {#code PackageManager}.
*/
private int getAppVersion() {
try {
PackageInfo packageInfo = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 0);
return packageInfo.versionCode;
} catch (NameNotFoundException e) {
// should never happen
throw new RuntimeException("Could not get package name: " + e);
}
}
/**
* Checks if the registration has expired.
*
* <p>To avoid the scenario where the device sends the registration to the
* server but the server loses it, the app developer may choose to re-register
* after REGISTRATION_EXPIRY_TIME_MS.
*
* #return true if the registration has expired.
*/
private boolean isRegistrationExpired() {
// checks if the information is not stale
long expirationTime = prefs.getLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, -1);
return System.currentTimeMillis() > expirationTime;
}
/**
* Registers the application with GCM servers asynchronously.
* <p>
* Stores the registration id, app versionCode, and expiration time in the
* application's shared preferences.
*/
private void registerBackground() {
registrationTask = new AsyncTask<Void, Void, Boolean>() {
#Override
protected Boolean doInBackground(Void... params) {
long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);
for (int i = 1; i <= MAX_ATTEMPTS; i++) {
//Log.d(TAG, "Attempt #" + i + " to register");
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(ctx);
}
String regid = gcm.register(Common.getSenderId());
// You should send the registration ID to your server over HTTP,
// so it can use GCM/HTTP or CCS to send messages to your app.
ServerUtilities.register(Common.getPreferredEmail(), regid);
// Save the regid - no need to register again.
setRegistrationId(regid);
return Boolean.TRUE;
} catch (IOException ex) {
//Log.e(TAG, "Failed to register on attempt " + i + ":" + ex);
if (i == MAX_ATTEMPTS) {
break;
}
try {
//Log.d(TAG, "Sleeping for " + backoff + " ms before retry");
Thread.sleep(backoff);
} catch (InterruptedException e1) {
// Activity finished before we complete - exit.
//Log.d(TAG, "Thread interrupted: abort remaining retries!");
Thread.currentThread().interrupt();
}
// increase backoff exponentially
backoff *= 2;
}
}
return Boolean.FALSE;
}
#Override
protected void onPostExecute(Boolean status) {
broadcastStatus(status);
}
}.execute();
}
private void broadcastStatus(boolean status) {
Intent intent = new Intent(Common.ACTION_REGISTER);
intent.putExtra(Common.EXTRA_STATUS, status ? Common.STATUS_SUCCESS : Common.STATUS_FAILED);
ctx.sendBroadcast(intent);
}
public void cleanup() {
if (registrationTask != null) {
registrationTask.cancel(true);
}
if (gcm != null) {
gcm.close();
}
}
}
This is Server Utilities Class:
public final class ServerUtilities {
private static final String TAG = "ServerUtilities";
private static final int MAX_ATTEMPTS = 5;
private static final int BACKOFF_MILLI_SECONDS = 2000;
private static final Random random = new Random();
/**
* Register this account/device pair within the server.
*/
public static void register(final String email, final String regId) {
//Log.i(TAG, "registering device (regId = " + regId + ")");
String serverUrl = Common.getServerUrl() + "/register";
Map<String, String> params = new HashMap<String, String>();
params.put(DataProvider.SENDER_EMAIL, email);
params.put(DataProvider.REG_ID, regId);
// Once GCM returns a registration id, we need to register it in the
// demo server. As the server might be down, we will retry it a couple
// times.
try {
post(serverUrl, params, MAX_ATTEMPTS);
} catch (IOException e) {
}
}
/**
* Unregister this account/device pair within the server.
*/
public static void unregister(final String email) {
//Log.i(TAG, "unregistering device (email = " + email + ")");
String serverUrl = Common.getServerUrl() + "/unregister";
Map<String, String> params = new HashMap<String, String>();
params.put(DataProvider.SENDER_EMAIL, email);
try {
post(serverUrl, params, MAX_ATTEMPTS);
} catch (IOException e) {
// At this point the device is unregistered from GCM, but still
// registered in the server.
// We could try to unregister again, but it is not necessary:
// if the server tries to send a message to the device, it will get
// a "NotRegistered" error message and should unregister the device.
}
}
/**
* Send a message.
*/
public static void send(String msg, String to) throws IOException {
//Log.i(TAG, "sending message (msg = " + msg + ")");
String serverUrl = Common.getServerUrl() + "/send";
Map<String, String> params = new HashMap<String, String>();
params.put(DataProvider.MESSAGE, msg);
params.put(DataProvider.SENDER_EMAIL, Common.getPreferredEmail());
params.put(DataProvider.RECEIVER_EMAIL, to);
post(serverUrl, params, MAX_ATTEMPTS);
}
/** Issue a POST with exponential backoff */
private static void post(String endpoint, Map<String, String> params, int maxAttempts) throws IOException {
long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);
for (int i = 1; i <= maxAttempts; i++) {
//Log.d(TAG, "Attempt #" + i);
try {
post(endpoint, params);
return;
} catch (IOException e) {
//Log.e(TAG, "Failed on attempt " + i + ":" + e);
if (i == maxAttempts) {
throw e;
}
try {
Thread.sleep(backoff);
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
return;
}
backoff *= 2;
} catch (IllegalArgumentException e) {
throw new IOException(e.getMessage(), e);
}
}
}
/**
* Issue a POST request to the server.
*
* #param endpoint POST address.
* #param params request parameters.
*
* #throws IOException propagated from POST.
*/
private static void post(String endpoint, Map<String, String> params) throws IOException {
URL url;
try {
url = new URL(endpoint);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("invalid url: " + endpoint);
}
StringBuilder bodyBuilder = new StringBuilder();
Iterator<Entry<String, String>> iterator = params.entrySet().iterator();
// constructs the POST body using the parameters
while (iterator.hasNext()) {
Entry<String, String> param = iterator.next();
bodyBuilder.append(param.getKey()).append('=').append(param.getValue());
if (iterator.hasNext()) {
bodyBuilder.append('&');
}
}
String body = bodyBuilder.toString();
//Log.v(TAG, "Posting '" + body + "' to " + url);
byte[] bytes = body.getBytes();
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setFixedLengthStreamingMode(bytes.length);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
// post the request
OutputStream out = conn.getOutputStream();
out.write(bytes);
out.close();
// handle the response
int status = conn.getResponseCode();
if (status != 200) {
throw new IOException("Post failed with error code " + status);
}
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
}
Constants class only have sender id and url.
Question is quite basic . I am following a tutorial on creating a chat application using tomcat7 . Everything works fine on localhost but as i deploy it on openshift it doesn't seem to be creating a socket connection .
link to the uploaded website is here : http://qabchat-survey987.rhcloud.com
Java Script file is given bellow which is responsible for sending and receiving messages between client and server
var sessionId = '';
// name of the client
var name = '';
// socket connection url and port
var socket_url = 'qabchat-survey987.rhcloud.com';
var port = '8443';
$(document).ready(function() {
$("#form_submit, #form_send_message").submit(function(e) {
e.preventDefault();
join();
});
});
var webSocket;
/**
* Connecting to socket
*/
function join() {
// Checking person name
if ($('#input_name').val().trim().length <= 0) {
alert('Enter your name');
} else {
name = $('#input_name').val().trim();
$('#prompt_name_container').fadeOut(1000, function() {
// opening socket connection
openSocket();
});
}
return false;
}
/**
* Will open the socket connection
*/
function openSocket() {
// Ensures only one connection is open at a time
if (webSocket !== undefined && webSocket.readyState !== WebSocket.CLOSED) {
return;
}
// Create a new instance of the websocket
webSocket = new WebSocket("ws://" + socket_url + ":" + port
+ "/qabchat/chat1?name=" + name);
/**
* Binds functions to the listeners for the websocket.
*/
webSocket.onopen = function(event) {
$('#message_container').fadeIn();
if (event.data === undefined)
return;
};
webSocket.onmessage = function(event) {
// parsing the json data
parseMessage(event.data);
};
webSocket.onclose = function(event) {
alert('Error! Connection is closed. Try connecting again.');
};
}
/**
* Sending the chat message to server
*/
function send() {
var message = $('#input_message').val();
if (message.trim().length > 0) {
sendMessageToServer('message', message);
} else {
alert('Please enter message to send!');
}
}
/**
* Closing the socket connection
*/
function closeSocket() {
webSocket.close();
$('#message_container').fadeOut(600, function() {
$('#prompt_name_container').fadeIn();
// clearing the name and session id
sessionId = '';
name = '';
// clear the ul li messages
$('#messages').html('');
$('p.online_count').hide();
});
}
/**
* Parsing the json message. The type of message is identified by 'flag' node
* value flag can be self, new, message, exit
*/
function parseMessage(message) {
var jObj = $.parseJSON(message);
// if the flag is 'self' message contains the session id
if (jObj.flag == 'self') {
sessionId = jObj.sessionId;
} else if (jObj.flag == 'new') {
// if the flag is 'new', a client joined the chat room
var new_name = 'You';
// number of people online
var online_count = jObj.onlineCount;
$('p.online_count').html(
'Hello, <span class="green">' + name + '</span>. <b>'
+ online_count + '</b> people online right now')
.fadeIn();
if (jObj.sessionId != sessionId) {
new_name = jObj.name;
}
var li = '<li class="new"><span class="name">' + new_name + '</span> '
+ jObj.message + '</li>';
$('#messages').append(li);
$('#input_message').val('');
ai
} else if (jObj.flag == 'message') {
// if the json flag is 'message', it means somebody sent the chat
// message
var from_name = 'You';
if (jObj.sessionId != sessionId) {
from_name = jObj.name;
}
var li = '<li><span class="name">' + from_name + '</span> '
+ jObj.message + '</li>';
// appending the chat message to list
appendChatMessage(li);
$('#input_message').val('');
} else if (jObj.flag == 'exit') {
// if the json flag is 'exit', it means somebody left the chat room
var li = '<li class="exit"><span class="name red">' + jObj.name
+ '</span> ' + jObj.message + '</li>';
var online_count = jObj.onlineCount;
$('p.online_count').html(
'Hello, <span class="green">' + name + '</span>. <b>'
+ online_count + '</b> people online right now');
appendChatMessage(li);
}
}
/**
* Appending the chat message to list
*/
function appendChatMessage(li) {
$('#messages').append(li);
// scrolling the list to bottom so that new message will be visible
$('#messages').scrollTop($('#messages').height());
}
/**
* Sending message to socket server message will be in json format
*/
function sendMessageToServer(flag, message) {
var json = '{""}';
// preparing json object
var myObject = new Object();
myObject.sessionId = sessionId;
myObject.message = message;
myObject.flag = flag;
// converting json object to json string
json = JSON.stringify(myObject);
// sending message to server
webSocket.send(json);
}
I have tried using 8000 port as well as using wss: instead of ws for the instance of websocket . Java file is given bellow :
#ServerEndpoint("/chat1")
public class SocketServer {
// set to store all the live sessions
private static final Set<Session> sessions = Collections
.synchronizedSet(new HashSet<Session>());
// Mapping between session and person name
private static final HashMap<String, String> nameSessionPair = new HashMap<String, String>();
private static final HashMap<String, String> SessionNamePair=new HashMap<String,String>();
private JSONUtils jsonUtils = new JSONUtils();
// Getting query params
public static Map<String, String> getQueryMap(String query) {
Map<String, String> map = Maps.newHashMap();
if (query != null) {
String[] params = query.split("&");
for (String param : params) {
String[] nameval = param.split("=");
map.put(nameval[0], nameval[1]);
}
}
return map;
}
/**
* Called when a socket connection opened
* */
#OnOpen
public void onOpen(Session session) {
System.out.println(session.getId() + " has opened a connection");
Map<String, String> queryParams = getQueryMap(session.getQueryString());
String name = "";
if (queryParams.containsKey("name")) {
// Getting client name via query param
name = queryParams.get("name");
try {
name = URLDecoder.decode(name, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// Mapping client name and session id
nameSessionPair.put(session.getId(), name);
SessionNamePair.put(name, session.getId());
}
// Adding session to session list
sessions.add(session);
try {
// Sending session id to the client that just connected
session.getBasicRemote().sendText(
jsonUtils.getClientDetailsJson(session.getId(),
"Your session details"));
} catch (IOException e) {
e.printStackTrace();
}
// Notifying all the clients about new person joined
sendMessageToAll(session.getId(), name, " joined conversation!", true,
false);
}
/**
* method called when new message received from any client
*
* #param message
* JSON message from client
* */
#OnMessage
public void onMessage(String message, Session session) {
System.out.println("Message from " + session.getId() + ": " + message);
String msg = null;
// Parsing the json and getting message
try {
JSONObject jObj = new JSONObject(message);
msg = jObj.getString("message");
} catch (JSONException e) {
e.printStackTrace();
}
// Sending the message to all clients
sendMessageToAll(session.getId(), nameSessionPair.get(session.getId()),
msg, false, false);
}
/**
* Method called when a connection is closed
* */
#OnClose
public void onClose(Session session) {
System.out.println("Session " + session.getId() + " has ended");
// Getting the client name that exited
String name = nameSessionPair.get(session.getId());
// removing the session from sessions list
sessions.remove(session);
// Notifying all the clients about person exit
sendMessageToAll(session.getId(), name, " left conversation!", false,
true);
}
/**
* Method to send message to all clients
*
* #param sessionId
* #param message
* message to be sent to clients
* #param isNewClient
* flag to identify that message is about new person joined
* #param isExit
* flag to identify that a person left the conversation
* */
private void sendMessageToAll(String sessionId, String name,
String message, boolean isNewClient, boolean isExit) {
// Looping through all the sessions and sending the message individually
for (Session s : sessions) {
String json = null;
// Checking if the message is about new client joined
if (isNewClient) {
json = jsonUtils.getNewClientJson(sessionId, name, message,
sessions.size());
} else if (isExit) {
// Checking if the person left the conversation
json = jsonUtils.getClientExitJson(sessionId, name, message,
sessions.size());
} else {
// Normal chat conversation message
json = jsonUtils
.getSendAllMessageJson(sessionId, name, message);
}
try {
System.out.println("Sending Message To: " + sessionId + ", "
+ json + SessionNamePair.get(name));
s.getBasicRemote().sendText(json);
} catch (IOException e) {
System.out.println("error in sending. " + s.getId() + ", "
+ e.getMessage());
e.printStackTrace();
}
}
}
}
I can not seem to figure out why the code is not working on openshift while it works just fine on localhost . Name of the main root directory of the project in openshift is qabchat.
I ran a simple test found out that after the onopen() function in javascript file , onclose() function is being called .
So, Google used to have a nice page where they gave code sample on how to implement a GCM Xmpp server on this page:
https://developers.google.com/cloud-messaging/ccs
I had bookmarked this answer anytime I wanted to view the implementation
Confused about Google GCM XMPP
But everything linked from in that answer is gone. Google deleted them.
But now, they have removed everything, and added a page that just explains what it does. Sure, but the sample java code would be nice. I tried to go to the sample site on github that they link to
https://github.com/google/gcm
but it only provides samples of HTTP GCM server version.
Can somebody point me to a working code sample please? Or Is there a library out there that would work with c# at all? if not, I would just settle with the java version too.
Thanks.
Here is one I wrote for a class example (with some non-XMPP parts deleted to keep it small enough so I can post the code, but have the full server at http://people.eku.edu/styere/GcmPushServer.java):
// derived from https://developer.android.com/google/gcm/ccs.html
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
//import javax.swing.JScrollPane;
//import javax.swing.SwingUtilities;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.PacketInterceptor;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.DefaultPacketExtension;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.util.StringUtils;
import org.json.simple.JSONValue;
import org.json.simple.JSONObject;
import org.json.simple.parser.ParseException;
import org.xmlpull.v1.XmlPullParser;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Random;
import java.net.*;
import java.io.*;
import java.util.*;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.HttpsURLConnection;
// list of all users and associated devices
class UserList {
// (--deleted--)
// constructor/read existing data from file
public UserList() {
// (--deleted--)
}
// add a new device to an existing user (called from networking thread)
// duplicate IDs are quietly accepted
public synchronized void addDevice( String uname, String newRegToken ) {
// (--deleted--)
}
// generate a group address/notification key
// !!!!!!!!!!!!!!! W A R N I N G !!!!!!!!!!!!!!!
// If the group addr/notification key is lost, it currently CANNOT be recovered/rebuilt
public String createNotificationKey( String nKeyName, String addr ) {
String[] idset = new String[1];
idset[0] = addr;
String newGroupAddr;
try {
// create a https connection to create the notification_key
URL url = new URL( "https://android.googleapis.com/gcm/notification" );
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
// send as a POST request
conn.setRequestMethod("POST");
// add request parameters
conn.addRequestProperty( "project_id", ""+GcmPushServer.senderId );
conn.addRequestProperty( "Authorization", "key="+GcmPushServer.password );
// use "set" since this may already exist
conn.setRequestProperty( "Content-Type", "application/json" );
// create data to send with request
Map<String,Object> sendData = new HashMap<>();
// create a new notification key
sendData.put( "operation", "create" );
sendData.put( "notification_key_name", (--deleted--) );
sendData.put( "registration_ids", (--deleted--) );
String strData = JSONValue.toJSONString(sendData);
// Send post request
conn.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes( strData );
wr.flush();
wr.close();
// successful?
int rc = conn.getResponseCode();
//System.out.println("ResponseCode = " + rc );
// read the response
Scanner input = new Scanner( conn.getInputStream() );
String resp="";
// read/display lines
while( input.hasNextLine() ) {
String s = input.nextLine();
resp += s;
}
//System.out.println("Response content: " + resp);
if ( rc == HttpsURLConnection.HTTP_OK ) {
JSONObject obj = (JSONObject) JSONValue.parse(resp);
newGroupAddr = (String) obj.get( "notification_key" );
//System.out.println(" new notification_key: " + newGroupAddr );
return newGroupAddr;
} else {
}
} catch ( Exception e ) {
//System.out.println("-- Exception: " + e.getMessage() );
}
return null;
}
// add/delete a single address to/from a notification key
// (add if doAdd is true, delete otherwise)
// removing final address will quietly delete the key
public static void modifyNotificationKey( String nKeyName, String nKey,
String addr, boolean doAdd ) {
String[] idset = new String[1];
idset[0] = addr;
try {
// create a https connection to create the notification_key
URL url = new URL( "https://android.googleapis.com/gcm/notification" );
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
// send as a POST request
conn.setRequestMethod("POST");
// add request parameters
conn.addRequestProperty( "project_id", ""+GcmPushServer.senderId );
conn.addRequestProperty( "Authorization", "key="+GcmPushServer.password );
// use "set" since this may already exist
conn.setRequestProperty( "Content-Type", "application/json" );
// create data to send with request
Map<String,Object> sendData = new HashMap<>();
// create a new notification key
sendData.put( "operation", doAdd? "add" : "remove" ); // add or delete key?
sendData.put( "notification_key_name", (--deleted--) );
sendData.put( "notification_key", (--deleted--) );
sendData.put( "registration_ids", (--deleted--) );
String strData = JSONValue.toJSONString(sendData);
//System.out.println("genGroupAddress POST data: " + strData );
// Send post request
conn.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes( strData );
wr.flush();
wr.close();
//conn.openConnection();
// successful?
int rc = conn.getResponseCode();
//System.out.println("ResponseCode = " + rc );
Scanner input = new Scanner( conn.getInputStream() );
// read/display lines
while( input.hasNextLine() ) {
System.out.println("Response content:");
String s = input.nextLine();
System.out.println( s );
}
} catch ( Exception e ) {
// do nothing
}
}
}
// text area for log messages
class LogTextArea extends JTextArea {
// update the "log" with the specified message
public void logMessage( String msg ) {
// (--deleted--)
}
}
class CcsServer {
private static final String GCM_SERVER = "gcm.googleapis.com";
private static final int GCM_PORT = 5235;
private static final String GCM_ELEMENT_NAME = "gcm";
private static final String GCM_NAMESPACE = "google:mobile:data";
// display/log area
LogTextArea logArea;
UserList users;
CcsServer( LogTextArea lta, UserList u ) {
logArea = lta;
users = u;
}
static {
ProviderManager.addExtensionProvider(GCM_ELEMENT_NAME, GCM_NAMESPACE,
new PacketExtensionProvider() {
#Override
public PacketExtension parseExtension(XmlPullParser parser) throws
Exception {
String json = parser.nextText();
return new GcmPacketExtension(json);
}
});
}
private XMPPConnection connection;
/**
* Indicates whether the connection is in draining state, which means that it
* will not accept any new downstream messages.
*/
protected volatile boolean connectionDraining = false;
/**
* Sends a downstream message to GCM.
*
* #return true if the message has been successfully sent.
*/
public boolean sendDownstreamMessage(String jsonRequest) throws
NotConnectedException {
if (!connectionDraining) {
send(jsonRequest);
return true;
}
logArea.logMessage("Dropping downstream message since the connection is draining");
return false;
}
/**
* 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 nextMessageId() {
return "m-" + UUID.randomUUID().toString();
}
/**
* Sends a packet with contents provided.
*/
protected void send(String jsonRequest) throws NotConnectedException {
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 properly process upstream messages.
*/
protected void handleUpstreamMessage(Map<String, Object> jsonObject) {
// PackageName of the application that sent this message.
String category = (String) jsonObject.get("category");
String from = (String) jsonObject.get("from");
#SuppressWarnings("unchecked")
Map<String, String> payload = (Map<String, String>) jsonObject.get("data");
// what type of upstream message is this?
if ( ! payload.containsKey( "my_action" ) )
{
// Hmmm - this shouldn't happen!
logArea.logMessage( "handleUpstreamMessage - incoming message is missing my_action" );
// just ignore the message
return;
}
// what action do they want?
String my_action = (String) payload.get( "my_action" );
if ( my_action.equals( "edu.eku.styere.gcmpushclient.REGISTER" ) ) {
// registration request
String username = (String) payload.get( "username" );
logArea.logMessage( "Registration request: user=" + username + ", ID/Token=" + from );
// save the information
users.addDevice( username, from );
return;
} else {
// take default action of echoing the message
payload.put("ECHO", "Application: " + category);
// Send an ECHO response back
String echo = createJsonMessage(from, nextMessageId(), payload,
"echo:CollapseKey", null, false);
try {
sendDownstreamMessage(echo);
} catch (NotConnectedException e) {
logArea.logMessage( "Not connected anymore, echo message is not sent: " + e.getMessage() );
}
}
}
/**
* Handles an ACK.
*
* <p>Logs a INFO message, but subclasses could override it to
* properly handle ACKs.
*/
protected void handleAckReceipt(Map<String, Object> jsonObject) {
String messageId = (String) jsonObject.get("message_id");
String from = (String) jsonObject.get("from");
logArea.logMessage( "handleAckReceipt() from: " + from + ", messageId: " + messageId );
}
/**
* Handles a NACK.
*
* <p>Logs a INFO message, but subclasses could override it to
* properly handle NACKs.
*/
protected void handleNackReceipt(Map<String, Object> jsonObject) {
String messageId = (String) jsonObject.get("message_id");
String from = (String) jsonObject.get("from");
logArea.logMessage( "handleNackReceipt() from: " + from + ", messageId: " + messageId );
}
protected void handleControlMessage(Map<String, Object> jsonObject) {
logArea.logMessage( "handleControlMessage(): " + jsonObject );
String controlType = (String) jsonObject.get("control_type");
if ("CONNECTION_DRAINING".equals(controlType)) {
connectionDraining = true;
} else {
logArea.logMessage( "Unrecognised control type: " + controlType + ". This could "+
"happen if new features are " + "added to the CCS protocol." );
}
}
/**
* Creates a JSON encoded GCM message.
*
* #param to RegistrationId of the target device (Required).
* #param messageId Unique messageId for which CCS sends 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.
*/
protected 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 senderId Your GCM project number
* #param apiKey API Key of your project
*/
public void connect(long senderId, String apiKey)
throws XMPPException, IOException, SmackException {
ConnectionConfiguration config =
new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
config.setSecurityMode(SecurityMode.enabled);
config.setReconnectionAllowed(true);
config.setRosterLoadedAtLogin(false);
config.setSendPresence(false);
config.setSocketFactory(SSLSocketFactory.getDefault());
connection = new XMPPTCPConnection(config);
connection.connect();
connection.addConnectionListener( new LoggingConnectionListener() );
// Handle incoming packets
connection.addPacketListener(new PacketListener() {
#Override
public void processPacket(Packet packet) {
logArea.logMessage( "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
handleUpstreamMessage(jsonObject);
// Send ACK to CCS
String messageId = (String) jsonObject.get("message_id");
String from = (String) jsonObject.get("from");
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 if ("control".equals(messageType.toString())) {
// Process control message
handleControlMessage(jsonObject);
} else {
logArea.logMessage( "Unrecognised message type: " +
messageType.toString() );
}
} catch (ParseException e) {
logArea.logMessage( "Error parsing JSON " + json );
} catch (Exception e) {
logArea.logMessage( "Failed to process packet" );
}
}
}, new PacketTypeFilter(Message.class));
// Log all outgoing packets
connection.addPacketInterceptor(new PacketInterceptor() {
#Override
public void interceptPacket(Packet packet) {
logArea.logMessage( "Sent: " + packet.toXML());
}
}, new PacketTypeFilter(Message.class));
connection.login(senderId + "#gcm.googleapis.com", apiKey);
}
//---------- support classes ----------
/**
* XMPP Packet Extension for GCM Cloud Connection Server.
*/
private static class GcmPacketExtension extends DefaultPacketExtension {
private final 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,
StringUtils.escapeForXML(json), GCM_ELEMENT_NAME);
}
public Packet toPacket() {
Message message = new Message();
message.addExtension(this);
return message;
}
}
class LoggingConnectionListener implements ConnectionListener {
#Override
public void connected(XMPPConnection xmppConnection) {
logArea.logMessage( "Connected." );
}
#Override
public void authenticated(XMPPConnection xmppConnection) {
logArea.logMessage( "Authenticated." );
}
#Override
public void reconnectionSuccessful() {
logArea.logMessage( "Reconnecting.." );
}
#Override
public void reconnectionFailed(Exception e) {
logArea.logMessage( "Reconnection failed.. " + e.getMessage() );
}
#Override
public void reconnectingIn(int seconds) {
logArea.logMessage( "Reconnecting in " + seconds + " secs" );
}
#Override
public void connectionClosedOnError(Exception e) {
logArea.logMessage( "Connection closed on error." );
}
#Override
public void connectionClosed() {
logArea.logMessage( "Connection closed." );
}
}
}
// a non-editable combo (drop-down) box for destination addresses
class DestComboBox extends JComboBox<String> {
// (deleted to save space)
}
// screen panel for sending a message
class SendMessagePanel extends JPanel implements ActionListener, ItemListener {
// Message Types
protected final int MSGTYPE_NOTIFICATION = 1;
protected final int MSGTYPE_NOTIFICATION_DATA = 2;
protected final int MSGTYPE_DATA_COLLAPSE = 3;
protected final int MSGTYPE_DATA_NONCOLLAPSE = 4;
// log window
LogTextArea msgs;
// server class
CcsServer ccsServer;
// constructor
SendMessagePanel( UserList u, LogTextArea m, CcsServer c ) {
// (deleted to save space)
}
// respond to the button
#Override
public void actionPerformed(ActionEvent e) {
String toAddr = "zzzzzz"; // destination address
// may be device, notification_key, or topic address
ttl = 2419200; // time-to-live in seconds
// what type of message?
int msgTypeIndex = (--deleted--);
// create the message
Map<String, Object> message = new HashMap<String, Object>();
message.put("to", toAddr);
if ( msgTypeIndex == MSGTYPE_NOTIFICATION ||
msgTypeIndex == MSGTYPE_NOTIFICATION_DATA ||
msgTypeIndex == MSGTYPE_DATA_COLLAPSE ) {
// create a collapse key
message.put("collapse_key", "ck"+msgTypeIndex );
}
message.put("time_to_live", ttl);
message.put("message_id", ccsServer.nextMessageId());
// notification included?
if ( msgTypeIndex == MSGTYPE_NOTIFICATION ||
msgTypeIndex == MSGTYPE_NOTIFICATION_DATA ) {
// create the notification payload
HashMap<String, String> notePayload = new HashMap<>();
notePayload.put( "title", "Gcm Push Message Example" );
notePayload.put( "body", (--deleted--) );
// identify which notifications should replace older versions
notePayload.put( "tag", "ntag" + msgTypeIndex );
notePayload.put( "icon", "#drawable/new_picture" ); // notification icon
// additional stuff if we also have data
if ( msgTypeIndex == MSGTYPE_NOTIFICATION_DATA ) {
// what to do when the user opens the notification
notePayload.put( "click_action", "OPEN_MAIN_ACTIVITY" );
}
message.put( "notification", notePayload );
}
// data included?
if ( msgTypeIndex == MSGTYPE_NOTIFICATION_DATA ||
msgTypeIndex == MSGTYPE_DATA_COLLAPSE ||
msgTypeIndex == MSGTYPE_DATA_NONCOLLAPSE ) {
HashMap<String, String> dataPayload = new HashMap<>();
dataPayload.put( "contents", (--deleted--) );
message.put("data", dataPayload);
}
// actually send the message
try {
ccsServer.sendDownstreamMessage( JSONValue.toJSONString(message) );
} catch (NotConnectedException enc ) {
msgs.logMessage( "Not connected anymore, echo message is not sent: " + enc.getMessage() );
}
}
}
class BorderPanel extends JPanel {
// (--deleted--)
}
public class GcmPushServer
{
// (--deleted--)
}
Google's example implementation of an XMPP server is in the friendly-ping sample. It has Java and Go versions.
A little bit late, but here's:
The direct link to the sample app server for ccs connection Friendly Ping java
Wolfram Rittmeyer also created a gcm server, in his An XMPP Server for Google Cloud Messaging post
http://www.androidhive.info/2014/10/android-building-group-chat-app-using-sockets-part-2/
Hi,
This is a tutorial about building a group chat app using socket programming. This app allows us to chat between multiple devices like android mobiles and web.
I want to send more than one "String" at a time to the server. I'm having trouble figuring that out.
The link to the tutorial where I downloaded the code is pasted above. I've already made the dynamic web page and I have it hosted on eapps.com At the very bottom of the this email is the edited code for the app. If you click the link above, you can see how I changed it.
The way it works is..
A web socket is created using WebSocketClient class and it has all the callback methods like onConnect, onMessage and onDisconnect.
In onMessage method parseMessage() is called to parse the JSON received from the socket server.
In parseMessage() method, the purpose of JSON is identified by reading the flag value.
When a new message is received, the message is added to list view data source and adapter.notifyDataSetChanged() is called to update the chat list.
sendMessageToServer() method is used to send the message from android device to socket server.
playBeep() method is called to play device’s default notification sound whenever a new message is received.
When you click the btnSend. it uses this method from the UtilsXd class. I've changed it a little in an attempt to pass an extra value.
public String getSendMessageJSONXD(String message, String whichPicIndex) {
String json = null;
try {
JSONObject jObj = new JSONObject();
jObj.put("flag", FLAG_MESSAGE);
jObj.put("sessionId", getSessionId());
jObj.put("message", message);
jObj.put("id", id);
json = jObj.toString();
} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
First of all, what I still don't understand is, where did the values for
String sessionId = jObj.getString("sessionId");
and
String onlineCount = jObj.getString("onlineCount");
from this method
private void parseMessage(final String msg, String idINDEX) {
come from.
They were't added in the JSON object created in the UtilsXD class so how are they created?
That's not the problem I'm having. This is.
superString is the value I want to pass to dictate which picture to show.
superString = (sharedPrefs.getString("prefSyncAvatar", "1"));
You can change your picture in from the settings.
When a message is received, a switch/case statement changes the picture of/ for the message received according to the value passed by superString.
I should be able to sit there and just receive messages, and whatever number the user passes, the profilePicture should be set according to that number.
Here's where the problem begins.
This constructer builds a message based of the message that's just been parsed.
// Message m = new Message(fromName, message, isSelf);
Message m = new Message(fromName, message, isSelf, id, name,
image, status, profilePic, timeStamp, url);
In this method.
private void parseMessage(final String msg, String idINDEX) {
I can pass an value to the string "id" excluding the JSON I need it to.
String id = idINDEX;
this works,
String id = "0";
this works,
String id = utils.getPictureId();
this works,
String id = jObj.getString("id");
This doesn't work.
This is the error I'm getting.
org.json.JSONException: No value for id (this is the issue)
I've added the key/value pair
jObj.put("id", id);
in
public String getSendMessageJSONXD(String message, String whichPicIndex) {
but it's not coming though to the message.
Here's where I think the problem is.
The method onMessage, isn't can't take an extra parameter because it's from a library project. And I can't find that method to make a new constructor.
#Override
public void onMessage(String message) {
Log.d(TAG, String.format("Got string message! %s", message));
parseMessage(message, superString);
}
#Override
public void onMessage(byte[] data) {
Log.d(TAG, String.format("Got binary message! %s",
bytesToHex(data)));
String hello = "99";
parseMessage(bytesToHex(data), superString);
}
/////// Here's the final code below ////////
// JSON flags to identify the kind of JSON response
private static final String TAG_SELF = "self", TAG_NEW = "new",
TAG_MESSAGE = "message", TAG_ID = "id", TAG_EXIT = "exit";
#SuppressWarnings("deprecation")
#SuppressLint({ "NewApi", "CutPasteId" })
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_chat);
showUserSettings();
getActionBar().setTitle("City Chat - Beta 1.3");
superString = (sharedPrefs.getString("prefSyncAvatar", "1"));
listView = (ListView) findViewById(R.id.list_view_messages);
feedItems = new ArrayList<FeedItem>();
// We first check for cached request
vollewStuff();
//
//
// THis is where this fun begins
btnSend = (Button) findViewById(R.id.btnSend);
inputMsg = (EditText) findViewById(R.id.inputMsg);
listViewMessages = (ListView) findViewById(R.id.list_view_messages);
utils = new UtilsXD(getApplicationContext());
// Getting the person name from previous screen
Intent i = getIntent();
name = i.getStringExtra("name");
Integer.parseInt((sharedPrefs.getString("prefSyncAvatar", "1")));
btnSend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Sending message to web socket server
sendMessageToServer(utils.getSendMessageJSONXD(inputMsg
.getText().toString(), superString), superString);
utils.storePictureId((sharedPrefs.getString("prefSyncAvatar",
"1")));
// Clearing the input filed once message was sent
inputMsg.setText("");
}
});
listMessages = new ArrayList<Message>();
adapter = new MessagesListAdapter(this, listMessages, feedItems);
listViewMessages.setAdapter(adapter);
/**
* Creating web socket client. This will have callback methods
* */
client = new WebSocketClient(URI.create(WsConfig.URL_WEBSOCKET
+ URLEncoder.encode(name)), new WebSocketClient.Listener() {
#Override
public void onConnect() {
}
/**
* On receiving the message from web socket server
* */
#Override
public void onMessage(String message) {
Log.d(TAG, String.format("Got string message! %s", message));
parseMessage(message, superString);
// parseMessage(message,
// (sharedPrefs.getString("prefSyncAvatar", "1")));
}
#Override
public void onMessage(byte[] data) {
Log.d(TAG, String.format("Got binary message! %s",
bytesToHex(data)));
String hello = "99";
parseMessage(bytesToHex(data), superString);
// Message will be in JSON format
// parseMessage(bytesToHex(data),
// (sharedPrefs.getString("prefSyncAvatar", "1")));
}
/**
* Called when the connection is terminated
* */
#Override
public void onDisconnect(int code, String reason) {
String message = String.format(Locale.US,
"Disconnected! Code: %d Reason: %s", code, reason);
showToast(message);
//
// clear the session id from shared preferences
utils.storeSessionId(null);
}
#Override
public void onError(Exception error) {
Log.e(TAG, "Error! : " + error);
// showToast("Error! : " + error);
showToast("Are you sure you want to leave?");
}
}, null);
client.connect();
}
/**
* Method to send message to web socket server
* */
private void sendMessageToServer(String message, String id) {
if (client != null && client.isConnected()) {
client.send(message);
client.send(id);
}
}
/**
* Parsing the JSON message received from server The intent of message will
* be identified by JSON node 'flag'. flag = self, message belongs to the
* person. flag = new, a new person joined the conversation. flag = message,
* a new message received from server. flag = exit, somebody left the
* conversation.
* */
private void parseMessage(final String msg, String idINDEX) {
try {
jObj = new JSONObject(msg);
// JSON node 'flag'
String flag = jObj.getString("flag");
String id = idINDEX;
// if flag is 'self', this JSON contains session id
if (flag.equalsIgnoreCase(TAG_SELF)) {
String sessionId = jObj.getString("sessionId");
// Save the session id in shared preferences
utils.storeSessionId(sessionId);
Log.e(TAG, "Your session id: " + utils.getSessionId());
} else if (flag.equalsIgnoreCase(TAG_NEW)) {
// If the flag is 'new', new person joined the room
String name = jObj.getString("name");
String message = jObj.getString("message");
// number of people online
String onlineCount = jObj.getString("onlineCount");
showToast(name + message + ". Currently " + onlineCount
+ " people online!");
} else if (flag.equalsIgnoreCase(TAG_MESSAGE)) {
// if the flag is 'message', new message received
String fromName = name;
String message = jObj.getString("message");
String sessionId = jObj.getString("sessionId");
// switch (Integer.parseInt((sharedPrefs.getString(
// "prefSyncAvatar", "1"))))
boolean isSelf = true;
switch (Integer.parseInt(utils.getPictureId())) {
case 1:
profilePic = "http://clxxxii.vm-host.net/clxxxii/citychatlion.png";
break;
case 2:
profilePic = "http://clxxxii.vm-host.net/clxxxii/citychatmatt.png";
break;
case 3:
profilePic = "http://clxxxii.vm-host.net/clxxxii/citychatroboman.png";
break;
case 4:
profilePic = "http://clxxxii.vm-host.net/clxxxii/citychatalien.png";
break;
case 5:
profilePic = "http://clxxxii.vm-host.net/clxxxii/citychatkitty.png";
break;
case 10:
profilePic = "http://clxxxii.vm-host.net/clxxxii/citychatkitty.png";
break;
}
// Checking if the message was sent by you
if (!sessionId.equals(utils.getSessionId())) {
fromName = jObj.getString("name");
// profilePic = jObj.getString("profilePic");
//
//
//
//
jObj.getString("message");
isSelf = false;
profilePic = "http://clxxxii.vm-host.net/clxxxii/citychatalien.png";
}
// profilePic =
// "http://clxxxii.vm-host.net/clxxxii/citychatlion.png";
Integer.parseInt(utils.getPictureId());
String name = "clxxxii";
String image = "http://i.huffpost.com/gen/1716876/thumbs/o-ATLANTA-TRAFFIC-facebook.jpg";
String status = "status";
String timeStamp = "1403375851930";
String url = "url";
// Message m = new Message(fromName, message, isSelf);
Message m = new Message(fromName, message, isSelf, id, name,
image, status, profilePic, timeStamp, url);
// Appending the message to chat list
appendMessage(m);
} else if (flag.equalsIgnoreCase(TAG_EXIT)) {
// If the flag is 'exit', somebody left the conversation
String name = jObj.getString("name");
String message = jObj.getString("message");
showToast(name + message);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
///////// I've updated the socket server from the first project. /////// I've added the JSON value "id" successfully /// But I how do I change the value without having to type in "5" please see below..
//
This is the JSONutilty method I changed.
//
public String getSendAllMessageJson(String sessionId, String fromName,
String message, String photoId) {
String json = null;
try {
JSONObject jObj = new JSONObject();
jObj.put("flag", FLAG_MESSAGE);
jObj.put("sessionId", sessionId);
jObj.put("name", fromName);
jObj.put("message", message);
jObj.put("id", photoId);
json = jObj.toString();
} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
}
This is the method that is being used by SocketServer. I can successfully send a message from this activity, to the utility method to send over the network.
// Normal chat conversation message
json = jsonUtils //
.getSendAllMessageJson(sessionId, name, message, "5");
How can I retrieve a value sent over the network to place in spot where I have "5" instead of hard coding it?
Thanks!!!
jobj doesn't have the value id. Example of the JSON object looks like this:
{
"message": " joined conversation!",
"flag": "new",
"sessionId": "4",
"name": "Ravi Tamada",
"onlineCount": 6
}
(as shown in the part1 of the same tutorial).
That solves the first issue of onlineCount and sessionId.
Thanks #miselking, you where correct, The server was missing the JSON string "id". To actually solve the problem of post.
"I want to send more than one "String" at a time to the server. I'm having trouble figuring that out."
This is how you do it.
Step 1)
Adding the string photoId to the method
public String getSendAllMessageJson(String sessionId, String fromName,
String message, String photoId) {
String json = null;
try {
JSONObject jObj = new JSONObject();
jObj.put("flag", FLAG_MESSAGE);
jObj.put("sessionId", sessionId);
jObj.put("name", fromName);
jObj.put("message", message);
jObj.put("id", photoId);
json = jObj.toString();
} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
}
Step 2)
Add the string to the correct sting to the method.
String json = null;
json = jsonUtils
.getSendAllMessageJson(sessionId, name, message,
photoId);
Step 3) Parse the JSON
try {
JSONObject jObj = new JSONObject(message);
msg = jObj.getString("message");
photoId = jObj.getString("id");
} catch (JSONException e) {
e.printStackTrace();
}