What is proper practice for multithreading and httpclient in Java? - java

I'm creating a program that can do multiple logins. I will also give each login the ability to add an item to cart and purchase. The code is currently working for one account, and it's very basic. I had to trim out some private information, but the code should still be clear. Again, I'm just wondering what approach I should take for multiple logins? Does this code for the most part look optimal for speed? How do I approach a retry attempt if checkout returns 500? This code is currently setup for only a single login. Also, there weren't many articles I found to properly clean up the HttpClient. At least, I don't think the tutorials I found were very reputable.
Thanks again for taking the time to read this, I just want to learn other practices to improve my code and approach a proper multithreading technique.
Alittle more detail about my code, there is a token that is retrieved when you view the page, the token is stored and used throughout the program.
class example {
private static List<Header> headers = new ArrayList<Header>();
private static BasicCookieStore cookieStore = new BasicCookieStore();
private static CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultHeaders(headers).setDefaultCookieStore(cookieStore).build();
public static void main(String[] args) throws Exception {
String loginURL = "...";
String productUrl = "...";
String userid = "";
String password = "";
String formKey = "";
int size = 9;
Boolean debug = true;
JsonElement product;
headers.add(new BasicHeader("Host", "..."));
headers.add(new BasicHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"));
headers.add(new BasicHeader("Accept-Language", "en-us"));
headers.add(new BasicHeader("Content-Encoding", "gzip, deflate"));
headers.add(new BasicHeader("Content-Type", "Application/x-www-form-urlencoded"));
headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 8_4_1 like Mac OS X) "
+ "AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H321 Safari/600.1.4"));
headers.add(new BasicHeader("Connection", "keep-alive"));
Scanner in = new Scanner(System.in);
Gson gson = new Gson();
System.out.println("Select Profile\n1. ...\n2. Custom");
int select = in.nextInt();
switch(select) {
case 1:
userid = "...";
password = "...";
break;
// Custom Account Login
case 2:
System.out.println("Enter User_ID:");
userid = in.next();
System.out.println("Enter Password:");
password = in.next();
break;
}
int input = 0;
do {
input = in.nextInt();
switch(input) {
case 99:
debug = true;
break;
// View Menu.
case 0:
System.out.println("...");
break;
// Initiate Session
case 1:
// Retrieve formKey for login page.
formKey = getLogin(GetPageContent(loginURL));
session(formKey, userid, password, debug);
System.out.println("Press 0 to View Menu");
break;
case 2:
product = getProduct(GetPageContent(productUrl));
// Retrieve Product ID
Product productInfo = gson.fromJson(product.getAsJsonObject(), Product.class);
// Retrieve Color
Product[] color = gson.fromJson(product.getAsJsonObject().getAsJsonObject("attributes").getAsJsonObject("92").getAsJsonArray("options"), Product[].class);
// Prepare product request
String productKey = productInfo.getProductId();
String colorId = color[0].getId();
String postUrl = productInfo.getPostUrl();
// Execute addToCart
String result = addToCart(formKey, postUrl, productKey, colorId, size, debug);
break;
case 3:
String result2 = checkout(formKey);
break;
}
} while(input != 0);
}
public static void session(String formKey, String userid, String password, Boolean debug) {
HttpPost post = new HttpPost("...");
try {
// Package the data
StringEntity entity = new StringEntity("...");
post.setEntity(entity);
// Execute the data
HttpResponse response = httpClient.execute(post);
} catch (Exception e) {
e.printStackTrace();
} finally {
post.releaseConnection();
System.out.println("Login execution completed.");
}
}
public static String addToCart(String formKey, String postUrl, String productId, String colorId, int size, Boolean debug) {
String result = "";
HttpPost post = new HttpPost(postUrl);
try {
StringEntity entity = new StringEntity("...");
post.setEntity(entity);
// Execute the data
HttpResponse response = httpClient.execute(post);
System.out.println("Response Code : "
+ response.getStatusLine().getStatusCode());
// RETURN RESULT
result = EntityUtils.toString(response.getEntity());
if(debug) {
System.out.println("LOG: " + result);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
post.releaseConnection();
System.out.println("Adding to cart execution completed.");
}
return result;
}
public static String GetPageContent(String url) throws Exception {
StringBuffer result = null;
HttpGet request = new HttpGet(url);
try {
HttpResponse response = httpClient.execute(request);
int responseCode = response.getStatusLine().getStatusCode();
System.out.println("\nSending 'GET' request to URL : " + url);
System.out.println("Response Code : " + responseCode);
BufferedReader rd = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
request.releaseConnection();
}
return result.toString();
}
public static String getLogin(String html) {
String formKey = "";
Document doc = Jsoup.parse(html);
Element loginform = doc.getElementById("login-form");
Elements inputElements = loginform.getElementsByTag("input");
for (Element inputElement : inputElements) {
String key = inputElement.attr("name");
String value = inputElement.attr("value");
if (key.equals("form_key"))
formKey = value;
}
return formKey;
}
public static JsonObject getProduct(String html)
throws UnsupportedEncodingException {
Document doc = Jsoup.parse(html);
System.out.println("Extracting form's data...");
Element form = doc.getElementById("product_addtocart_form");
Elements formElements = form.getElementsByTag("input");
String rawScript = form.getElementsByTag("script").html();
String script = "{" + rawScript.substring(rawScript.lastIndexOf("g({") + 3, rawScript.indexOf("}});")) + "}}";
// Create JSON object
JsonElement jelement = new JsonParser().parse(script.trim());
JsonObject jobject = jelement.getAsJsonObject();
jobject = jobject.getAsJsonObject();
// Retrieve post link.
jobject.addProperty("postUrl", form.attr("action"));
return jobject;
}
public static String checkout(String formKey) {
HttpPost post = new HttpPost("...");
String result = "";
try {
StringEntity entity = new StringEntity("...");
post.setEntity(entity);
HttpResponse response = httpClient.execute(post);
int status = response.getStatusLine().getStatusCode();
if(status == 200) {
result = EntityUtils.toString(response.getEntity());
System.out.println("Checkout Result: " + result);
} else if(status == 302) {
System.out.println("Checkout failed, Code: 302.");
} else if(status == 404) {
System.out.println("Checkout failed, Code: 404.");
} else if(status == 500) {
(insert retry step here)
System.out.println("Webserver is probably down. Code, 500.");
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
post.releaseConnection();
}
return result;
}
}

Related

how to post data in key/value pair? [duplicate]

This question already has answers here:
Java - sending HTTP parameters via POST method easily
(18 answers)
Closed 5 years ago.
i need to post data to particular url
in which in content i need to post html in content array and in meta headers in json format.
URL oracle = new URL("");
try (BufferedReader in = new BufferedReader(
new InputStreamReader(oracle.openStream()))) {
String inputLine1;
while ((inputLine1 = in.readLine()) != null) {
System.out.println(inputLine1);
com.eclipsesource.json.JsonObject object = Json.parse(inputLine1).asObject();
com.eclipsesource.json.JsonArray items = Json.parse(inputLine1).asObject().get("data").asArray();
for (JsonValue item : items) {
//System.out.println(item.toString());
String name = item.asObject().getString("id", "Unknown Item");
System.out.println(name);
String quantity = item.asObject().getString("url", "id");
// JSONArray jsonArray2 = new JSONArray(quantity);
System.out.println(quantity);
/* Platform.runLater(() ->{
try {
Thread.sleep(10000);
} catch (InterruptedException ex) {
Logger.getLogger(HV1.class.getName()).log(Level.SEVERE, null, ex);
}*/
Img.load(quantity);
URL url;
InputStream is = null;
BufferedReader br;
String line;
url = new URL(quantity);
is = url.openStream(); // throws an IOException
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
System.out.println(line);
byte[] postData= line.getBytes( StandardCharsets.UTF_8 );
wb2.load(line);
String originalUrl = "";
String newUrl = originalUrl.replace("ID", name);
System.out.println(newUrl);
String request = newUrl;
URL url1 = new URL( request );
HttpURLConnection conn= (HttpURLConnection) url1.openConnection();
conn.setDoOutput( true );
conn.setInstanceFollowRedirects( false );
conn.setRequestMethod( "POST" );
conn.setRequestProperty( "Content-Type", "text/plain");
conn.setRequestProperty( "charset", "utf-8");
//conn.setRequestProperty( "Content-Length", Integer.toString( line ));
conn.setUseCaches( false );
try( DataOutputStream wr = new DataOutputStream( conn.getOutputStream())) {
wr.write(postData);
System.out.println("200 ok");
this is what i tried but i had post in text/plain but i want to post in key/value pair.
updated code
URL oracle = new URL("");
try (BufferedReader in = new BufferedReader(
new InputStreamReader(oracle.openStream()))) {
String inputLine1;
while ((inputLine1 = in.readLine()) != null) {
System.out.println(inputLine1);
com.eclipsesource.json.JsonObject object = Json.parse(inputLine1).asObject();
com.eclipsesource.json.JsonArray items = Json.parse(inputLine1).asObject().get("data").asArray();
for (JsonValue item : items) {
//System.out.println(item.toString());
String name = item.asObject().getString("id", "Unknown Item");
System.out.println(name);
String quantity = item.asObject().getString("url", "id");
// JSONArray jsonArray2 = new JSONArray(quantity);
System.out.println(quantity);
/* Platform.runLater(() ->{
try {
Thread.sleep(10000);
} catch (InterruptedException ex) {
Logger.getLogger(HV1.class.getName()).log(Level.SEVERE, null, ex);
}*/
Img.load(quantity);
URL url;
InputStream is = null;
BufferedReader br;
String line;
url = new URL(quantity);
is = url.openStream(); // throws an IOException
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
System.out.println(line);
byte[] postData= line.getBytes( StandardCharsets.UTF_8 );
wb2.load(line);
String originalUrl = "";
String newUrl = originalUrl.replace("ID", name);
System.out.println(newUrl);
URL url1 = new URL(newUrl);
Map<String,Object> params = new LinkedHashMap<>();
params.put("content", postData);
params.put("meta", "abc");
StringBuilder postData1 = new StringBuilder();
for (Map.Entry<String,Object> param : params.entrySet()) {
if (postData1.length() != 0) postData1.append('&');
postData1.append(URLEncoder.encode(param.getKey(), "UTF-8"));
postData1.append('=');
postData1.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}
byte[] postDataBytes = postData1.toString().getBytes("UTF-8");
HttpURLConnection conn = (HttpURLConnection)url1.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
conn.setDoOutput(true);
conn.getOutputStream().write(postDataBytes);
Reader in1 = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
for (int c; (c = in1.read()) >= 0;)
System.out.print((char)c);
/* try{
Thread.sleep(400);
}catch(InterruptedException e){System.out.println(e);} */
}
}
}
this is my updted code(answer) this is how i solve my problem thanks for your precious time.
Take a look at this previous answer regarding HTTP Post parameters that exploit BasicNameValuePairs.
Name Value Pairs
Here is a pertinent piece of code from that answer.
HttpClient httpclient;
HttpPost httppost;
ArrayList<NameValuePair> postParameters;
httpclient = new DefaultHttpClient();
httppost = new HttpPost("your login link");
postParameters = new ArrayList<NameValuePair>();
postParameters.add(new BasicNameValuePair("param1", "param1_value"));
postParameters.add(new BasicNameValuePair("param2", "param2_value"));
httpPost.setEntity(new UrlEncodedFormEntity(postParameters, "UTF-8"));
HttpResponse response = httpclient.execute(httpPost);
Best would be using something like Spring and Jackson to create a JSON sending via a request, if you are not familiar with what you are trying to achieve:
This is just basic implementation
private final String uri = "yoururl.de/asdfasd";
private final HttpMethod httpMethod = HttpMethod.POST;
private final ContentType contentType = ContentType.json;
And EPO to transfer the Data
SendKeyValuePairsEPO implements Serializable{
private static final long serialVersionUID = 5311348008314829094L;
private final Integer startIndex;
private final Integer size;
private final Integer totalSize;
private final List<KeyValuePairEPO> values;
/**
* Contructor
*
* #param startIndex start searching index
* #param size requested result size
* #param totalSize total size of available records
* #param values the key value pairs
*/
public SendKeyValuePairsEPO(#JsonProperty("startIndex") final Integer startIndex,
#JsonProperty("size") final Integer size,
#JsonProperty("totalSize") final Integer totalSize,
#JsonProperty("values") final List<KeyValuePairEPO> values) {
this.startIndex = startIndex;
this.size = size;
this.totalSize = totalSize;
this.values = values;
}
and aswell a KeyValuePairEPO:
KeyValuePairEPO implements Serializable{
private static final long serialVersionUID = 5311348008314829094L;
private final String key;
private final String value;
private final String type; //maybe you need a type to tell what kind of value it is
...
And at last you will need to do something like:
/*package*/ <T> T sendRequest(Class<T> responseClass, Object requestEpo, String uri) {
try {
//Parse encapsulated COntent type to media type
HttpHeaders headers = new HttpHeaders();
MediaType requestContentType requestContentType = MediaType.APPLICATION_JSON;
//Set content type and accept header to this type
headers.setContentType(requestContentType);
headers.setAccept(Collections.singletonList(requestContentType));
//Parse the data object to a JSON
String requestJSONAsString = "";
if (request.getData() != null) {
try {
requestJSONAsString = RestObjectMapper.getInstance().writeValueAsString(requestEpo);
} catch (JsonProcessingException ex) {
throw new InternalServerErrorException(String.format("Error parsing: %s", requestEpo.getClass().getSimpleName()), ex);
}
}
//Perform the send request
return sendRequest(responseClass, uri, headers, httpMethod, requestJSONAsString);
} finally {
LOG.debug("Ended sendRequest");
}
}
private <T> T sendRequest(final Class<T> responseClass, final String uri, final HttpHeaders httpHeaders, final HttpMethod httpMethod, String requestJSON) {
try {
LOG.debug(String.format("Start sendRequest with:%s %s %s %s", uri, httpHeaders, httpMethod, requestJSON));
RestTemplate rest = new RestTemplate();
ClientHttpRequestFactory restFactory = rest.getRequestFactory();
if(restFactory instanceof SimpleClientHttpRequestFactory){
((SimpleClientHttpRequestFactory)restFactory).setReadTimeout(REQUEST_TIMEOUT);
((SimpleClientHttpRequestFactory)restFactory).setConnectTimeout(REQUEST_TIMEOUT);
}
HttpEntity<String> entity = new HttpEntity<>(requestJSON, httpHeaders);
final ResponseEntity<String> response = rest.exchange(uri, httpMethod, entity, String.class);
LOG.debug("Status:" + response.getStatusCode().toString());
String returnedPayload = response.getBody();
return RestObjectMapper.getInstance().readValue(returnedPayload, responseClass);
} catch (HttpStatusCodeException ex) {
LOG.error("HTTP Error in sendRequest: " + ex.getMessage());
switch (ex.getStatusCode()) {
case BAD_REQUEST:
throw new BadRequestException(uri, ex);
case NOT_FOUND:
throw new NotFoundException(uri, ex);
case FORBIDDEN:
throw new ForbiddenException(uri, ex);
case REQUEST_TIMEOUT:
throw new RequestTimeoutException(ex, REQUEST_TIMEOUT);
default:
throw new InternalServerErrorException(ex);
}
} catch (Exception ex) {
LOG.error("Error in sendRequest: " + ex.getMessage());
throw new InternalServerErrorException(ex);
} finally {
LOG.debug("Ended sendRequest");
}
}
where RestObjectMapper is:
public class RestObjectMapper extends ObjectMapper {
public static final String EMPTY_JSON = "{}";
private static final long serialVersionUID = 3924442982193452932L;
/**
* Singleton Instance
* Pattern: Initialization-on-demand holder idiom:
* <ul>
* <li>the class loader loads classes when they are first accessed (in this case Holder's only access is within the getInstance() method)</li>
* <li>when a class is loaded, and before anyone can use it, all static initializers are guaranteed to be executed (that's when Holder's static block fires)</li>
* <li>the class loader has its own synchronization built right in that make the above two points guaranteed to be threadsafe</li></ul>
*/
private static class INSTANCE_HOLDER {
private static final RestObjectMapper INSTANCE = new RestObjectMapper();
}
private RestObjectMapper() {
super();
configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
configure(DeserializationFeature.UNWRAP_ROOT_VALUE, false);
configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
}
/**
* Gets the singleton Instance of the JSON Mapper
*
* #return the singleton instance
*/
public static RestObjectMapper getInstance() {
return INSTANCE_HOLDER.INSTANCE;
}
By the way ResponseClass is another EPO the result (JSON) will be mapped to.

How to make a correct Json Deserialization to a Java Object?

I really need help here, im Deserializing the next json:
{
"name":"myname",
"userID":"12345",
"password":"sha1passwordASDESFSGSD",
"active":"1",
"profile":"2",
"job":"Manager"
}
Im using Jersey to create webService, when i recive the json i recive it as a InputStream
Also i tried with a String
#POST
#Path("user/in/")
#Produces("application/json")
public String InsertUser(InputStream inStr)
{
String line = null, res = "POST 200 > ";
BufferedReader br = new BufferedReader(new InputStreamReader(inStr));
try {
while ((line = br.readLine()) != null) {
System.out.println(line);
res += line;
}
} catch (IOException e) {
e.printStackTrace();
}
try {
UserInformation user = new Gson().fromJson(res, UserInformation.class);
System.out.println("All done");
System.out.println(user.getName());
} catch (Exception e) {
System.out.println("Error al convertir jo object " + e.getCause() + e.getMessage());
}
return "POST 200 > ";
}
I tried using a InputStreamReader:
#POST
#Path("user/in/")
#Produces("application/json")
public String InsertUser(InputStream inStr)
{
try {
InputStreamReader isr = new InputStreamReader(inStr);
UserInformation user = new Gson().fromJson(isr, UserInformation.class);
System.out.println("All done");
System.out.println(user.getName());
} catch (Exception e) {
System.out.println("Error al convertir jo object " + e.getCause() + e.getMessage());
}
return "POST 200 > ";
}
Neither of those codes work. They don't throw an exception or print "All done".
When i debug the object, user doesn't appear in the variables menu.
In my experience, is because an error is happening in the line UserInformation user = new Gson().fromJson(isr, UserInformation.class);
But i cant see which one is.
My UserInformation Class is the next
public class UserInformation {
private String name;
private String userID;
private String password;
private String active;
private String profile;
private String job;
// Methods removed for brevity
}
I am assuming you are using Google gson. Here is my answer:
#Post
#Path("user/in")
#Produces(MediaType.APPLICATION_JSON)
public Response InsertUser(string json){
JsonElement jsonElement = new JsonParser().parse(json);
JsonObject object = jsonElement.getAsJsonObject();
String name = object.getAsJsonPrimitive("name").getAsString();
int userID = object.getAsJsonPrimitve("userID").getAsInt();
String password = object.getAsJsonPrimitive("password").getAsString();
String job = object.getAsJsonPrimitive("job").getAsString();
int active = object.getAsJsonPrimitve("active").getAsInt();
int profile = object.getAsJsonPrimitve("profile").getAsInt();
return Response.status(Response.Status.OK).entity("all done").build();
}
I already find the solution, the problem was that i was receiving a InputStream,
following its recommendations the solution code is:
#POST
#Path("users/in/")
#Produces(MediaType.APPLICATION_JSON)
public String InsertUser(String json)
{
try{
UserInformation user = new Gson().fromJson(json, UserInformation.class);
String name = user.getName();
String userID = user.getUserID();
String password = user.getPassword();
String job = user.getJob();
String active = user.getActive();
String profile = user.getProfile();
}catch(Exception e){
System.out.println(Response.status(500).entity(e.getCause() + e.getMessage()).build().toString());
return Response.status(500).entity(e.getCause() + e.getMessage()).build().toString();
}
}

Smartsheet 2.0 api return all sheets in your account

Just started making a program to upload data into a smartsheet. Problem is i am getting the error "Invalid Accept header. Media type not supported. " its happening here
connection = (HttpURLConnection) new URL(GET_SHEETS_URL).openConnection();
connection.addRequestProperty("Authorization", "Bearer " + accessToken);
here is what i have taken from smartsheet github
public class JavaSDKSample {
private static final String BASE_URL = "https://api.smartsheet.com/2.0";
private static final String GET_SHEETS_URL = BASE_URL + "/sheets";
private static final String SHEET_ID = "{sheetId}";
private static final String SHARE_SHEET_URL = BASE_URL + "/sheet/" + SHEET_ID + "/shares";
public static void main(String[] args) {
HttpURLConnection connection = null;
StringBuilder response = new StringBuilder();
//We are using Jackson JSON parser to deserialize the JSON. See http://wiki.fasterxml.com/JacksonHome
//Feel free to use which ever library you prefer.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
System.out.println("STARTING HelloSmartsheet...");
//Create a BufferedReader to read user input.
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter Smartsheet API access token:");
String accessToken = in.readLine();
System.out.println("Fetching list of your sheets...");
//Create a connection and fetch the list of sheets
connection = (HttpURLConnection) new URL(GET_SHEETS_URL).openConnection();
connection.addRequestProperty("Authorization", "Bearer " + accessToken);
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
//Read the response line by line.
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
//Use Jackson to convert the JSON string to a List of Sheets
List<Sheet> sheets
= mapper.readValue(response.toString(), new TypeReference<List<Sheet>>() {});
if (sheets.size() == 0) {
System.out.println("You don't have any sheets. Goodbye!");
return;
}
System.out.println("Total sheets: " + sheets.size());
int i = 1;
for (Sheet sheet : sheets) {
System.out.println( i++ + ": " + sheet.name);
}
System.out.print("Enter the number of the sheet you want to share: ");
//Prompt the user to provide the sheet number, the email address, and the access level
Integer sheetNumber = Integer.parseInt(in.readLine().trim()); //NOTE: for simplicity, error handling and input validation is neglected.
Sheet chosenSheet = sheets.get(sheetNumber - 1);
System.out.print("Enter an email address to share " + chosenSheet.getName() + " to: ");
String email = in.readLine();
System.out.print("Choose an access level (VIEWER, EDITOR, EDITOR_SHARE, ADMIN) for " + email + ": " );
String accessLevel = in.readLine();
//Create a share object
Share share = new Share();
share.setEmail(email);
share.setAccessLevel(accessLevel);
System.out.println("Sharing " + chosenSheet.name + " to " + email + " as " + accessLevel + ".");
//Create a connection. Note the SHARE_SHEET_URL uses /sheet as opposed to /sheets (with an 's')
connection = (HttpURLConnection) new URL(SHARE_SHEET_URL.replace(SHEET_ID, "" + chosenSheet.getId())).openConnection();
connection.setDoOutput(true);
connection.addRequestProperty("Authorization", "Bearer " + accessToken);
connection.addRequestProperty("Content-Type", "application/json");
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
//Serialize the Share object
writer.write(mapper.writeValueAsString(share));
writer.close();
//Read the response and parse the JSON
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
Result result = mapper.readValue(response.toString(), Result.class);
System.out.println("Sheet shared successfully, share ID " + result.result.id);
System.out.println("Press any key to quit.");
in.read();
} catch (IOException e) {
BufferedReader reader = new BufferedReader(new InputStreamReader(((HttpURLConnection) connection).getErrorStream()));
String line;
try {
response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
Result result = mapper.readValue(response.toString(), Result.class);
System.out.println(result.message);
} catch (IOException e1) {
e1.printStackTrace();
}
} catch (Exception e) {
System.out.println("Something broke: " + e.getMessage());
e.printStackTrace();
}
}
public static class Sheet {
Long id;
String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static class Share {
String email;
String accessLevel;
Long id;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAccessLevel() {
return accessLevel;
}
public void setAccessLevel(String accessLevel) {
this.accessLevel = accessLevel;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
public static class Result {
String message;
Share result;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Share getResult() {
return result;
}
public void setResult(Share result) {
this.result = result;
}
}
}
The error message Invalid Accept header is your clue. You need to set the appropriate Accept header, in this case application/json.
Add the following line just below the line where you set your connection variable.
connection.setRequestProperty("Accept", "application/json");
Also, you may be interested in using the existing SDKs that are available for Smartsheet, listed here.

Subsequent httpClient calls return initial calls results

I have these methods in a class called HttpHelper. Now the initial call validates user credentials and returns true. That is expected. The next call is to register a user. That seems to go fine with no hiccups and is to return the new user ID. Instead of returning the user ID it returns true again. Almost like it is cached and just returning the result from the initial call. Anyone have any thoughts as to why this might occur?
private static CookieStore sCookieStore;
private static String invoke(HttpUriRequest request)
throws ClientProtocolException, IOException {
String result = null;
DefaultHttpClient httpClient = new DefaultHttpClient();
// restore cookie
if (sCookieStore != null) {
httpClient.setCookieStore((org.apache.http.client.CookieStore) sCookieStore);
}
//request.addHeader("Host", "localhost");
HttpResponse response = httpClient.execute(request);
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(
response.getEntity().getContent()));
for (String s = reader.readLine(); s != null; s = reader.readLine()) {
builder.append(s);
}
result = builder.toString();
Log.d(TAG, "result is ( " + result + " )");
// store cookie
sCookieStore = (CookieStore) ((AbstractHttpClient) httpClient).getCookieStore();
return result;
}
public static String invokeGet(String action, List<NameValuePair> params) {
try {
StringBuilder sb = new StringBuilder(API_URL);
sb.append(action);
if (params != null) {
for (NameValuePair param : params) {
sb.append("?");
sb.append(param.getName());
sb.append("=");
sb.append(param.getValue());
}
}
Log.d(TAG, "url is" + sb.toString());
//HttpGet httpGet = new HttpGet(URLEncoder.encode(sb.toString(), "UTF-8"));
HttpGet httpGet = new HttpGet(sb.toString());
return invoke(httpGet);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
return null;
}
public static String invokeGet(String action) {
return invokeGet(action, null);
}
Here are the calls I am making. As specified above the authResult variable would result in a string result of true. The nextResult should hold the user ID value but instead holds the value true like from the initial request:
String authResult = HttpHelper.invokeGet("<url to validate user>");
if (this.URL.indexOf("register") > -1)
String nextResult = HttpHelper.invokeGet(this.URL);
else
String nextResult = HttpHelper.invokeGet(this.URL);
UPDATED: added in the sCookieStore variable.
UPDATED 2: adding in the methods that are being called via the API (MVC .NET):
authResult variable would get this result:
public bool Get(String userName, String userPassword)
{
Task<IdentityUser> iu = _repo.FindUser(userName, userPassword);
if (iu != null)
{
FormsAuthentication.SetAuthCookie(userName, false);
return true;
}
return false;
}
nextResult variable should get this result:
[HttpGet]
[AllowAnonymous]
public async Task<IHttpActionResult> RegisterUser(String userName, String userPassword, String huh)
{
UserModel userModel = new UserModel();
userModel.ConfirmPassword = userPassword;
userModel.UserName = userName;
userModel.Password = userPassword;
String userID = "";
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result = await _repo.RegisterUser(userModel);
IHttpActionResult errorResult = GetErrorResult(result);
if (errorResult != null)
{
return errorResult;
}
else
{
Task<IdentityUser> iu = _repo.FindUser(userModel.UserName, userModel.Password);
using (var context = new AuthContext())
{
var userStore = new UserStore<IdentityUser>(context);
var userManager = new UserManager<IdentityUser>(userStore);
userID = iu.Result.Id;
result = await userManager.AddToRoleAsync(userID, "Users");
errorResult = GetErrorResult(result);
if (errorResult != null)
{
return errorResult;
}
}
}
return Ok("userID:" + userID);
}
It looks like authResult is going to fire invokeGet 2 times, giving it the same argument (this.URL). Within invokeGet, the variable sb is going to be this.URL both times the function fires.
This is a bit curious to me:
// restore cookie
if (sCookieStore != null) {
httpClient.setCookieStore((org.apache.http.client.CookieStore) sCookieStore);
}
then at the end,
// store cookie
sCookieStore = (CookieStore) ((AbstractHttpClient) httpClient).getCookieStore();
When is sCookieStore defined? It could be that the cookies aren't being handled correctly and you're making two fresh connections. If getting and setting the cookies is the issue, it might be better to get a cookie if it exists at the beginning of invoke, then set the new one at the end.

commons httpclient - Adding query string parameters to GET/POST request

I am using commons HttpClient to make an http call to a Spring servlet. I need to add a few parameters in the query string. So I do the following:
HttpRequestBase request = new HttpGet(url);
HttpParams params = new BasicHttpParams();
params.setParameter("key1", "value1");
params.setParameter("key2", "value2");
params.setParameter("key3", "value3");
request.setParams(params);
HttpClient httpClient = new DefaultHttpClient();
httpClient.execute(request);
However when i try to read the parameter in the servlet using
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest().getParameter("key");
it returns null. In fact the parameterMap is completely empty. When I manually append the parameters to the url before creating the HttpGet request, the parameters are available in the servlet. Same when I hit the servlet from the browser using the URL with queryString appended.
What's the error here? In httpclient 3.x, GetMethod had a setQueryString() method to append the querystring. What's the equivalent in 4.x?
Here is how you would add query string parameters using HttpClient 4.2 and later:
URIBuilder builder = new URIBuilder("http://example.com/");
builder.setParameter("parts", "all").setParameter("action", "finish");
HttpPost post = new HttpPost(builder.build());
The resulting URI would look like:
http://example.com/?parts=all&action=finish
If you want to add a query parameter after you have created the request, try casting the HttpRequest to a HttpBaseRequest. Then you can change the URI of the casted request:
HttpGet someHttpGet = new HttpGet("http://google.de");
URI uri = new URIBuilder(someHttpGet.getURI()).addParameter("q",
"That was easy!").build();
((HttpRequestBase) someHttpGet).setURI(uri);
The HttpParams interface isn't there for specifying query string parameters, it's for specifying runtime behaviour of the HttpClient object.
If you want to pass query string parameters, you need to assemble them on the URL yourself, e.g.
new HttpGet(url + "key1=" + value1 + ...);
Remember to encode the values first (using URLEncoder).
I am using httpclient 4.4.
For solr query I used the following way and it worked.
NameValuePair nv2 = new BasicNameValuePair("fq","(active:true) AND (category:Fruit OR category1:Vegetable)");
nvPairList.add(nv2);
NameValuePair nv3 = new BasicNameValuePair("wt","json");
nvPairList.add(nv3);
NameValuePair nv4 = new BasicNameValuePair("start","0");
nvPairList.add(nv4);
NameValuePair nv5 = new BasicNameValuePair("rows","10");
nvPairList.add(nv5);
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
URI uri = new URIBuilder(request.getURI()).addParameters(nvPairList).build();
request.setURI(uri);
HttpResponse response = client.execute(request);
if (response.getStatusLine().getStatusCode() != 200) {
}
BufferedReader br = new BufferedReader(
new InputStreamReader((response.getEntity().getContent())));
String output;
System.out.println("Output .... ");
String respStr = "";
while ((output = br.readLine()) != null) {
respStr = respStr + output;
System.out.println(output);
}
This approach is ok but will not work for when you get params dynamically , sometimes 1, 2, 3 or more, just like a SOLR search query (for example)
Here is a more flexible solution. Crude but can be refined.
public static void main(String[] args) {
String host = "localhost";
String port = "9093";
String param = "/10-2014.01?description=cars&verbose=true&hl=true&hl.simple.pre=<b>&hl.simple.post=</b>";
String[] wholeString = param.split("\\?");
String theQueryString = wholeString.length > 1 ? wholeString[1] : "";
String SolrUrl = "http://" + host + ":" + port + "/mypublish-services/carclassifications/" + "loc";
GetMethod method = new GetMethod(SolrUrl );
if (theQueryString.equalsIgnoreCase("")) {
method.setQueryString(new NameValuePair[]{
});
} else {
String[] paramKeyValuesArray = theQueryString.split("&");
List<String> list = Arrays.asList(paramKeyValuesArray);
List<NameValuePair> nvPairList = new ArrayList<NameValuePair>();
for (String s : list) {
String[] nvPair = s.split("=");
String theKey = nvPair[0];
String theValue = nvPair[1];
NameValuePair nameValuePair = new NameValuePair(theKey, theValue);
nvPairList.add(nameValuePair);
}
NameValuePair[] nvPairArray = new NameValuePair[nvPairList.size()];
nvPairList.toArray(nvPairArray);
method.setQueryString(nvPairArray); // Encoding is taken care of here by setQueryString
}
}
This is how I implemented my URL builder.
I have created one Service class to provide the params for the URL
public interface ParamsProvider {
String queryProvider(List<BasicNameValuePair> params);
String bodyProvider(List<BasicNameValuePair> params);
}
The Implementation of methods are below
#Component
public class ParamsProviderImp implements ParamsProvider {
#Override
public String queryProvider(List<BasicNameValuePair> params) {
StringBuilder query = new StringBuilder();
AtomicBoolean first = new AtomicBoolean(true);
params.forEach(basicNameValuePair -> {
if (first.get()) {
query.append("?");
query.append(basicNameValuePair.toString());
first.set(false);
} else {
query.append("&");
query.append(basicNameValuePair.toString());
}
});
return query.toString();
}
#Override
public String bodyProvider(List<BasicNameValuePair> params) {
StringBuilder body = new StringBuilder();
AtomicBoolean first = new AtomicBoolean(true);
params.forEach(basicNameValuePair -> {
if (first.get()) {
body.append(basicNameValuePair.toString());
first.set(false);
} else {
body.append("&");
body.append(basicNameValuePair.toString());
}
});
return body.toString();
}
}
When we need the query params for our URL, I simply call the service and build it.
Example for that is below.
Class Mock{
#Autowired
ParamsProvider paramsProvider;
String url ="http://www.google.lk";
// For the query params price,type
List<BasicNameValuePair> queryParameters = new ArrayList<>();
queryParameters.add(new BasicNameValuePair("price", 100));
queryParameters.add(new BasicNameValuePair("type", "L"));
url = url+paramsProvider.queryProvider(queryParameters);
// You can use it in similar way to send the body params using the bodyProvider
}
Im using Java 8 and apache httpclient 4.5.13
HashMap<String, String> customParams = new HashMap<>();
customParams.put("param1", "ABC");
customParams.put("param2", "123");
URIBuilder uriBuilder = new URIBuilder(baseURL);
for (String paramKey : customParams.keySet()) {
uriBuilder.addParameter(paramKey, customParams.get(paramKey));
}
System.out.println(uriBuilder.build().toASCIIString()); // ENCODED URL
System.out.println(uriBuilder.build().toString); // NORMAL URL
Full example with DTO
public class HttpResponseDTO {
private Integer statusCode;
private String body;
private String errorMessage;
public Integer getStatusCode() {
return statusCode;
}
public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}
/**
*
* #param destinationURL
* #param params
* #param headers
* #return HttpResponseDTO
*/
public static HttpResponseDTO get(String baseURL, Boolean encodeURL, HashMap<String, String> params, HashMap<String, String> headers) {
final HttpResponseDTO httpResponseDTO = new HttpResponseDTO();
// ADD PARAMS IF
if (params != null && Boolean.FALSE.equals(params.isEmpty())) {
URIBuilder uriBuilder;
try {
uriBuilder = new URIBuilder(baseURL);
for (String paramKey : params.keySet()) {
uriBuilder.addParameter(paramKey, params.get(paramKey));
}
// CODIFICAR URL ?
if (Boolean.TRUE.equals(encodeURL)) {
baseURL = uriBuilder.build().toASCIIString();
} else {
baseURL = uriBuilder.build().toString();
}
} catch (URISyntaxException e) {
httpResponseDTO.setStatusCode(500);
httpResponseDTO.setErrorMessage("ERROR AL CODIFICAR URL: " + e.getMessage());
return httpResponseDTO;
}
}
// HACER PETICION HTTP
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
final HttpGet get = new HttpGet(baseURL);
// ADD HEADERS
if (headers != null && Boolean.FALSE.equals(headers.isEmpty())) {
for (String headerKey : headers.keySet()) {
get.setHeader(headerKey, headers.get(headerKey));
}
}
try (CloseableHttpResponse response = httpClient.execute(get);) {
HttpEntity httpEntity = response.getEntity();
if (httpEntity != null) {
httpResponseDTO.setBody(EntityUtils.toString(httpEntity));
httpResponseDTO.setStatusCode(response.getStatusLine().getStatusCode());
}
} catch(Exception e) {
httpResponseDTO.setStatusCode(500);
httpResponseDTO.setErrorMessage(e.getMessage());
return httpResponseDTO;
}
} catch(Exception e) {
httpResponseDTO.setStatusCode(500);
httpResponseDTO.setErrorMessage(e.getMessage());
return httpResponseDTO;
}
return httpResponseDTO;
}

Categories