Storing UDID in a database server - Android - javascript

I have generated a UDID string on the client side of Android. I need to send this to the javascript side so that it could communicate to the database server (via php) in order to store this UDID.
Is there a way to do it either directly (by avoiding php) or otherwise?
** My Android application has a WebView

Post to http with params:
public void postData() {
// Create a new HttpClient and Post Header
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.yoursite.com/yourexample.php");
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("UDID", "12345"));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
}
}
for your server side maybe it would be useful to learn somethings about web api's. take a look at this 2 links to start from some place:
Creating a RESTful API with PHP
[GUIDE] Android Client-Server Communication (PHP-MYSQL REST API)
You should show what you have already done, take a look at this to make better - to the point- questions

If you want to store data in a database from an Android app, without having to learn a server-side language, the simplest soulution is to use a MBaaS (Mobile Backend as a service) like :
Firebase
Appback
If you want to have lower fees you could also host your own solution but this could get more complicated:
http://hood.ie/
http://firehose.io/
http://remotestorage.io/
http://socky.org/
http://sockethub.org/
http://deployd.com/
My personal preference is Hoodie.
You could also generate your own RESTful API using Node.js + Express with MongoDB :
Yeoman generator for RESTful API

Related

How to connect android studio (developing mobile apps) with phpmyadmin database in a server? [duplicate]

Android 3.3 API 18
Hello,
I am developing my first App using android. The App will have to connect to an online database to store user data.
I am looking for a cloud storage with a MySQL database included. However, can my App connect directly to this MySQL database and push and pull data from it? Or is there other things I need to do?
Many thanks for any suggestions,
Yes you can do that.
Materials you need:
WebServer
A Database Stored in the webserver
And a little bit android knowledge :)
Webservices (json ,Xml...etc) whatever you are comfortable with
1. First set the internet permissions in your manifest file
<uses-permission android:name="android.permission.INTERNET" />
2. Make a class to make an HTTPRequest from the server
(i am using json parisng to get the values)
for eg:
public class JSONfunctions {
public static JSONObject getJSONfromURL(String url) {
InputStream is = null;
String result = "";
JSONObject jArray = null;
// Download JSON data from URL
try {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
} catch (Exception e) {
Log.e("log_tag", "Error in http connection " + e.toString());
}
// Convert response to string
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
result = sb.toString();
} catch (Exception e) {
Log.e("log_tag", "Error converting result " + e.toString());
}
try {
jArray = new JSONObject(result);
} catch (JSONException e) {
Log.e("log_tag", "Error parsing data " + e.toString());
}
return jArray;
}
}
3. In your MainActivity Make an object of the class JsonFunctions and pass the url as an argument from where you want to get the data
eg:
JSONObject jsonobject;
jsonobject = JSONfunctions.getJSONfromURL("http://YOUR_DATABASE_URL");
4. And then finally read the jsontags and store the values in an arraylist and later show it in listview if you want
and if you have any problem you can follow this blog
he gives excellent android tutorials AndroidHive
Since the above answer i wrote was long back and now HttpClient, HttpPost,HttpEntity have been removed in Api 23. You can use the below code in the build.gradle(app-level) to still continue using org.apache.httpin your project.
android {
useLibrary 'org.apache.http.legacy'
signingConfigs {}
buildTypes {}
}
or You can use HttpURLConnection like below to get your response from server
public String getJSON(String url, int timeout) {
HttpURLConnection c = null;
try {
URL u = new URL(url);
c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setRequestProperty("Content-length", "0");
c.setUseCaches(false);
c.setAllowUserInteraction(false);
c.setConnectTimeout(timeout);
c.setReadTimeout(timeout);
c.connect();
int status = c.getResponseCode();
switch (status) {
case 200:
case 201:
BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line+"\n");
}
br.close();
return sb.toString();
}
} catch (MalformedURLException ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
} finally {
if (c != null) {
try {
c.disconnect();
} catch (Exception ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
}
}
}
return null;
}
or You can use 3rd party Library like Volley, Retrofit to call the webservice api and get the response and later parse it with using FasterXML-jackson, google-gson.
What you want to do is a bad idea. It would require you to embed your username and password in the app. This is a very bad idea as it might be possible to reverse engineer your APK and get the username and password to this publicly facing mysql server which may contain sensitive user data.
I would suggest making a web service to act as a proxy to the mysql server. I assume users need to be logged in, so you could use their username/password to authenticate to the web service.
You can use PHP, JSP, ASP or any other server side script to connect with mysql database and and return JSON data that you can parse it to in your android app this link how to do it
step 1 : make a web service on your server
step 2 : make your application make a call to the web service and receive result sets
Yes definitely you can connect to the MySql online database for that you need to create a web service. This web service will provide you access to the MySql database. Then you can easily pull and push data to MySql Database. PHP will be a good option for creating web service its simple to implement. Good luck...
you can definitely make such application, you need to make http conection to the database, by calling a php script which will in response run specific queries according to your project, and generated the result in the form of xml, or json formate , whihc can be displayed on your android application!.
for complete tutorial on how to connect android application to mysql i would recommend to check out this tutorila
It is actually very easy. But there is no way you can achieve it directly. You need to select a service side technology. You can use anything for this part. And this is what we call a RESTful API or a SOAP API. It depends on you what to select.
I have done many project with both. I would prefer REST.
So what will happen you will have some scripts in your web server, and you know the URLs. For example we need to make a user registration. And for this we have
mydomain.com/v1/userregister.php
Now from the android side you will send an HTTP request to the above URL. And the above URL will handle the User Registration and will give you a response that whether the operation succeed or not.
For a complete detailed explanation of the above concept. You can visit the following link.
**Android MySQL Tutorial to Perform CRUD Operation**
Look at this online backend.
Parse.com
They offer push notifications, social integration, data storage, and the ability to add rich custom logic to your app’s backend with Cloud Code.

How to connect jade-agents (java) and babylon.js (html/javascript) - Servlet to html?

Summary:
IDE: Eclipse
Server: Java
Client: Html/Javascript
After sending data via ajax/jquery to a servlet and using JadeGateway to send those information to an agent, resulting data should go back to html/javascript.
I need a way to connect either a servlet or an agent with an existing and running html file (ofc without reloading the page).
Background:
I want to create a agent based game using babylon.js and jade/pug (let's call it jade).
During a game, information about game states should go to an agent, so that he could figure out what to do (e.g. create more units or attack). After this, the agent needs to send the information to the game, to call the appropriate function.
What I did so far:
I connected the game (html/javascript) with a servlet using ajax. There I used JadeGateway to send an ACLMessage to an agent.
I also used websockets to connect client/server but this method is too limited for what i need i think.
I now need a tool/method or tips to send information from an agent or the servlet. Both is possible, because the agent can send information back to the jadegateway agent/servlet.
I know how to use ajax to call a servlet from html and right back, but now the information is tranfered to some other classes, so that didn't work anymore.
In the babylon.js scene.registerBeforeRender function I do this:
$.ajax({
url: "AgentListenerServlet",
type: "POST",
data: {playerString: convertPlayerToJson(player1)},
success: function(data) {
alert(data.command)
},
error: function() {
alert("Listener Failed")
}
});
Sending message to an agent via jadegateway:
JadeGateway.execute(new CyclicBehaviour() {
public void action() {
final ACLMessage msgSend = new ACLMessage(ACLMessage.INFORM);
msgSend.setContent(message);
msgSend.addReceiver(new AID("First", AID.ISLOCALNAME));
myAgent.send(msgSend);
final ACLMessage msgReceive = myAgent.receive();
if(msgReceive != null && msgReceive.getContent() != null){
//used this as immediate answer for ajax success function, but maybe it can also be used to send the returning agent message?
Map <String, Object> map = new HashMap<String, Object>();
map.put("command", "information");
write(response, map);
} else {
block();
}
}
});
private void write(HttpServletResponse response, Map<String, Object> map) throws IOException {
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(new Gson().toJson(map));
}
agent code (simplified):
public void action() {
final ACLMessage msgSend = new ACLMessage(ACLMessage.INFORM); //sending message
final ACLMessage msgReceive = receive(); //receiving message
//Here i get information out of sent json objects from jadegateway
//Maybe here send handled information back to html?
} else {
block();
}
}
Maybe showing this codes is not necessary, because they are working and the problem is not there, but the template for asking a question requested these.
Expected and results:
So the problem is not, that it isn't working, but that I need to know how to continue.
I don't know what I expect, because i don't know the possibilities.
Maybe, what would help me, is to send a simple string from the agent or servlet that i can call with the alert function in the game.
Or maybe i should ask this: is it possible to get an answer in ajax (success function) after the data was sent to the servlet and passed to an agent?
Sorry for the huge spam. Hope I made my problem clear.
No need to reply, websockets is the solution after all.
I just figured out, that you can push data from server to client without a client request with
session.getBasicRemote().sendText(msgReceive.getContent());
The session is automatically generated and you can reveice it with websockets onopen method:
#OnOpen
public void onOpen(Session session){
this.session = session;
}

CometD client Java APIn how to?

For my project I have to use pubsub and cometD subscriber.
I use Oracle Weblogic application server for two applciations.
One of them publish some messages to pubsubs channels and the other one subscribe to channels to display the messages.
My pubsub server is on the weblogic application server too and configured with some xml files (weblogic.xml and weblogic-pubsub.xml).
Here is how my pubsub server is configured (weblogic-pubsub.xml):
<wlps:channel>
<wlps:channel-pattern>/gip/**</wlps:channel-pattern>
</wlps:channel>
<wlps:channel-constraint>
<wlps:channel-resource-collection>
<wlps:channel-resource-name>all-permissions</wlps:channel-resource-name>
<wlps:description>Grant all permissions for everything by everyone</wlps:description>
<wlps:channel-pattern>/gip/*</wlps:channel-pattern>
</wlps:channel-resource-collection>
</wlps:channel-constraint>
And it works well because my second application can susbscribe to channel with the cometD subscirber javascript API and dojo toolkit.
So now the subscription is done client side of my web application thanks to this Javascript API.
Here is how the subscription is done client side (Javascript API) with the dojo toolkit:
//Initialize Dojo (CometD) for pubsub events
dojo.require("dojo.io.script");
dojo.require("dojox.cometd");
dojo.require("dojox.cometd.callbackPollTransport");
dojo.addOnLoad(function ()
{
console.log("on load dojo");
dojox.cometd.init("/WebInterface/cometd", {
});
dojox.cometd.subscribe("/gip/**", onEvent);
initMap();
});
This client side implementation works well, the onEvent() function is well fired when messages reach the pubsub channel.
Now, I would like the subscription and the message handling are done server side. For this, I understood that CometD has also a client Java API allowing to subscribe to pubsub channel and to handle the messages.
But I have not succeeded to do that.
Here is now what I tried to do for the server side following the CometD 3 documentation (https://docs.cometd.org/current/reference/#_java_client) :
import com.vaadin.ui.CustomComponent;
import java.util.HashMap;
import java.util.Map;
import org.cometd.bayeux.Channel;
import org.cometd.bayeux.Message;
import org.cometd.bayeux.client.ClientSession;
import org.cometd.bayeux.client.ClientSessionChannel;
import org.cometd.client.BayeuxClient;
import org.cometd.client.transport.ClientTransport;
import org.cometd.client.transport.LongPollingTransport;
import org.eclipse.jetty.client.HttpClient;
public class WireServerCometD extends CustomComponent {
private static final String CHANNEL = "/gip";
private final ClientSessionChannel.MessageListener gipListener = new GIPListener();
public WireServerCometD() {
System.out.println("Wire CometD constructor");
setSizeFull();
setWidth(50, Unit.PERCENTAGE);
setHeight(300, Unit.PIXELS);
addStyleName("customBackground");
try {
// Create (and eventually set up) Jetty's HttpClient:
HttpClient httpClient = new HttpClient();
// Here set up Jetty's HttpClient, for example:
// Prepare the transport
Map<String, Object> options = new HashMap<String, Object>();
ClientTransport transport = new LongPollingTransport(options, httpClient);
// Create the BayeuxClient
ClientSession client = new BayeuxClient("http://localhost:8080/WebInterface/cometd", transport);
client.getChannel(CHANNEL).addListener(new ClientSessionChannel.MessageListener() {
public void onMessage(ClientSessionChannel channel, Message message) {
if (message.isSuccessful()) {
// Here handshake is successful
System.out.println("Handshake is successfull");
}
}
});
client.handshake();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static class GIPListener implements ClientSessionChannel.MessageListener {
public void onMessage(ClientSessionChannel channel, Message message) {
System.out.println("message received");
}
}
}
This is a Vaadin framework component, the channel subscription and message listener are done in the try block.
I have the following error at the code line HttpClient httpClient = new HttpClient(); :
SEVERE:
java.lang.IncompatibleClassChangeError: org/eclipse/jetty/client/HttpClient
And the onMessage function is never fired ...
Can you bring me some help please ?
Thank you,
First of all, I think WebLogic may ship a very old version of CometD, or a very customized one that does not match the official one from the CometD project.
The dojox.cometd.callbackPollTransport was not something that ever existed in the CometD project, it was probably a draft attempt when CometD was 0.x, or something that was not officially released, or something created by WebLogic.
Your chances to have an official CometD 3.x client work with the "CometD" shipped by WebLogic are very slim. I doubt they are compatible.
Furthermore, I don't think Vaadin will be able to translate the component you wrote above in JavaScript.
A while back, people wrote bindings for CometD in JavaScript, but those never entered officially the CometD project (lack of traction, see https://github.com/cometd/cometd/issues/63), so I am not sure in what state they are now.
The IncompatibleClassChangeError is probably due to the fact that you are using a JDK older than JDK 7, and CometD 3.x only works with JDK 7+.
I'm afraid you will have to rethink the whole system.
I would suggest to stick with the official CometD on the server (not the one shipped by WebLogic), and if you really have to use Vaadin/GWT have a look at how people wrote those bindings in the past, and perhaps replicate them if you can't use those libraries.
Once you have the Vaadin/GWT bindings in place, and the official CometD in the server, and JDK 7+, you should be good.

Connecting to websocket using C# (I can connect using JavaScript, but C# gives Status code 200 error)

I am new in the area of websocket.
I can connect to websocket server using JavaScript using this code:
var webSocket = new WebSocket(url);
But for my application, I need to connect to the same server using c#. The code I am using is:
ClientWebSocket webSocket = null;
webSocket = new ClientWebSocket();
await webSocket.ConnectAsync(new Uri(url), CancellationToken.None);
3rd line of the code results following error:
"Server returned status code 200 when status code 101 was expected"
After little bit of survey, I realised that somehow server can't switch http protocol to websocket protocol during connection process.
Am I doing anything stupid in my C# code or there is something going wrong with the server. I don't have any access to the server, as the url I am using is a third party one .
Could you please give me any suggestion regarding the issue?
TL; DR:
Use ReceiveAsync() in loop until Close frame is received or CancellationToken is canceled. That's how you get your messages. Sending is straightworward, just SendAsync(). Do not use CloseAsync() before CloseOutputAsync() - because you want to stop your receiving loop first. Otherwise - either the CloseAsync() would hang, or if you use CancellationToken to quit ReceiveAsync() - the CloseAsync() would throw.
I learned a lot from https://mcguirev10.com/2019/08/17/how-to-close-websocket-correctly.html .
Full answer:
Use Dotnet client, here, have an example cut out from my real life code, that illustrate how the handshaking is made. The most important thing most people don't understand about how the thing operates is that there is no magic event when a message is received. You create it yourself. How?
You just perform ReceiveAsync() in a loop that ends, when a special Close frame is received. So when you want to disconnect you have to tell the server you close with CloseOutputAsync, so it would reply with a similar Close frame to your client, so it would be able to end receiving.
My code example illustrates only the most basic, outer transmission mechanism. So you send and receive raw binary messages. At this point you cannot tell the specific server response is related to the specific request you've sent. You have to match them yourself after coding / decoding messages. Use any serialization tool for that, but many crypto currency markets use Protocol Buffers from Google. The name says it all ;)
For matching any unique random data can be used. You need tokens, in C# I use Guid class for that.
Then I use request / response matching to make request work without dependency on events. The SendRequest() methods awaits until matching response arrives, or... the connection is closed. Very handy and allows to make way more readable code than in event-based approach. Of course you can still invoke events on messages received, just make sure they are not matched to any requests that require response.
Oh, and for waiting in my async method I use SemaphoreSlim. Each request puts its own semaphore in a special dictionary, when I get the response, I find the entry by the response token, release the semaphore, dispose it, remove from the dictionary. Seems complicated, but it's actually pretty simple.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
namespace Example {
public class WsClient : IDisposable {
public int ReceiveBufferSize { get; set; } = 8192;
public async Task ConnectAsync(string url) {
if (WS != null) {
if (WS.State == WebSocketState.Open) return;
else WS.Dispose();
}
WS = new ClientWebSocket();
if (CTS != null) CTS.Dispose();
CTS = new CancellationTokenSource();
await WS.ConnectAsync(new Uri(url), CTS.Token);
await Task.Factory.StartNew(ReceiveLoop, CTS.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
public async Task DisconnectAsync() {
if (WS is null) return;
// TODO: requests cleanup code, sub-protocol dependent.
if (WS.State == WebSocketState.Open) {
CTS.CancelAfter(TimeSpan.FromSeconds(2));
await WS.CloseOutputAsync(WebSocketCloseStatus.Empty, "", CancellationToken.None);
await WS.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
}
WS.Dispose();
WS = null;
CTS.Dispose();
CTS = null;
}
private async Task ReceiveLoop() {
var loopToken = CTS.Token;
MemoryStream outputStream = null;
WebSocketReceiveResult receiveResult = null;
var buffer = new byte[ReceiveBufferSize];
try {
while (!loopToken.IsCancellationRequested) {
outputStream = new MemoryStream(ReceiveBufferSize);
do {
receiveResult = await WS.ReceiveAsync(buffer, CTS.Token);
if (receiveResult.MessageType != WebSocketMessageType.Close)
outputStream.Write(buffer, 0, receiveResult.Count);
}
while (!receiveResult.EndOfMessage);
if (receiveResult.MessageType == WebSocketMessageType.Close) break;
outputStream.Position = 0;
ResponseReceived(outputStream);
}
}
catch (TaskCanceledException) { }
finally {
outputStream?.Dispose();
}
}
private async Task<ResponseType> SendMessageAsync<RequestType>(RequestType message) {
// TODO: handle serializing requests and deserializing responses, handle matching responses to the requests.
}
private void ResponseReceived(Stream inputStream) {
// TODO: handle deserializing responses and matching them to the requests.
// IMPORTANT: DON'T FORGET TO DISPOSE THE inputStream!
}
public void Dispose() => DisconnectAsync().Wait();
private ClientWebSocket WS;
private CancellationTokenSource CTS;
}
}
BTW, why use other libraries than the .NET built in? I can't find any reason other than maybe poor documentation of the Microsoft's classes. Maybe - if for some really weird reason you would want to use modern WebSocket transport with an ancient .NET Framework ;)
Oh, and I haven't tested the example. It's taken from the tested code, but all inner protocol parts were removed to leave only the transport part.
Since WebsocketSharp is not .NET Core compatible I suggest using websocket-client instead.
Here's some sample code
static async Task Main(string[] args)
{
var url = new Uri("wss://echo.websocket.org");
var exitEvent = new ManualResetEvent(false);
using (var client = new WebsocketClient(url))
{
client.MessageReceived.Subscribe(msg => Console.WriteLine($"Message: {msg}"));
await client.Start();
await client.Send("Echo");
exitEvent.WaitOne();
}
Console.ReadLine();
}
Be sure to use ManualResetEvent. Otherwise it doesn't work.
If you connect with a WebSocket client and you get an HTTP 200 as response, means that probably you are connecting to the wrong place (host, path and/or port).
Basically, you are connecting to a normal HTTP endpoint that is not understanding your WebSocket requirement, and it is just returning the "OK" response (HTTP 200). Probably the WebSocket server runs in another port or path in the same server.
Check your URL.
Not quite sure what happened to WebSocketSharp nuget package, however I noticed that now WebSocket# is showing up as most relevant result in nuget repo. It took me some time before I realized that Connect() is now returning Task, hopefully this example will be useful to someone:
using System;
using System.Threading.Tasks;
using WebSocketSharp;
namespace Example
{
class Program
{
private static void Main(string[] args)
{
using (var ws = new WebSocket(url: "ws://localhost:1337", onMessage: OnMessage, onError: OnError))
{
ws.Connect().Wait();
ws.Send("Hey, Server!").Wait();
Console.ReadKey(true);
}
}
private static Task OnError(ErrorEventArgs errorEventArgs)
{
Console.Write("Error: {0}, Exception: {1}", errorEventArgs.Message, errorEventArgs.Exception);
return Task.FromResult(0);
}
private static Task OnMessage(MessageEventArgs messageEventArgs)
{
Console.Write("Message received: {0}", messageEventArgs.Text.ReadToEnd());
return Task.FromResult(0);
}
}
}
All the libraries mentioned above are Wrappers. The .Net Frameworks class doing this is System.Net.WebSockets.ClientWebSocket
Websocket URLs should start with ws:// or wss:// where the latter is secure websocket.

how to send message to particular websocket connection using java server

I am new to WebSockets.
I have already made a simple server-client chat in WebSockets.
And now I am trying to make client-server-client chat application.
I have a question that in java server how can we send a message to particular WebSocket connection.
If user-A want to send a message to User-B.
Then how can I manage that User-B is using this or that connection or send a message to that particular connection?
I am searching too much for this on google but could not find anything good.
You have to design an architecture for that.
When a client establishes a connection with the server (opens the WebSocket), the server has to keep the connection somewhere (howsoever you're identifying a specific connection with the Java backend you're using), in a data structure that will depend on what you're trying to do. A good identifier would be an ID the user provides (like a nickname that's not already picked by another peer connected to the same server). Otherwise, simply use the socket object as a unique identifier and, when listing other users on the frontend, associate them with their unique identifier so that a client can send a message to a specific peer.
A HashMap would be a good choice for a data structure if a client is going to chat with another specific client, as you can map the unique ID of a client to the socket and find an entry with in O(1) in a hash table.
If you want to broadcast a message from a client to all other clients, although a HashMap would also work pretty well (with something like HashMap.values()), you may use a simple List, sending the incoming message to all connected clients except the original sender.
Of course, you also want to remove a client from the data structure when you lose connection with it, which is easy using a WebSocket (the Java framework you are using should call you back when a socket closes).
Here's an (almost complete) example using a Jetty 9 WebSocket (and JDK 7):
package so.example;
import java.io.IOException;
import java.util.HashMap;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
#WebSocket
public class MyWebSocket {
private final static HashMap<String, MyWebSocket> sockets = new HashMap<>();
private Session session;
private String myUniqueId;
private String getMyUniqueId() {
// unique ID from this class' hash code
return Integer.toHexString(this.hashCode());
}
#OnWebSocketConnect
public void onConnect(Session session) {
// save session so we can send
this.session = session;
// this unique ID
this.myUniqueId = this.getMyUniqueId();
// map this unique ID to this connection
MyWebSocket.sockets.put(this.myUniqueId, this);
// send its unique ID to the client (JSON)
this.sendClient(String.format("{\"msg\": \"uniqueId\", \"uniqueId\": \"%s\"}",
this.myUniqueId));
// broadcast this new connection (with its unique ID) to all other connected clients
for (MyWebSocket dstSocket : MyWebSocket.sockets.values()) {
if (dstSocket == this) {
// skip me
continue;
}
dstSocket.sendClient(String.format("{\"msg\": \"newClient\", \"newClientId\": \"%s\"}",
this.myUniqueId));
}
}
#OnWebSocketMessage
public void onMsg(String msg) {
/*
* process message here with whatever JSON library or protocol you like
* to get the destination unique ID from the client and the actual message
* to be sent (not shown). also, make sure to escape the message string
* for further JSON inclusion.
*/
String destUniqueId = ...;
String escapedMessage = ...;
// is the destination client connected?
if (!MyWebSocket.sockets.containsKey(destUniqueId)) {
this.sendError(String.format("destination client %s does not exist", destUniqueId));
return;
}
// send message to destination client
this.sendClient(String.format("{\"msg\": \"message\", \"destId\": \"%s\", \"message\": \"%s\"}",
destUniqueId, escapedMessage));
}
#OnWebSocketClose
public void onClose(Session session, int statusCode, String reason) {
if (MyWebSocket.sockets.containsKey(this.myUniqueId)) {
// remove connection
MyWebSocket.sockets.remove(this.myUniqueId);
// broadcast this lost connection to all other connected clients
for (MyWebSocket dstSocket : MyWebSocket.sockets.values()) {
if (dstSocket == this) {
// skip me
continue;
}
dstSocket.sendClient(String.format("{\"msg\": \"lostClient\", \"lostClientId\": \"%s\"}",
this.myUniqueId));
}
}
}
private void sendClient(String str) {
try {
this.session.getRemote().sendString(str);
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendError(String err) {
this.sendClient(String.format("{\"msg\": \"error\", \"error\": \"%s\"}", err));
}
}
The code is self explanatory. About JSON formatting and parsing, Jetty has some interesting utilities within package org.eclipse.jetty.util.ajax.
Also note that if your WebSocket server framework is not thread-safe, you will need to synchronize the data structure to make sure there's no data corruption (here MyWebSocket.sockets).

Categories

Resources