What is the best way to call multiple api parallel in Java? I want to do multiple rest calls, combine the results and return a jsonArray. I am using ExecutorService and get the correct output when i access the url from only one client pc. But when i access the url from multiple clients, each time i am getting a jsonArray of different size even though i am calling same url.
What i have done is given below:
ExecutorService executor = Executors.newFixedThreadPool(5);
resultArray = new JSONArray();
for (Branch branch : Branches) {
Future<Response> response = executor.submit(new Request(branch.getUrl(),
branch.getUserName(), branch.getPassword()));
responseBody = response.get().getResponseBody();
resultArray.put(responseBody);
}
executor.shutdown();
while(!executor.isTerminated()) {
}
return resultArray.toString();
public class Request implements Callable<Response> {
private HttpURLConnection con;
private URL obj;
private String response;
private String url;
private String username;
private String password;
public Request(String url, String username, String password) {
this.url = url;
this.username = username;
this.password = password;
}
#Override
public Response call() {
try {
obj = new URL(url);
con = (HttpURLConnection) obj.openConnection();
String userCredentials = username + ":" + password;
String basicAuth = "Basic " + java.util.Base64.getEncoder().encodeToString(userCredentials.getBytes());
con.setRequestProperty ("Authorization", basicAuth);
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
if(responseCode == 200) {
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer stringBuffer = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
stringBuffer.append(inputLine);
}
in.close();
response = stringBuffer.toString();
return new Response(responseCode, response);
}
else {
response = "{\"response\":\"some error occurred\"}";
return new Response(responseCode, response);
}
} catch (IOException e) {
response = "{\"output\":\"some error occurred\"}";
return new Response(404, response);
}
}
}
public class Response {
private String responseBody;
private int responseCode;
public Response(int responseCode, String responseBody) {
this.responseBody = responseBody;
this.responseCode = responseCode;
}
public int getResponseCode() {
return responseCode;
}
public String getResponseBody() {
return responseBody;
}
}
Please check this,
Collection<Callable<Response>> tasks = new ArrayList<>();
for (Branch branch : Branches) {
tasks.add(new Request(branch.getUrl(), branch.getUserName(), branch.getPassword()));
}
int numThreads = Branches.size() > 4 ? 4 : Branches.size();
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
List<Future<Response>> results = executor.invokeAll(tasks);
for(Future<Response> response : results){
responseBody = response.get().getResponseBody();
resultArray.put(responseBody);
}
Java 7 onwards we you can try replace ExecutorService with ForkJoin Pool,
Collection<Callable<Response>> tasks = new ArrayList<>();
for (Branch branch : Branches) {
tasks.add(new Request(branch.getUrl(), branch.getUserName(), branch.getPassword()));
}
int numThreads = Branches.size() > 4 ? 4 : Branches.size();
ForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
List<Future<Response>> results = pool.invokeAll(tasks);
for(Future<Response> response : results){
responseBody = response.get().getResponseBody();
resultArray.put(responseBody);
}
Note:- The code is not tested, i have used something like this few months back.
Related
Im doing a REST server and client using java to learn.
Everything works ok but the PUT request from the client dont pass the data in the body correctly because when I see the log in the server the parameters are NULL
This is the client PUT request code:
private static class Mod {
int idUser;
String nameUser;
String passwordUser;
public Mod(int idUser, String nameUser, String passwordUser) {
this.idUser = idUser;
this.nameUser = nameUser;
this.passwordUser = passwordUser;
try {
URL url = new URL("http://localhost:8080/api/users/" + idUser + "/");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("PUT");
connection.setDoInput(true);
connection.setDoOutput(true);
HashMap<String, String> postDataParams = new HashMap<>();
postDataParams.put("nameUser", this.nameUser);
postDataParams.put("passwordUser", this.passwordUser);
connection.setDoInput(true);
connection.setDoOutput(true);
OutputStream os = connection.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8));
writer.write(getPutDataString(postDataParams));
writer.flush();
writer.close();
os.close();
if (connection.getResponseCode() == 201) {
System.out.println("Modified");
connection.disconnect();
} else {
System.out.println("Error");
}
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
private String getPutDataString(HashMap<String, String> params) {
StringBuilder result = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> entry : params.entrySet()) {
if (first) {
first = false;
} else {
result.append("&");
}
result.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8));
result.append("=");
result.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
}
return result.toString();
}
}
This is the code for the POST request. It uses the same way of "injecting" the parameters and works perfect:
private static class Create {
String nameUser, passwordUser;
public Create(String nameUser, String passwordUser) {
this.nameUser = nameUser;
this.passwordUser = passwordUser;
try {
URL url = new URL("http://localhost:8080/api/users/");
HttpURLConnection myConnection = (HttpURLConnection) url.openConnection();
myConnection.setRequestMethod("POST");
HashMap<String, String> postDataParams = new HashMap<>();
postDataParams.put("nameUser", this.nameUser);
postDataParams.put("passwordUser", this.passwordUser);
myConnection.setDoInput(true);
myConnection.setDoOutput(true);
OutputStream os = myConnection.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8));
writer.write(getPostDataString(postDataParams));
writer.flush();
writer.close();
os.close();
myConnection.getResponseCode();
if (myConnection.getResponseCode() == 201) {
System.out.println("Created");
myConnection.disconnect();
} else {
System.out.println("Error");
}
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
private String getPostDataString(HashMap<String, String> params) {
StringBuilder result = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> entry : params.entrySet()) {
if (first) {
first = false;
} else {
result.append("&");
}
result.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8));
result.append("=");
result.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
}
return result.toString();
}
}
The REST Controller in the server:
#RestController
#RequestMapping("/api")
public class UserRestController {
#Autowired
private IUserService userService;
#GetMapping("/users")
public List<User> index() {
return userService.findAll();
}
#GetMapping("/users/{id}")
public User show(#PathVariable Long id) {
return this.userService.findById(id);
}
#PostMapping("/users")
#ResponseStatus(HttpStatus.CREATED)
public User create(#ModelAttribute User user) {
this.userService.save(user);
return user;
}
#PutMapping("/users/{id}")
#ResponseStatus(HttpStatus.CREATED)
public User update(#ModelAttribute User user, #PathVariable Long id) {
User currentUser = this.userService.findById(id);
currentUser.setNameUser(user.getNameUser());
currentUser.setPasswordUser(user.getPasswordUser());
this.userService.save(currentUser);
return currentUser;
}
#DeleteMapping("/users/{id}")
#ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(#PathVariable Long id) {
this.userService.delete(id);
}
}
You should use x-www-form-urlencoded because you are not sending any file.
Moreover, you need more work to manually do a form-data request so it's better to change the server so that it accepts x-www-form-urlencoded parameters.
After you have modified the server, add the content type to the request:
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
and remove this line:
connection.setDoInput(true)
because you use the HttpURLConnection as output.
Note that you can make the PUT request easily with Apache HttpClient.
I have been working on my own Http Client Class, and i want a way to implement the onload and oerror feature like, "declaring an event and actions for that event", if an error with the connection happened i must have the ability to specify a custom action for it.
public static void Error(int code){
System.out.println("Oops, something went wrong Error code:" + code.toString());
}
URL url = new URL("http://example.com/");
Map<String, String> params = new HashMap<String, String>();
params.put("key","value");
http_client client = new http_client(url, "GET", params , true);
client.onError = Error(client.ErrorCode);
Something like that.
Here is my class:
class http_client {
protected String responseText;
protected boolean loaded = false;
protected boolean error = false;
public http_client(URL url, String method , Map<String,String> parameters , boolean cache) throws IOException, ProtocolException{
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int status = connection.getResponseCode();
if(status > 299){
error = true;
}
connection.setRequestMethod(method);
if(method == "POST"){
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
}
connection.setUseCaches(cache);
connection.setDoInput(true);
connection.setDoOutput(true);
DataOutputStream s = new DataOutputStream(connection.getOutputStream());
s.writeBytes(paramToStr(parameters));
s.flush();
s.close();
InputStream is = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder response = new StringBuilder();
String CurrentLine;
int lines = 0;
while((CurrentLine = reader.readLine()) != null){
lines += 1;
response.append(CurrentLine + "\n");
}
reader.close();
responseText = response.toString();
responseText = responseText.substring(0 , responseText.length() - 1);
if(lines == 1){
responseText = responseText.replace("\n","");
}
loaded = true;
}
public static String paramToStr(Map<String, String> parameters) throws UnsupportedEncodingException{
StringBuilder result = new StringBuilder();
result.append("?");
for(Map.Entry<String,String> entry: parameters.entrySet()){
String key = URLEncoder.encode(entry.getKey() , "UTF-8");
String value = URLEncoder.encode(entry.getValue() , "UTF-8");
result.append(key);
result.append("=");
result.append(value);
result.append("&");
}
String str = result.toString();
str = result.substring(0 , str.length() - 1);
return str;
}
}
Thanks in advance.
You can use the Function Interface Java provides:
class http_client {
protected String responseText;
protected boolean loaded = false;
protected Function<Integer, Void> success;
protected Function<Integer, Void> error;
public http_client(URL url, String method , Map<String,String> parameters , boolean cache, Function<Integer, String>success, Function<Integer, String> error) throws IOException, ProtocolException{
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int status = connection.getResponseCode();
if(status > 299){
error.apply(status);
} else {
success.apply(status);
}
...
}
}
to call it just pass some lambda function
...
http_client client = new http_client(url, "GET", params , true, status -> System.out.println("success! " + status), status -> System.out.println("error " + status));
I have been working on this and I have hit a point where I dont know what to do. What I am trying to do is use one class to download and parse out a file into a string and then send that string to another class to parse out the JSON stuff. All the parts work fine by themselves and I have tested everything separately. I just dont know how to send the value to the Json parses to start the parsing.
So this is my filedownloader class.
public class JsonFileDownloader extends AsyncTask<String, Void, String> {
//used to access the website
String username = "admin";
String password = "admin";
public String ret = "";
#Override
protected String doInBackground(String... params) {
Log.d("Params ", params[0].toString());
readFromFile(params[0]);
return ret;
}
private String readFromFile(String myWebpage) {
HttpURLConnection urlConnection = null;
try {
//Get the url connection
URL url = new URL(myWebpage);
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
}
});
urlConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
if (inputStream != null) {
ret = streamToString(inputStream);
inputStream.close();
Log.d("Final String", ret);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
return ret;
}
}
public static String streamToString(InputStream is) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = rd.readLine()) != null) {
sb.append(line);
}
return sb.toString();
}
public String getJsonData()
{
return ret;
}
}
This works fine I have tested it over and over with no errors.
The next is the Json parser which is like this.
public class JSONParser {
JSONObject jsonResponse;
String jsonData;
//Consturctor
public JSONParser()
{
//this.jsonData = jsonData;
// this.OutputData = outPutData;
}
public void parsesData(String promo,
ArrayList<String> pictureHTTP,
ArrayList<String> pathHTTP,
ArrayList<String> labelText) throws IOException {
//Build the Json String
JsonFileDownloader jfd = new JsonFileDownloader();
// jsonData = String.valueOf(jfd.execute(promo));
jfd.execute(promo);
//jfd.getResuts(jsonData);
//jsonData = jfd.ret;
Log.d("JsonData String = " , jsonData);
//Try to parse the data
try
{
Log.d("Jsondata " , jsonData);
//Creaate a new JSONObject ith the name/value mapping from the JSON string
jsonResponse = new JSONObject(jsonData);
//Returns the value mapped by the name if it exists and is a JSONArry
JSONArray jsonMainNode = jsonResponse.optJSONArray("");
//Proccess the JSON node
int lenghtJsonArrar = jsonMainNode.length();
for (int i = 0; i<lenghtJsonArrar; i++)
{
//Get object for each json node
JSONObject jsonChildNode = jsonMainNode.getJSONObject(i);
//Get the node values
//int song_id = Integer.parseInt(jsonChildNode.optString("song_id").toString());
String picture = jsonChildNode.optString("picture").toString();
String pathName = jsonChildNode.optString("path").toString();
String lableName = jsonChildNode.optString("label".toString());
//Debug Testing code
pictureHTTP.add(picture);
pathHTTP.add(pathName);
labelText.add(lableName);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
Now I know where the problem is occurring. When i try to assign a value to the jsonData it never is assigned so it is null and the system fails.
I have tried a few things after the jfd.exicute() but I just dont know how to get the value from the final string output into the jsonData.
Thank you for any help with this.
Alright, here is a pretty flexible pattern for the overall usage of using AsyncTask to download web content and getting the results from it back to the UI thread.
Step 1 Define an interface that will act as a message bus between the AsyncTask and where you want the data.
public interface AsyncResponse<T> {
void onResponse(T response);
}
Step 2 Create a generic AsyncTask extension that will take any URL and return the results from it. You basically had this already, but I made some tweaks. Most importantly, allowing the setting of the AsyncResponse callback interface.
public class WebDownloadTask extends AsyncTask<String, Void, String> {
private AsyncResponse<String> callback;
// Optional parameters
private String username;
private String password;
// Make a constuctor to store the parameters
public WebDownloadTask(String username, String password) {
this.username = username;
this.password = password;
}
// Don't forget to call this
public void setCallback(AsyncResponse<String> callback) {
this.callback = callback;
}
#Override
protected String doInBackground(String... params) {
String url = params[0];
return readFromFile(url);
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (callback != null) {
callback.onResponse(s);
} else {
Log.w(WebDownloadTask.class.getSimpleName(), "The response was ignored");
}
}
/******* private helper methods *******/
private String streamToString(InputStream is) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = rd.readLine()) != null) {
sb.append(line);
}
return sb.toString();
}
private String readFromFile(String myWebpage) {
String response = null;
HttpURLConnection urlConnection = null;
try {
//Get the url connection
URL url = new URL(myWebpage);
// Unnecessary for general AsyncTask usage
/*
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
}
});
*/
urlConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
if (inputStream != null) {
response = streamToString(inputStream);
inputStream.close();
Log.d("Final String", response);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return response;
}
}
Step 3 Go forth and use that AsyncTask wherever you wish. Here is an example. Note that if you do not use setCallback, you will be unable to get the data that came from the AsyncTask.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebDownloadTask task = new WebDownloadTask("username", "password");
task.setCallback(new AsyncResponse<String>() {
#Override
public void onResponse(String response) {
// Handle response here. E.g. parse into a JSON object
// Then put objects into some list, then place into an adapter...
Toast.makeText(getApplicationContext(), response, Toast.LENGTH_SHORT).show();
}
});
// Use any URL, this one returns a list of 10 users in JSON
task.execute("http://jsonplaceholder.typicode.com/users");
}
}
I am trying to build a simple HTTP client program that sends a request to a web server and prints the response out to the user.
I have got the following error when I run my code and I am not sure what is causing it:
-1
Exception in thread "main" java.lang.IllegalArgumentException: port out of range:-1
at java.net.InetSocketAddress.(InetSocketAddress.java:118)
at java.net.Socket.(Socket.java:189)
at com.example.bookstore.MyHttpClient.execute(MyHttpClient.java:18)
at com.example.bookstore.MyHttpClientApp.main(MyHttpClientApp.java:29)
Java Result: 1
Below is my MyHttpClient.java class
public class MyHttpClient {
MyHttpRequest request;
public MyHttpResponse execute(MyHttpRequest request) throws IOException {
this.request = request;
int port = request.getPort();
System.out.println(port);
//Create a socket
Socket s = new Socket(request.getHost(), request.getPort());
//Create I/O streams
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter outToServer = new PrintWriter(s.getOutputStream());
//Get method (POST OR GET) from request
String method = request.getMethod();
//Create response
MyHttpResponse response = new MyHttpResponse();
//GET Request
if(method.equalsIgnoreCase("GET")){
//Construct request line
String path = request.getPath();
String queryString = request.getQueryString();
//Send request line to server
outToServer.println("GET " + path + " HTTP/1.0");
//=================================================\\
//HTTP RESPONSE
//RESPONSE LINE
//Read response from server
String line = inFromServer.readLine();
//Get response code - should be 200.
int status = Integer.parseInt(line.substring(9, 3));
//Get text description of response code - if 200 should be OK.
String desc = line.substring(13);
//HEADER LINES
//Loop through headers until get to blank line...
//Header name: Header Value - structure
do{
line = inFromServer.readLine();
if(line != null && line.length() == 0){
//line is not blank
//header name start of line to the colon.
String name = line.substring(0, line.indexOf(": "));
//header value after the colon to end of line.
String value = String.valueOf(line.indexOf(": "));
response.addHeader(name, value);
}
}while(line != null && line.length() == 0);
//MESSAGE BODY
StringBuilder sb = new StringBuilder();
do{
line = inFromServer.readLine();
if(line != null){
sb.append((line)+"\n");
}
}while(line != null);
String body = sb.toString();
response.setBody(body);
//return response
return response;
}
//POST Request
else if(method.equalsIgnoreCase("POST")){
return response;
}
return response;
}
}
This is the MyHttpClientApp.java class
public class MyHttpClientApp {
public static void main(String[] args) {
String urlString = null;
URI uri;
MyHttpClient client;
MyHttpRequest request;
MyHttpResponse response;
try {
//==================================================================
// send GET request and print response
//==================================================================
urlString = "http://127.0.0.1/bookstore/viewBooks.php";
uri = new URI(urlString);
client = new MyHttpClient();
request = new MyHttpRequest(uri);
request.setMethod("GET");
response = client.execute(request);
System.out.println("=============================================");
System.out.println(request);
System.out.println("=============================================");
System.out.println(response);
System.out.println("=============================================");
}
catch (URISyntaxException e) {
String errorMessage = "Error parsing uri (" + urlString + "): " + e.getMessage();
System.out.println("MyHttpClientApp: " + errorMessage);
}
catch (IOException e) {
String errorMessage = "Error downloading book list: " + e.getMessage();
System.out.println("MyHttpClientApp: " + errorMessage);
}
}
}
MyHttpRequest
public class MyHttpRequest {
private URI uri;
private String method;
private Map<String, String> params;
public MyHttpRequest(URI uri) {
this.uri = uri;
this.method = null;
this.params = new HashMap<String, String>();
}
public String getHost() {
return this.uri.getHost();
}
public int getPort() {
return this.uri.getPort();
}
public String getPath() {
return this.uri.getPath();
}
public void addParameter(String name, String value) {
try {
name = URLEncoder.encode(name, "UTF-8");
value = URLEncoder.encode(value, "UTF-8");
this.params.put(name, value);
}
catch (UnsupportedEncodingException ex) {
System.out.println("URL encoding error: " + ex.getMessage());
}
}
public Map<String, String> getParameters() {
return this.params;
}
public String getQueryString() {
Map<String, String> parameters = this.getParameters();
// construct StringBuffer with name/value pairs
Set<String> names = parameters.keySet();
StringBuilder sbuf = new StringBuilder();
int i = 0;
for (String name : names) {
String value = parameters.get(name);
if (i != 0) {
sbuf.append("&");
}
sbuf.append(name);
sbuf.append("=");
sbuf.append(value);
i++;
}
return sbuf.toString();
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
#Override
public String toString() {
StringBuilder sbuf = new StringBuilder();
sbuf.append(this.getMethod());
sbuf.append(" ");
sbuf.append(this.getPath());
if (this.getMethod().equals("GET")) {
if (this.getQueryString().length() > 0) {
sbuf.append("?");
sbuf.append(this.getQueryString());
}
sbuf.append("\n");
sbuf.append("\n");
}
else if (this.getMethod().equals("POST")) {
sbuf.append("\n");
sbuf.append("\n");
sbuf.append(this.getQueryString());
sbuf.append("\n");
}
return sbuf.toString();
}
}
MyHttpResponse
public class MyHttpResponse {
private int status;
private String description;
private Map<String, String> headers;
private String body;
public MyHttpResponse() {
this.headers = new HashMap<String, String>();
}
public int getStatus() {
return this.status;
}
public void setStatus(int status) {
this.status = status;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public Map<String, String> getHeaders() {
return this.headers;
}
public void addHeader(String header, String value) {
headers.put(header, value);
}
public String getBody() {
return body;
}
public void setBody(String is) {
this.body = is;
}
#Override
public String toString() {
StringBuilder sbuf = new StringBuilder();
sbuf.append("Http Response status line: ");
sbuf.append("\n");
sbuf.append(this.getStatus());
sbuf.append(" ");
sbuf.append(this.getDescription());
sbuf.append("\n");
sbuf.append("---------------------------------------------");
sbuf.append("\n");
sbuf.append("Http Response headers: ");
sbuf.append("\n");
for (String key: this.getHeaders().keySet()) {
String value = this.getHeaders().get(key);
sbuf.append(key);
sbuf.append(": ");
sbuf.append(value);
sbuf.append("\n");
}
sbuf.append("---------------------------------------------");
sbuf.append("\n");
sbuf.append("Http Response body: ");
sbuf.append("\n");
sbuf.append(this.getBody());
sbuf.append("\n");
return sbuf.toString();
}
}
Any ideas what might be happening? Many thanks in advance.
I guess your request don't specify a port explicitly and so your request.getPort() is returning -1. And then you try to connect to port -1. And this is illegal.
Instead of that, before using the port : check if it is <= 0 and in this case use 80 as default value.
int port = request.getPort();
if(port<=0) port=80;
since there is no set port in the URI, as of javadocs -1 is returned from port:
http://docs.oracle.com/javase/6/docs/api/java/net/URI.html#getPort()
The port component of this URI, or -1 if the port is undefined
Lots of recreating the wheel going on here. Why not use Java's in-built HTTP client (at least; there are also many third-party HTTP clients out there that do very nicely).
URL url = new URL("http://stackoverflow.com");
final HttpURLConnection connection = url.openConnection();
connection.setDoInput(true);
connection.connect();
int responseCode = connection.getResponseCode();
etc.
use
uri = URIUtil.encodeQuery(urlString)
instead
uri = new URI(urlString);
Can anyone point me to a good implementation of a way to send GET and POST Requests. They are alot of ways to do these, and i am looking for the best implementation. Secondly is there a generic way to send both these methods rather then using two different ways. After all the GET method merely has the params in the Query Strings, whereas the POST method uses the headers for the Params.
Thanks.
You can use the HttpURLConnection class (in java.net) to send a POST or GET HTTP request. It is the same as any other application that might want to send an HTTP request. The code to send an Http Request would look like this:
import java.net.*;
import java.io.*;
public class SendPostRequest {
public static void main(String[] args) throws MalformedURLException, IOException {
URL reqURL = new URL("http://www.stackoverflow.com/"); //the URL we will send the request to
HttpURLConnection request = (HttpURLConnection) (reqUrl.openConnection());
String post = "this will be the post data that you will send"
request.setDoOutput(true);
request.addRequestProperty("Content-Length", Integer.toString(post.length)); //add the content length of the post data
request.addRequestProperty("Content-Type", "application/x-www-form-urlencoded"); //add the content type of the request, most post data is of this type
request.setMethod("POST");
request.connect();
OutputStreamWriter writer = new OutputStreamWriter(request.getOutputStream()); //we will write our request data here
writer.write(post);
writer.flush();
}
}
A GET request will look a little bit different, but much of the code is the same. You don't have to worry about doing output with streams or specifying the content-length or content-type:
import java.net.*;
import java.io.*;
public class SendPostRequest {
public static void main(String[] args) throws MalformedURLException, IOException {
URL reqURL = new URL("http://www.stackoverflow.com/"); //the URL we will send the request to
HttpURLConnection request = (HttpURLConnection) (reqUrl.openConnection());
request.setMethod("GET");
request.connect();
}
}
I prefer using dedicated class to do GET/POST and any HTTP connections or requests.
Moreover I use HttpClient to execute these GET/POST methods.
Below is sample from my project. I needed thread-safe execution so there is ThreadSafeClientConnManager.
There is an example of using GET (fetchData) and POST (sendOrder)
As you can see execute is general method for executing HttpUriRequest - it can be POST or GET.
public final class ClientHttpClient {
private static DefaultHttpClient client;
private static CookieStore cookieStore;
private static HttpContext httpContext;
static {
cookieStore = new BasicCookieStore();
httpContext = new BasicHttpContext();
httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
client = getThreadSafeClient();
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, AppConstants.CONNECTION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, AppConstants.SOCKET_TIMEOUT);
client.setParams(params);
}
private static DefaultHttpClient getThreadSafeClient() {
DefaultHttpClient client = new DefaultHttpClient();
ClientConnectionManager mgr = client.getConnectionManager();
HttpParams params = client.getParams();
client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, mgr.getSchemeRegistry()),
params);
return client;
}
private ClientHttpClient() {
}
public static String execute(HttpUriRequest http) throws IOException {
BufferedReader reader = null;
try {
StringBuilder builder = new StringBuilder();
HttpResponse response = client.execute(http, httpContext);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
reader = new BufferedReader(new InputStreamReader(content, CHARSET));
String line = null;
while((line = reader.readLine()) != null) {
builder.append(line);
}
if(statusCode != 200) {
throw new IOException("statusCode=" + statusCode + ", " + http.getURI().toASCIIString()
+ ", " + builder.toString());
}
return builder.toString();
}
finally {
if(reader != null) {
reader.close();
}
}
}
public static List<OverlayItem> fetchData(Info info) throws JSONException, IOException {
List<OverlayItem> out = new LinkedList<OverlayItem>();
HttpGet request = buildFetchHttp(info);
String json = execute(request);
if(json.trim().length() <= 2) {
return out;
}
try {
JSONObject responseJSON = new JSONObject(json);
if(responseJSON.has("auth_error")) {
throw new IOException("auth_error");
}
}
catch(JSONException e) {
//ok there was no error, because response is JSONArray - not JSONObject
}
JSONArray jsonArray = new JSONArray(json);
for(int i = 0; i < jsonArray.length(); i++) {
JSONObject chunk = jsonArray.getJSONObject(i);
ChunkParser parser = new ChunkParser(chunk);
if(!parser.hasErrors()) {
out.add(parser.parse());
}
}
return out;
}
private static HttpGet buildFetchHttp(Info info) throws UnsupportedEncodingException {
StringBuilder builder = new StringBuilder();
builder.append(FETCH_TAXIS_URL);
builder.append("?minLat=" + URLEncoder.encode("" + mapBounds.getMinLatitude(), ENCODING));
builder.append("&maxLat=" + URLEncoder.encode("" + mapBounds.getMaxLatitude(), ENCODING));
builder.append("&minLon=" + URLEncoder.encode("" + mapBounds.getMinLongitude(), ENCODING));
builder.append("&maxLon=" + URLEncoder.encode("" + mapBounds.getMaxLongitude(), ENCODING));
HttpGet get = new HttpGet(builder.toString());
return get;
}
public static int sendOrder(OrderInfo info) throws IOException {
HttpPost post = new HttpPost(SEND_ORDER_URL);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("id", "" + info.getTaxi().getId()));
nameValuePairs.add(new BasicNameValuePair("address", info.getAddressText()));
nameValuePairs.add(new BasicNameValuePair("name", info.getName()));
nameValuePairs.add(new BasicNameValuePair("surname", info.getSurname()));
nameValuePairs.add(new BasicNameValuePair("phone", info.getPhoneNumber()));
nameValuePairs.add(new BasicNameValuePair("passengers", "" + info.getPassengers()));
nameValuePairs.add(new BasicNameValuePair("additionalDetails", info.getAdditionalDetails()));
nameValuePairs.add(new BasicNameValuePair("lat", "" + info.getOrderLocation().getLatitudeE6()));
nameValuePairs.add(new BasicNameValuePair("lon", "" + info.getOrderLocation().getLongitudeE6()));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
String response = execute(post);
if(response == null || response.trim().length() == 0) {
throw new IOException("sendOrder_response_empty");
}
try {
JSONObject json = new JSONObject(response);
int orderId = json.getInt("orderId");
return orderId;
}
catch(JSONException e) {
throw new IOException("sendOrder_parsing: " + response);
}
}
EDIT
The execute method is public because sometimes I use custom (or dynamic) GET/POST requests.
If you have URL object you can pass to execute method:
HttpGet request = new HttpGet(url.toString());
execute(request);
As you said: the GET-Parameters are in the URL - So you can use a loadUrl() on your Webview to send them.
[..].loadUrl("http://www.example.com/data.php?param1=value1¶m2=value2&...");
The developer training docs have a good example on GET requests. You're responsible for adding the query parameters to the URL.
Post is similar, but as you said, quite different. The HttpConnectionURLConnection class can do both, and it's easy to just set the post body with an output stream.
protected String doInBackground(String... strings) {
String response = null;
String data = null;
try {
data = URLEncoder.encode("CustomerEmail", "UTF-8")
+ "=" + URLEncoder.encode(username, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String url = Constant.URL_FORGOT_PASSWORD;// this is url
response = ServiceHandler.postData(url,data);
if (response.equals("")){
return response;
}else {
return response;
}
}
public static String postData(String urlpath,String data){
String text = "";
BufferedReader reader=null;
try
{
// Defined URL where to send data
URL url = new URL(urlpath);
// Send POST data request
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write( data );
wr.flush();
// Get the server response
reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String line = null;
// Read Server Response
while((line = reader.readLine()) != null)
{
sb.append(line + "\n");
}
text = sb.toString();
return text;
}
catch(Exception ex)
{
}
finally
{
try
{
reader.close();
}
catch(Exception ex) {}
}
return text;
}
private RequestListener listener;
private int requestId;
private HashMap<String, String> reqParams;
private File file;
private String fileName;
private RequestMethod reqMethod;
private String url;
private Context context;
private boolean isProgressVisible = false;
private MyProgressDialog progressDialog;
public NetworkClient(Context context, int requestId, RequestListener listener,
String url, HashMap<String, String> reqParams, RequestMethod reqMethod,
boolean isProgressVisible) {
this.listener = listener;
this.requestId = requestId;
this.reqParams = reqParams;
this.reqMethod = reqMethod;
this.url = url;
this.context = context;
this.isProgressVisible = isProgressVisible;
}
public NetworkClient(Context context, int requestId, RequestListener listener,
String url, HashMap<String, String> reqParams, File file, String fileName, RequestMethod reqMethod,
boolean isProgressVisible) {
this.listener = listener;
this.requestId = requestId;
this.reqParams = reqParams;
this.file = file;
this.fileName = fileName;
this.reqMethod = reqMethod;
this.url = url;
this.context = context;
this.isProgressVisible = isProgressVisible;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
if (isProgressVisible) {
showProgressDialog();
}
}
#Override
protected String doInBackground(Void... params) {
try {
if (Utils.isInternetAvailable(context)) {
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
clientBuilder.connectTimeout(10, TimeUnit.SECONDS);
clientBuilder.writeTimeout(10, TimeUnit.SECONDS);
clientBuilder.readTimeout(20, TimeUnit.SECONDS);
OkHttpClient client = clientBuilder.build();
if (reqMethod == RequestMethod.GET) {
Request.Builder reqBuilder = new Request.Builder();
reqBuilder.url(url);
Request request = reqBuilder.build();
Response response = client.newCall(request).execute();
String message = response.message();
String res = response.body().string();
JSONObject jObj = new JSONObject();
jObj.put("statusCode", 1);
jObj.put("response", message);
return jObj.toString();
} else if (reqMethod == RequestMethod.POST) {
FormBody.Builder formBuilder = new FormBody.Builder();
RequestBody body = formBuilder.build();
Request.Builder reqBuilder = new Request.Builder();
reqBuilder.url(url);
reqBuilder.post(body);
Request request = reqBuilder.build();
Response response = client.newCall(request).execute();
String res = response.body().string();
JSONObject jObj = new JSONObject();
jObj.put("statusCode", 1);
jObj.put("response", res);
return jObj.toString();
} else if (reqMethod == RequestMethod.MULTIPART) {
MediaType MEDIA_TYPE = fileName.endsWith("png") ?
MediaType.parse("image/png") : MediaType.parse("image/jpeg");
MultipartBody.Builder multipartBuilder = new MultipartBody.Builder();
multipartBuilder.setType(MultipartBody.FORM);
multipartBuilder.addFormDataPart("file", fileName, RequestBody.create(MEDIA_TYPE, file));
RequestBody body = multipartBuilder.build();
Request.Builder reqBuilder = new Request.Builder();
reqBuilder.url(url);
reqBuilder.post(body);
Request request = reqBuilder.build();
Response response = client.newCall(request).execute();
String res = response.body().string();
JSONObject jObj = new JSONObject();
jObj.put("statusCode", 1);
jObj.put("response", res);
return jObj.toString();
}
} else {
JSONObject jObj = new JSONObject();
jObj.put("statusCode", 0);
jObj.put("response", context.getString(R.string.no_internet));
return jObj.toString();
}
} catch (final Exception e) {
e.printStackTrace();
JSONObject jObj = new JSONObject();
try {
jObj.put("statusCode", 0);
jObj.put("response", e.toString());
} catch (Exception e1) {
e1.printStackTrace();
}
return jObj.toString();
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
try {
JSONObject jObj = new JSONObject(result);
if (jObj.getInt("statusCode") == 1) {
listener.onSuccess(requestId, jObj.getString("response"));
} else {
listener.onError(requestId, jObj.getString("response"));
}
} catch (Exception e) {
listener.onError(requestId, result);
} finally {
dismissProgressDialog();
}
}
private void showProgressDialog() {
progressDialog = new MyProgressDialog(context);
}
private void dismissProgressDialog() {
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
progressDialog = null;
}
}
private static NetworkManager instance = null;
private Set<RequestListener> arrRequestListeners = null;
private int requestId;
public boolean isProgressVisible = false;
private NetworkManager() {
arrRequestListeners = new HashSet<>();
arrRequestListeners = Collections.synchronizedSet(arrRequestListeners);
}
public static NetworkManager getInstance() {
if (instance == null)
instance = new NetworkManager();
return instance;
}
public synchronized int addRequest(final HashMap<String, String> params, Context context, RequestMethod reqMethod, String apiMethod) {
try {
String url = Constants.WEBSERVICE_URL + apiMethod;
requestId = UniqueNumberUtils.getInstance().getUniqueId();
NetworkClient networkClient = new NetworkClient(context, requestId, this, url, params, reqMethod, isProgressVisible);
networkClient.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} catch (Exception e) {
onError(requestId, e.toString() + e.getMessage());
}
return requestId;
}
public synchronized int addMultipartRequest(final HashMap<String,String> params, File file, String fileName, Context context, RequestMethod reqMethod, String apiMethod) {
try {
String url = Constants.WEBSERVICE_URL + apiMethod;
requestId = UniqueNumberUtils.getInstance().getUniqueId();
NetworkClient networkClient = new NetworkClient(context, requestId, this, url, params, file, fileName, reqMethod, isProgressVisible);
networkClient.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} catch (Exception e) {
onError(requestId, e.toString() + e.getMessage());
}
return requestId;
}
public void isProgressBarVisible(boolean isProgressVisible) {
this.isProgressVisible = isProgressVisible;
}
public void setListener(RequestListener listener) {
try {
if (listener != null && !arrRequestListeners.contains(listener)) {
arrRequestListeners.add(listener);
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onSuccess(int id, String response) {
if (arrRequestListeners != null && arrRequestListeners.size() > 0) {
for (RequestListener listener : arrRequestListeners) {
if (listener != null)
listener.onSuccess(id, response);
}
}
}
#Override
public void onError(int id, String message) {
try {
if (Looper.myLooper() == null) {
Looper.prepare();
}
} catch (Exception e) {
e.printStackTrace();
}
if (arrRequestListeners != null && arrRequestListeners.size() > 0) {
for (final RequestListener listener : arrRequestListeners) {
if (listener != null) {
listener.onError(id, message);
}
}
}
}
public void removeListener(RequestListener listener) {
try {
arrRequestListeners.remove(listener);
} catch (Exception e) {
e.printStackTrace();
}
}
Create RequestListner intreface
public void onSuccess(int id, String response);
public void onError(int id, String message);
Get Unique Number
private static UniqueNumberUtils INSTANCE = new UniqueNumberUtils();
private AtomicInteger seq;
private UniqueNumberUtils() {
seq = new AtomicInteger(0);
}
public int getUniqueId() {
return seq.incrementAndGet();
}
public static UniqueNumberUtils getInstance() {
return INSTANCE;
}