I have write a simple method to post data to URL and consume the output. I hava tried multiple ways to consume the out put but no success yet:
public void postToUrl(final String theurl, final String query, final Callable<Void> myMethod){
String urlData="";
new Thread(new Runnable() {
#Override
public void run() {
try {
String urlData="";
String url=baseurl+ theurl + "/?" +query;
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true);
connection.connect();
InputStream response = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(response));
String line="";
while ((line = reader.readLine()) != null) {
urlData += line;
}
reader.close();
// How to consume urlData here?
// myMethod.call(); not accepts parameter
try {
myMethod.call(urlData);
}catch (Exception e){
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}}
).start();
}
I have to wrap the method inside a runnable and can not expect a runnable method to return a value.
I tried to consume the output when it is ready inside the runnable but I need to call a third party method to pass the output. I found callable but it does not accept parameters.
I have read the accepted answer here but it needs to define a new class for every method.
I have read this Q/A but it suggest to define an interface instead of method that I believe is not the proper use of interface.
If this method is not the proper way to call and consume a url, how do you manage multiple client-server request in an application? Do you rewrite the codes above for every type of request? Do you really define a new class or new interface for every clien-server interactions?
Related
How to make a PUT request using HttpURLConnection with query parameters?
I am trying to consume a third party REST API using HttpURLConnection but when I try to pass the parameters in the URL, it doesn't work and throw an error as shown below:
The REST API Url could not be found in the mappings registry
This is the code block that doesn't work for me as of now:
URL url;
StringBuffer response = new StringBuffer();
try
{
url = new URL(" http://thirdparty.com/party/api/v2/ksp/12/ks");
HttpURLConnection httpURL = (HttpURLConnection) url.openConnection();
httpURL.setDoOutput(true);
httpURL.setRequestMethod("PUT");
StringBuilder sbUrl = new StringBuilder("parameter1_id=");
sbUrl.append(getParameter1Value())
.append("¶meter2_id=")
.append(getParameter2Value());
final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(httpURL.getOutputStream()));
writer.write(sbUrl.toString());
writer.flush();
writer.close();
// throw the exception here in case invocation of web service
if (httpURL.getResponseCode() != 200)
{
// throw exception
}
else
{
//SUCCESS
}
}
catch (IOException e)
{
}
When I provide these parameters in the Body as form-data parameters, the REST API seems provide the response.
My question here is that how do I make this work with HttpURLConnection?
What have I tried till now?
I have tried to modify the above to something like below, but it doesn't work.
try
{
url = new URL(" http://thirdparty.com/party/api/v2/ksp/12/ks");
HttpURLConnection httpURL = (HttpURLConnection) url.openConnection();
httpURL.setDoOutput(true);
httpURL.setRequestMethod("PUT");
httpURL.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + "----WebKitFormBoundarydklhfklsdfhlksh");
dataOutputStream = new DataOutputStream(urlConnection.getOutputStream());
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"parameter1_id\"");
dataOutputStream.writeBytes("\r\n" + "parameter1Value" +"\r\n");
dataOutputStream.writeBytes("--" + "----WebKitFormBoundarydklhfklsdfhlksh");
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"parameter2_id\"");
dataOutputStream.writeBytes("\r\n" + "parameter2Value" + "\r\n");
dataOutputStream.writeBytes("--" + "----WebKitFormBoundarydklhfklsdfhlksh" + "--");
dataOutputStream.flush();
dataOutputStream.close();
urlConnection.connect();
// throw the exception here in case invocation of web service
if (httpURL.getResponseCode() != 200)
{
// throw exception
}
else
{
//SUCCESS
}
}
catch (IOException e)
{
}
EDIT: It throws an error with response code as 500
EDIT: Just to clarify, I'm not trying to upload a file but trying to send the parameters inside the BODY (like Query parameters instead of being sent as URL parameters).
Any pointers or suggestions on this are very much appreciated.
You talk about 'query parameters' and 'parameters in the URL', but neither of the approaches you show does any such things. Both your approaches (try to) send parameters in the request body, aka 'entity', not in the URL. Although body contents may be involved in an application-level query, they are NOT query string aka query parameters at the HTTP level. You also ask 'how do I make this work with HttpURLConnection' as if that were a change or difference when both your attempts already use it.
Your first attempt looks almost correct. It should work if
you .setRequestProperty("Content-type", "application/x-www-form-urlencoded") (which is not automatic) and your values either are URLencoded or don't need it (no reserved characters) (depending on the server it may be enough to have no ampersand or equalsign)
Your second attempt also is fairly close. You need to write a boundary before the first part as well, and for each part after Content-disposition: form-data; name="blah" you need one CRLF to end that header line and a second CRLF to end the header block. (MIME multipart format allows multiple header lines in general, although in this case only one is needed.) And the end boundary should be followed by a CRLF (after the extra --).
Both only if you have the URL correct, of course. Nothing will work without the correct URL.
Best Method to Call WebService with HttpUrlConnection PUT Method
ApiListener apilistener=null;
public void updateWorker()
{
progressDialog = ProgressDialog.show(myContext, "Message",
progressDialog.setCancelable(false);
progressDialog.setCanceledOnTouchOutside(false);
Thread runThread = new Thread(new Runnable() {
#Override
public void run() {
HttpAppRequest http = new HttpAppRequest();
try {
JSONObject paramObject = new JSONObject();
JSONObject dataObject = new JSONObject();
dataObject.put("id", csId);
}
paramObject.put("data", dataObject);
Log.e(AppConstants.TAG, "Param = " + paramObject.toString());
AppResponse response = http.putJSONData(BASE_URL + "/updateapi", paramObject.toString(), true);
if (response.getStatusCode() == 200) {
String csUpdateResult = response.getContentData();
Log.e(AppConstants.TAG, csUpdateResult);
JSONObject updateObject = new JSONObject(csUpdateResult);
Message completeMessage = handler.obtainMessage(1, updateObject);
completeMessage.sendToTarget();
} else {
handler.sendEmptyMessage(-1);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
String csMessage = myContext.getResources().getString(R.string.id_network_response_failure);
Message completeMessage = handler.obtainMessage(0, csMessage);
completeMessage.sendToTarget();
}
}
});
runThread.start();
}
/*******************************************************************************************************/ Handler Api Response Here
Handler handler= new Handler() {
#Override
public void handleMessage(Message inputMessage) {
progressDialog.dismiss();
if (inputMessage.what == 1) {
try {
JSONObject msgObject = (JSONObject) inputMessage.obj;
if (msgObject.has("result")) {
JSONObject resultObject = msgObject.getJSONObject("result");
if (resultObject.has("status")) {
String csStatus = resultObject.getString("status");
if (csStatus.equalsIgnoreCase("success")) {
apilistener.onUpdate(resultObject.getString("msg"));
}
} else {
if(resultObject.has("status"))
{
apilistener.onFailed(resultObject.getString("reason"));
}
}
}
} catch (JSONException e) {
CommonMethods.showMessageBox("", e.getMessage(), myContext);
}
} else if (inputMessage.what == 0) {
String csMessage = (String) inputMessage.obj;
CommonMethods.showMessageBox("", csMessage, myContext);
}
}
};
//CallBack Listener to parent Activity/Fragment
//User listener like this
public interface ApiListener extends EventListener
{
void onSuccess(String msg);
void onFaiulure(String msg);
}
public void setListener(ApiListener listener)
{
apilistener=listener;
}
}
I have a RESTful webservice which I use for a server on NetBeans.
This webservice should get many requests from clients (multiplayer game).
I'm still new to this topic but if I understand it right- every call from clients to my webservice is a thread safe - because every connection to the web service is on a different thread (all my variables are inside the webservice methods) is this true?
And this brings me to my question:
Can I use wait(); inside a webservice method? let's say I'm waiting for two client connections, so the second connection will use notifyAll();
But since the webservice is not really a thread I don't know if it's possible to use these methods there? What should I use instead??
This is my webservice:
#Path("/w")
public class JSONRESTService {
String returned;
#POST
#Consumes("application/json")
#Path("/JSONService")
public String JSONREST(InputStream incomingData) {
StringBuilder JSONBuilder = new StringBuilder();
try {
BufferedReader in = new BufferedReader(new InputStreamReader(incomingData));
String line = null;
while ((line = in.readLine()) != null) {
JSONBuilder.append(line);
}
returned = "transfer was completed";
// This is what I'm trying to add but I know that I can't:
// count is a static variable, every new connection will increase this value
// only one player is connected
if (Utility.count == 1)
wait (); //wait for a 2nd player to connect to this webservice
// 2nd player is connected to this webservice
if (Utility.count == 2)
notifyAll (); // notify the 1st player
} catch (Exception e) {
System.out.println ("Error Parsing: - ");
returned ="error";
}
System.out.println ("Data Received: " + JSONBuilder.toString ());
return (returned);
}
}
Client:
JSONObject jsonObject = new JSONObject("string");
// Step2: Now pass JSON File Data to REST Service
try {
URL url = new URL("http://localhost:8080/w/JSONService");
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
out.write(jsonObject.toString());
out.close();
//string answer from server:
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuffer sb = new StringBuffer("");
String line="";
while ((line = in.readLine()) != null) {
sb.append(line);
System.out.println("\n"+line);
in.close();
} catch (Exception e) {
System.out.println("\nError while calling JSON REST Service");
System.out.println(e);
}
br.close();
} catch (Exception e) {
e.printStackTrace();
} } }`
You can always use wait() and notify() as it affects the thread the code is running on. Whether or not you should use it depends on the situation.
If you want a queue of players then use a queue :)
A little example I knocked up...
#Path("/w")
public class JSONRESTService {
private static BlockingQueue<Player> queue = new ArrayBlockingQueue<>(999);
#POST
#Consumes("application/json")
#Path("/JSONService")
public String JSONREST(InputStream incomingData) {
Player thisPlayer = ...; // Get player from session or something
System.out.println (thisPlayer.getName() + " starting...");
try {
if (queue.isEmpty()) {
System.out.println ("waiting for an opponent");
queue.add(thisPlayer);
synchronized (thisPlayer) {
thisPlayer.wait();
}
} else {
System.out.println ("get next in queue");
Player opponent = queue.take();
opponent.setOpponent(thisPlayer);
thisPlayer.setOpponent(opponent);
synchronized (opponent) {
opponent.notify();
}
}
System.out.println (thisPlayer.getName() + " playing " + thisPlayer.getOpponent().getName());
} catch (Exception ex) {
ex.printStackTrace();
}
}
static class Player {
private String name;
private Player opponent;
Player (String name) {
this.name = name;
}
public String getName() {
return name;
}
public Player getOpponent() {
return opponent;
}
public void setOpponent(Player opponent) {
this.opponent = opponent;
}
}
}
Yes. All local variables inside methods are thread-safe. Class fields variables might be thread-safe or might be not. It is up to you. If rest controller has singleton scope (usually by default it has) that's mean that class fields are shared among the all requests.
So, technically you can use some shared lock object to synchonize on it. Try to do it. But it's better to do it in async mode. See Reverse Ajax Comet technique with long polling in this article.
Alternatively you might use Reverse Ajax with Websockets and send 'Transfer was received' back to client without any idle.
I'm trying to download a pdf file using URLConnection. Here's how I setup the connection object.
URL serverUrl = new URL(url);
urlConnection = (HttpURLConnection) serverUrl.openConnection();
urlConnection.setDoInput(true);
urlConnection.setRequestMethod("GET");
urlConnection.setRequestProperty("Content-Type", "application/pdf");
urlConnection.setRequestProperty("ENCTYPE", "multipart/form-data");
String contentLength = urlConnection.getHeaderField("Content-Length");
I obtained inputstream from the connection object.
bufferedInputStream = new BufferedInputStream(urlConnection.getInputStream());
And the output stream to write the file contents.
File dir = new File(context.getFilesDir(), mFolder);
if(!dir.exists()) dir.mkdir();
final File f = new File(dir, String.valueOf(documentName));
f.createNewFile();
final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(f, true)); //true for appendMode
BlockingQueue is created so that threads performing read and write operations can access the queue.
final BlockingQueue<ByteArrayWrapper> blockingQueue = new ArrayBlockingQueue<ByteArrayWrapper>(MAX_VALUE,true);
final byte[] dataBuffer = new byte[MAX_VALUE];
Now created thread to read data from InputStream.
Thread readerThread = new Thread(new Runnable() {
#Override
public void run() {
try {
int count = 0;
while((count = bufferedInputStream.read(dataBuffer, 0, dataBuffer.length)) != -1) {
ByteArrayWrapper byteArrayWrapper = new ByteArrayWrapper(dataBuffer);
byteArrayWrapper.setBytesReadCount(count);
blockingQueue.put(byteArrayWrapper);
}
blockingQueue.put(null); //end of file
} catch(Exception e) {
e.printStackTrace();
} finally {
try {
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
Now the writer thread reads those file contents.
Thread writerThread = new Thread(new Runnable() {
#Override
public void run() {
try {
while(true) {
ByteArrayWrapper byteWrapper = blockingQueue.take();
if(null == byteWrapper) break;
bufferedOutputStream.write(byteWrapper.getBytesRead(), 0, byteWrapper.getBytesReadCount());
}
bufferedOutputStream.flush();
} catch(Exception e) {
e.printStackTrace();
} finally {
try {
bufferedOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
Finally, threads are started.
readerThread.start();
writerThread.start();
Theoretically it should read the file from InputStream and save it to the target file. However, in reality, it produces blank pdf file. At some other time, it shows invalid pdf format exception. File size matches with content length of the InputStream. Is there anything I'm missing?
I'm not familiar with ByteArrayWrapper. Does it just hold a reference to the array, like this?
public class ByteArrayBuffer {
final private byte[] data;
public ByteArrayBuffer(byte[] data) {
this.data = data;
}
public byte[] getBytesRead() {
return data;
}
/*...etc...*/
}
If so. that would be the problem: all of the ByteArrayWrapper objects are backed by the same array. Which is repeatedly overwritten by the writer. Even though BlockingQueue did the hard work of safely publishing each object from one thread to the other.
The simplest fix might be to make the ByteArrayWrapper effectively immutable i.e. don't change it after publishing it to another thread. Taking a copy of the array on construction would be simplest:
public ByteArrayWrapper(byte[] data) {
this.data = Arrays.copyOf(data, data.length);
}
One other problem is that "BlockingQueue does not accept null elements" (see BlockingQueue docs), and so the "end of input" sentinel value doesn't work. Replacing null with a
private static ByteArrayWrapper END = new ByteArrayWrapper(new byte[]{});
in the appropriate places will fix that.
By making those changes to a copy of the code I was able to retrieve a faithful copy of a PDF file.
Try to use Android DownloadManager (http://developer.android.com/reference/android/app/DownloadManager.html) it is used to handle long-running HTTP requests in the background.
Here you don't need to think about received bytes and the progress is displayed in the notification bar.
There is a good tutorial here: http://blog.vogella.com/2011/06/14/android-downloadmanager-example/
For my activities to work, I have to get data from the internet.
I implemented threads, but I am not that good with Java or threads yet, so I kinda rushed through it just hoping it would work. Well it works, but the UI feels slow sometimes because it takes awhile until the activity appears.
Here is my code
an activity, lets call it MainActivity calls:
JSONObject Data = WebApi.getData(id);
the class WebApi pieces the url together:
public static JSONObject getData(String id) {
String url = URL;
url += DATA_URL;
url += VALUE_DATA_ID + id;
return WebInterface.executeWeb(url);
}
and hands it over to WebInterface, in WebInterface the whole thing gets executed:
public static String getUrl(final String url) {
final StringBuilder sb = new StringBuilder();
Thread thread = new Thread(new Runnable() {
public void run()
{
try
{
InputStream is = (InputStream) new URL(url).getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String result, line = reader.readLine();
result = line;
while((line=reader.readLine())!=null){
result+=line;
}
sb.append(result);
} catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String result = sb.toString();
Log.d(App.TAG, result);
return result;
}
public static JSONObject executeWeb(final String url) {
String result = WebInterface.getUrl(url);
JSONObject json = null;
try {
json = new JSONObject(result.trim());
} catch (JSONException e) {
try {
json = new JSONObject("{}");
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
return json;
}
well this works but i feel like this would work even better, if I would implement it with ASyncTask. My Activity could show some cached data until the "real" data appears. Would that be possible with AsyncTask? And would I need to redo a lot of my code for that?
thanks in advance for the help!
Edit:
thanks to whoever suggested AsyncTaskLoader (i think that one deleted his answer)
I did it with AsyncTaskLoader, very handy and very easy!
In effect your code is single threaded because of thread.join(). The current thread just waits for the newly spawned thread to finish. You have in effect not removed the network from the main thread, hence the UI "locks up" or feels slow.
You could have a callback that runs on the main thread when your thread is finished, but AsyncTask does this for you, and allows you to update a progress bar properly if desired. Read the documentation on how to implement AsyncTask.
svenoaks is correct that your use of thread.join() is making your code effectively single threaded. His solution of using an AsyncTask is also correct.
An alternative approach is to use a Handler in conjunction with the threads you already have. Create the Handler on your main thread, then in the spawned thread obtain() a new message and use the handler to send it. You then have code in the handler (which executes on the main thread) that receives the message and updates the UI.
Without seeing more of your code I can't be sure what it is you want to do with the data, but I can give you a basic example of how to use an AsyncTask. First you won't need any of that Thread stuff in getUrl(), so lets get rid of it. getUrl() should look something like this:
public static String getUrl(String url) {
final StringBuilder sb = new StringBuilder();
try
{
InputStream is = (InputStream) new URL(url).getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String result, line = reader.readLine();
result = line;
while((line=reader.readLine())!=null){
result+=line;
}
sb.append(result);
} catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
String result = sb.toString();
return result;
}
Next lets wrap your call to WebApi.getData in an AsyncTask, so that it runs in the background.
new AsyncTask<Void, Void, JSONObject>(){
#Override
protected JSONObject doInBackground(Void... params) {
JSONObject data = WebApi.getData(id);
return data;
}
#Override
protected void onPostExecute(JSONObject result){
//here you can do something with result
}
}.execute();
AsynTask will execute whatever code is in doInBackground() in a background thread, and then return the result to onPostExecute(), which will be run on the UI thread. Please note id will have to be declared final in the example I gave above.
As has already been said, you should probably read the documentation on AsyncTask.
I'm new in java, and im trying to read a text file from the web into a variable, but i'm getting the text file's url, instead of the content, and just can't figure out what could be the problem.
The class where i'm trying to read the file:
public class readtextfile extends AsyncTask<String, Integer, String>{
private TextView description;
public readtextfile(TextView descriptiontext){
this.description = descriptiontext;
}
#Override
protected String doInBackground(String... params) {
URL url = null;
String result ="";
try {
url = new URL("http://example.com/description1.txt");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String line = null;
while ((line = in.readLine()) != null) {
result+=line;
}
in.close();
}
catch (MalformedURLException e) {e.printStackTrace();}
catch (IOException e) {e.printStackTrace();}
return result;
}
protected void onProgressUpdate() {
//called when the background task makes any progress
}
protected void onPreExecute() {
//called before doInBackground() is started
}
#Override
protected void onPostExecute(String result) {
this.description.setText(result);
}
}
The Activity where i call the class:
public class PhotosActivity extends Activity {
TextView description;
String descriptiontext;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.photos_layout);
description = ((TextView)findViewById(R.id.description1));
new readtextfile(description).execute();
}
}
Try url.openConnection and the use connection object to get inputStream. The updated method would be like
protected String doInBackground(String... params) {
URL url = null;
String result = "";
try {
url = new URL("http://www.example.com/description1.txt");
URLConnection connection = url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
result += line;
}
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
Update based on your comment.
You need not invoke the postExecute method. If you invoke postExecute it just execute that method. The doInBackground wont get exeuted. Instead you should use the execute method. Just like java thread.start() method invoke the overridden run() method.
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
refer developer doc
Try using Scanner like this.
URL url = new URL("http://www.example.com/description1.txt");
Scanner s = new Scanner(url.openStream());