Getting membername from JsonObject - java

I'm using a threaded server to get data out of an SQLite database, I have created in this case Drivers to get the various strings and ints from the database. On the server I'm creating a HashMap.
The HashMap is sent to a client handler where I create a Json Object and then override the run method to send it to the client.
On the client I'm using swing and creating buttons and tables for a GUI. When a button is pressed it calls this method which parses the reply into a Json object:
private void showDrivers() {
if (printWriter != null && bufferedReader != null) {
String toSend = "get";
printWriter.println(toSend);
String reply = null;
statusLabel.setText("Status: wait for server to reply");
try {
reply = bufferedReader.readLine();
statusLabel.setText("Status: received reply from server");
JsonParser.parseString(reply).getAsJsonObject();
} catch (IOException ex) {
statusLabel.setText("IOException " + ex);
}
System.out.println(jsonDriver);
JsonObject jsonReply = JsonParser.parseString(reply).getAsJsonObject();
JsonArray jsonDriverArray = jsonReply.getAsJsonArray("driverId");
System.out.println(jsonDriverArray);
}
}
I'm trying to get all the members from the array and then place them in a table, using the console to check that I'm actually getting the data from the array.
I have run everything in the debugger, making sure that I'm actually sending the data to the client, which I am. I expected that by using this:
JsonArray jsonDriverArray = jsonReply.getAsJsonArray("driverId");
It should get driverId 1, 2, 3, etc printing out to the console
System.out.println(jsonDriverArray);
Returns null, I thought that by using driverId as the member name it would get all the driverIds, likwise if I changed it to forenames it should get all the forenames.
In the debugger I get this which is stored in jsonReply:
1 -> {JsonObject#3072} "{"driverId":1,"driverRef":"hamilton","number":"44","code":"HAM","forename":"Lewis","surname":"Hamilton","dob":"07/01/1985","nationality":"British","url":"http://en.wikipedia.org/wiki/Lewis_Hamilton"}"
2 -> {JsonObject#3074} "{"driverId":2,"driverRef":"heidfeld","number":"","code":"HEI","forename":"Nick","surname":"Heidfeld","dob":"10/05/1977","nationality":"German","url":"http://en.wikipedia.org/wiki/Nick_Heidfeld"}"
3 -> {JsonObject#3076} "{"driverId":3,"driverRef":"rosberg","number":"6","code":"ROS","forename":"Nico","surname":"Rosberg","dob":"27/06/1985","nationality":"German","url":"http://en.wikipedia.org/wiki/Nico_Rosberg"}"
4 -> {JsonObject#3078} "{"driverId":4,"driverRef":"alonso","number":"14","code":"ALO","forename":"Fernando","surname":"Alonso","dob":"29/07/1981","nationality":"Spanish","url":"http://en.wikipedia.org/wiki/Fernando_Alonso"}"

Related

Async IO handling in Spring CLI with Java how to?

I have built a Spring CLI app which communicates with a server in an async fashion. The server was given, I did not create it, basically my app is required to open a TCP socket and send a JSON through it, then it sends back a JSON. It is mandatory not to use CLI parameters, but instead in the callback of the request I want to show the user a set of options for which he needs to select by inserting the corresponding number on the CLI. Most probably I'm not doing right something, because after entering the command, I see spring> on the console (this is an expected behavior) and it will block the async callback unless I press something (nothing is printed to the CLI when I receive the callback unless I press a bunch of enters - this is unexpected). To read from the console so far I used JLine's command line, what I would like to achieve is that when I get the response from the server and the callback is served, the console is given to the thread on which the callback is running (I instantly print the contents of the callback to the console, and I'm able to read the input without any tricks).
Some code:
public void runReceiver(){
receiverThread = new Thread(() -> {
byte[] digit = null;
int nb;
Iterator<CommandListener> it;
CommandListener listener;
String message;
List<CommandListener> listenersToRemove = new ArrayList<>();
while (true) {
try {
nb = communicatorInput.readInt();
digit = new byte[nb];
communicatorInput.readFully(digit);
} catch (IOException e) {
e.printStackTrace();
}
it = listeners.iterator();
while (it.hasNext()){
listener = it.next();
if (digit != null && digit.length > 0) {
message = new String(digit);
// the message was not acknowledged
if(message.contains("NACK")){
try {
listener.onError(message);
if (listener.isDone()) {
listenersToRemove.add(listener);
}
} catch (Exception e){
e.printStackTrace();
}
} else try {
listener.onCompleted(message);
} catch (InvalidObjectException e){
Main.logger.debug(String.format("Response could not be parsed as %s", listener.getCommandType()));
} catch (Exception e){
e.printStackTrace();
}
if (listener.isDone()) {
listenersToRemove.add(listener);
}
}
}
listeners.removeAll(listenersToRemove);
}
}, "receiverThread");
receiverThread.setDaemon(true);
receiverThread.start();
Then a CLI command (it expects no input here):
#CliCommand(value="start", help = "Starts stuff")
public void start() throws IOException, InterruptedException {
// this method is passed to the thread with the listener
getAvailabilities().updateAvailabilities("all", "all", "all", someListener);
}
And the callback for that listener:
someListener = new CommandListener() {
private String source = "Start some listener";
#Override
public void onCompleted(String r) throws IOException {
System.out.println("Which would you like to start?");
getAvailabilities().printAvailableBrands();
String brandNumber = "";
while(Objects.equals(brandNumber, "")){
System.out.println("Please enter the number of the Brand: ");
//when the callback arrives here I still only see ">spring:" and I get nothing printed on the console
brandNumber = cr.readLine();
if(!isInputAllowed(brandNumber, getAvailabilities().AvailableBrands.size())){
brandNumber = "";
}
}
BrandName = getAvailabilities().AvailableBrands.get(Integer.parseInt(brandNumber) - 1);
//updating the availabilities narrows down the things I list to the console, so I send an update after every selection
getAvailabilities().updateAvailabilities("all", BrandName, "all", getInterfaceListener);
done = true;
}
This might slightly connect to the issue that sometimes while debugging the CLI in Idea, it gets whacky inputs, eg. when I insert start it says No such command as ar, and if I press enter again, it'll say (some of) the rest: No such command as stt.
The problem is here:
if (listener.isDone()) {
listenersToRemove.add(listener);
}
If you want your listeners to be executed asynchronously you should not check their completion right away on the same thread as it will most likely return false.
The issue you might be having is that your listeners schedule some task but have no time to finish it as you immediately remove them after the loop:
listeners.removeAll(listenersToRemove);
It is very hard to tell what your logic is but I guess in the next while iteration your list is empty.

OptionalDataException Java

I am making a voice chat program and I got the OptionalDataException error and I never had this problem with the code before I added voice. The voice communication is handles by a different socket so I don't see the problem.
Code:
public class Client implements Runnable { // CLIENT
private String msg;
public void run() {
try {
s1 = new Socket(ipAddress, port);
s2 = new Socket(ipAddress, 1210);
o1 = new ObjectOutputStream(s1.getOutputStream());
o1.writeObject(name);
serverListModel.addElement(name);
i1 = new ObjectInputStream(s1.getInputStream());
Thread voice = new Thread(new ClientAudio());
voice.start();
while(true) {
msg = (String) i1.readObject();
String[] namePart = msg.split("-");
if(namePart[0].equals("AddName") && !namePart[1].equals(name) && !serverListModel.contains(namePart[1])) {
serverListModel.addElement(namePart[1]);
}
if(namePart[0].equals("RemoveName") && !namePart[1].equals(name)) {
serverListModel.removeElement(namePart[1]);
}
if(!msg.equals(null) && !namePart[0].equals("AddName") && !namePart[0].equals("RemoveName")) {
chatWindow.append(msg+"\n");
}
}
} catch (IOException | ClassNotFoundException e) {
chatWindow.append("Server Closed");
e.printStackTrace();
try {
s1.close();
} catch (IOException e1) {
e1.printStackTrace();
}
mainWindow(true);
}
}
}
flag
it was thrown at msg = (String) i1.readObject(); and it says
java.io.OptionalDataException
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1361)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at client.chat$Client.run(chat.java:319)
at java.lang.Thread.run(Thread.java:745)
From Oracle:
Exception indicating the failure of an object read operation due to unread primitive data, or the end of data belonging to a serialized object in the stream. This exception may be thrown in two cases:
An attempt was made to read an object when the next element in the stream is primitive data. In this case, the OptionalDataException's length field is set to the number of bytes of primitive data immediately readable from the stream, and the eof field is set to false.
An attempt was made to read past the end of data consumable by a class-defined readObject or readExternal method. In this case, the OptionalDataException's eof field is set to true, and the length field is set to 0.
It would appear that the next object in the Stream is not a String.
Is the server code under your control? Or do you at least have the source? If so, verify that String objects are the only ones being transmitted, or adjust your code to handle the actual objects/primitives being sent.
Edit
From your other question Voice Server not working:
byte[] soundData =
//...
o.write(soundData, 0, bytesRead);
... It looks like you are not writing String objects to the ObjectOutputStream. Actually, not even writing an Object, but raw bytes. You have to read data the same way you write it; anything else just won't work.

Getting a Json information

I am coding in Java and I'm using the minimal-json library. I am trying to get some information from a json text (idk if it's an array).
I'm trying to access the "game" value inside "stream", but I always get a crash by nullpointer or a parseexception.
Here is the json string I'm trying to get (From the Twitch Api):
{"_links":{"self":"https://api.twitch.tv/kraken/streams/hackerc0w","channel":"https://api.twitch.tv/kraken/channels/hackerc0w"},"stream":{"_id":13817896816,"game":"Programming","viewers":13,"created_at":"2015-04-01T13:54:54Z","video_height":1080,"average_fps":59.9235368156,"_links":{"self":"https://api.twitch.tv/kraken/streams/hackerc0w"},"preview":{"small":"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-80x45.jpg","medium":"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-320x180.jpg","large":"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-640x360.jpg","template":"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-{width}x{height}.jpg"},"channel":{"_links":{"self":"https://api.twitch.tv/kraken/channels/hackerc0w","follows":"https://api.twitch.tv/kraken/channels/hackerc0w/follows","commercial":"https://api.twitch.tv/kraken/channels/hackerc0w/commercial","stream_key":"https://api.twitch.tv/kraken/channels/hackerc0w/stream_key","chat":"https://api.twitch.tv/kraken/chat/hackerc0w","features":"https://api.twitch.tv/kraken/channels/hackerc0w/features","subscriptions":"https://api.twitch.tv/kraken/channels/hackerc0w/subscriptions","editors":"https://api.twitch.tv/kraken/channels/hackerc0w/editors","videos":"https://api.twitch.tv/kraken/channels/hackerc0w/videos","teams":"https://api.twitch.tv/kraken/channels/hackerc0w/teams"},"background":null,"banner":null,"broadcaster_language":"en","display_name":"hackerc0w","game":"Programming","logo":null,"mature":false,"status":"Coding a Chatbot in C","partner":false,"url":"http://www.twitch.tv/hackerc0w","video_banner":null,"_id":41236491,"name":"hackerc0w","created_at":"2013-03-11T17:08:22Z","updated_at":"2015-04-01T17:17:44Z","delay":0,"followers":28,"profile_banner":null,"profile_banner_background_color":null,"views":2948,"language":"de"}}}
The way I got if the livestreamer was live was like this:
public static boolean isStreamLive(String channel) {
try {
URL url = new URL(TWITCH_STREAM.replace("$c$", channel)) );
URLConnection conn = url.openConnection();
BufferedReader br = new BufferedReader( new InputStreamReader( conn.getInputStream() ));
String inputLine = br.readLine();
br.close();
JsonObject jsonObj = JsonObject.readFrom(inputLine);
return ( jsonObj.get("stream").isNull() )?false:true;
} catch (IOException e) {
return false;
}
}
And I mostly tried to copy the method above. But I have been checking the documentation of the library to know and I have been trying a lot of things.
The last was this:
public static String checkGame(String channel) {
if (!isStreamLive(channel)) return "El Estreamer esta Offline!";
try {
URL url = new URL( insertChannel(TWITCH_STREAM, channel) );
URLConnection conn = url.openConnection();
BufferedReader br = new BufferedReader( new InputStreamReader( conn.getInputStream() ));
String inputLine = br.readLine();
br.close();
JsonObject object = JsonObject.readFrom(inputLine);
JsonValue value = object.get("stream").asObject();
String msg = value.valueOf("status").toString();
return msg;
} catch (IOException e) {
return "Algo raro paso :/ error: 3";
}
return channel;
}
You've got two main problems with the code you've shown.
The first problem that you're having is that you're trying to get the status out of the wrong nested object. You're getting the stream object from the original json and then trying to get the value of the status key from that, but in the json you've posted status is part of a nested channel object.
The structure of the json object is like so:
{
"_links": { ... },
"stream": {
...
"channel":{
"_links": { ... },
...
"status":"Coding a Chatbot in C",
...
}
}
}
... so you can't get status directly from stream, you need to get channel from stream and get the status from that.
The second problem is that you're trying to use valueOf() to pull a value out of a JsonObject. valueOf() is a static method which creates a new object based on the supplied input, so it doesn't actually use data in the object you call it on.
Calling value.valueOf("status") will completely ignore data in value and create a new JsonObject containing the string "status".
If you want to get the value of a nested object, you need to drill down to it with a series of successive get("objName").asObject() calls, and then call .get("key") to obtain the value you want:
// hardcoded for example, actually would be read from BufferedReader
String inputLine = "{\"_links\":{\"self\":\"https://api.twitch.tv/kraken/streams/hackerc0w\",\"channel\":\"https://api.twitch.tv/kraken/channels/hackerc0w\"},\"stream\":{\"_id\":13817896816,\"game\":\"Programming\",\"viewers\":13,\"created_at\":\"2015-04-01T13:54:54Z\",\"video_height\":1080,\"average_fps\":59.9235368156,\"_links\":{\"self\":\"https://api.twitch.tv/kraken/streams/hackerc0w\"},\"preview\":{\"small\":\"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-80x45.jpg\",\"medium\":\"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-320x180.jpg\",\"large\":\"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-640x360.jpg\",\"template\":\"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-{width}x{height}.jpg\"},\"channel\":{\"_links\":{\"self\":\"https://api.twitch.tv/kraken/channels/hackerc0w\",\"follows\":\"https://api.twitch.tv/kraken/channels/hackerc0w/follows\",\"commercial\":\"https://api.twitch.tv/kraken/channels/hackerc0w/commercial\",\"stream_key\":\"https://api.twitch.tv/kraken/channels/hackerc0w/stream_key\",\"chat\":\"https://api.twitch.tv/kraken/chat/hackerc0w\",\"features\":\"https://api.twitch.tv/kraken/channels/hackerc0w/features\",\"subscriptions\":\"https://api.twitch.tv/kraken/channels/hackerc0w/subscriptions\",\"editors\":\"https://api.twitch.tv/kraken/channels/hackerc0w/editors\",\"videos\":\"https://api.twitch.tv/kraken/channels/hackerc0w/videos\",\"teams\":\"https://api.twitch.tv/kraken/channels/hackerc0w/teams\"},\"background\":null,\"banner\":null,\"broadcaster_language\":\"en\",\"display_name\":\"hackerc0w\",\"game\":\"Programming\",\"logo\":null,\"mature\":false,\"status\":\"Coding a Chatbot in C\",\"partner\":false,\"url\":\"http://www.twitch.tv/hackerc0w\",\"video_banner\":null,\"_id\":41236491,\"name\":\"hackerc0w\",\"created_at\":\"2013-03-11T17:08:22Z\",\"updated_at\":\"2015-04-01T17:17:44Z\",\"delay\":0,\"followers\":28,\"profile_banner\":null,\"profile_banner_background_color\":null,\"views\":2948,\"language\":\"de\"}}}";
JsonObject object = JsonObject.readFrom(inputLine); // parse json into object
JsonObject stream = object.get("stream").asObject(); // get "stream" sub-object
JsonObject channel = stream.get("channel").asObject(); // get "channel" sub-object
JsonValue status = channel.get("status"); // get the value of "status"
String msg = status.asString();
System.out.println(msg); // Coding a Chatbot in C

Persistent connection for repeated API calls

My android application is calling authenticated webservice API to download and sync records from server based on type of data.
For example:
Application calls the API in loop for different content types(Commerce, Science, Arts).
Now for each content type, application maintains last sync date so that it could sync data after that date only, for last one month.
The API call looks like:
private void loadData(){
String apiUrl = "";
String[] classArray = { "Commerce", "Science", "Arts" };
try{
for(int classIndex = 0; classIndex < classArray.length; classIndex++){
apiUrl = "http://www.myserver.com/datatype?class="+classArray[classIndex]+"&syncDate="+lastSyncDate;
String responseStr = getSyncData(apiUrl);
// Code to parse the JSON data and store it in SqliteDB.
}
}catch (Exception e) {
e.printStackTrace();
}
}
private String getSyncData(String webservice){
String line = "", jsonString = "";
try{
URL url = new URL(webservice);
HttpURLConnection conn = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); //using proxy may increase latency
conn.setInstanceFollowRedirects(false);
String userName = "abc#myserver.com", password = "abc123";
String base64EncodedCredentials = Base64.encodeToString((userName
+ ":" + password).getBytes(), Base64.URL_SAFE
| Base64.NO_WRAP);
conn.setRequestProperty("Authorization", "basic "+ base64EncodedCredentials);
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((line = rd.readLine()) != null) {
// Process line...
return line;
}
rd.close();
}
}catch (Exception e) {
e.printStackTrace();
}
return jsonString;
}
This method getSyncData() returns JSON response, which is parsed and stored in SqliteDb.
This code is working fine. But there is a slight performance issue when there are more content types in the classArray and each class have large data-set.
My question is :
To improve the overall performance of this process, can I open the connection
to www.myserver.com and pass the parameters with API call in loop to stop creating connection again and again for each content type.
Here I am using HttpURLConnection for API calls but can use any other technique in java.
Main purpose is to make the connection persistent so that application should not create it again and again for each call because for every call application creates a separate connection which is consuming more time.
I've done a similar processing before with webcall -> parse JSON -> store DB -> show/update views
and with a lot of testing and debugging I found out that what actually was slowing down the process was the store DB part, nothing to do with the webcall or JSON parsing.
I solved the situation by changing it to:
webcall -> parse JSON -> fire new thread to store DB -> show/update views
and with that simple change my results started appearing in a matter of 1sec (instead of the previous 5 to 6 seconds).
Hope it helps.
edit:
regarding the connection itself, you could use web-sockets (which are persistent, but not very well implemented in Android, you'll have to do quite an amount of manual parsing), so I suggest testing the DB thing first.

Android client/Java server socket; android sending but not receiving?

I've been searching for four hours and this is driving me nuts. I'm going to try keeping this short, if you need more information/code ask and I'll edit.
So I have an Android client that connects to a server using PrintWriter and BufferedReader. The way it works is it starts a new ASyncTask() to load the connection. When the connection is made, it sends a "Join" message to the server, and then loads a listen thread that has a while loop waiting for UserInput.readLine() != null, and once broken it returns a string that runs a process function that takes the string and does it's action, and reloads the listen task.
//Listener thread
class listen extends AsyncTask<Integer, Integer, Void> {
#Override
protected Void doInBackground(Integer... params) {
//Disconnect variable that's only turned true on backpress
if (!disconnect) {
try {
message = Connection.listen(); //socket object
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// async task finished
if (!disconnect) {
say("INCOMMING"); //easy-made function for Toast
input(message);
}
}
}
and in that Connection:
public String listen() throws IOException {
String userInput;
while ((userInput = in.readLine()) != null) {
}
return userInput;
}
Now in my server java app, I have a thread that loads up other connection threads into an ArrayList and acts as a headquarters to dispatch messages to all child clients
In my connection:
while ((inputLine = in.readLine()) != null) {
//Tells HQ to process string, with id being who it's coming from
hq.Process(id, inputLine);
if (!connected)
break;
}
in HQ object:
public void Process(int id, String str) {
String[] msg = str.split(","); //split message
String send = " "; //string I print to console
if (msg[0].equals("join")) {
send = msg[1] + " has joined!";
parent.seats[cnew.get(id).seat] = id;
cnew.get(id).sendData();
System.out.println(id);
}
And after join, the HQ tells that connection to send that player's information to the phone
public void sendData() {
out.println("chips," + chips); // Update chip count
//give player his cards
out.println("card," + hq.parent.gameCards.getCard(10) + ","
+ hq.parent.gameCards.getCard(11));
//a cry for help to get some output on the phone
out.println("error,SAY THIS");
// out.flush(); //commented out because it didn't help at all
System.out.println("sending id " + id); //debug checker (ignore this)
}
My problem is, it worked when I connected four phones and they all sent toasts to each other.
But as soon as I changed it to send back data as soon as the player joins, I'm not getting a response in Android at all.
I can't figure out why it's not working. On server side, it's going through everything (Checked with system.prints). The connection IS made, and when I click buttons on the phone the Server is outputting it's responses. But the phone is not receiving anything -- I still don't know if the server is failing to send or the phone is failing to read. Can you see anything in the code that may be causing this? Need to see more? Or have any tips on how to debug the connection status? The listen() task is never finishing it's execution anymore.
UPDATE: So I figured out it's probably to do with my while() loop on android side, doh, probably never breaking. Stupid mistake. But I tried to add this as a tester, and still nothing:
public String listen() throws IOException {
String userInput;
while ((userInput = in.readLine()) != null) {
if (userInput.length() > 2)
break;
}
return userInput;
}
UPDATE: Next desperate update -
When I hit "back" (which sends quit msg to server that closes connection, and calls out.close and the rest.close) then I get a never ending loop of "MSG" Toast's -- The Toast that I put when an input is recognized. Is a out.close causing a block?
So it turns out, println on the server's side wasn't printing a new line -- adding + "\n" at the end of the server's messages made it go through. Why? I don't know..

Categories

Resources