Can you tell me please how to create http(s) request in jsoup with request method PUT or DELETE?
I came across this link:
https://github.com/jhy/jsoup/issues/158
but it is few years old, so hopefully there is some restful support implemented in that library.
As far as I can see HttpConnection object I can only use 'get' or 'post' request methods.
http://jsoup.org/apidocs/org/jsoup/helper/HttpConnection.html
http://jsoup.org/apidocs/org/jsoup/Connection.html
Jsoup doesn't support PUT nor DELETE methods. Since it is a parser, it doesn't need to support those operations. What you can do is use HttpURLConnection , which is the same that Jsoup uses underneath. With this you can use whatever method you want and in the end parse the result with jsoup (if you really need it).
Check this code :
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
public class Main {
public static void main(String[] args) {
try {
String rawData = "RAW_DATA_HERE";
String url = "URL_HERE";
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
//add reuqest header
con.setRequestMethod("METHOD_HERE"); //e.g POST
con.setRequestProperty("KEY_HERE", "VALUE_HERE"); //e.g key = Accept, value = application/json
con.setDoOutput(true);
OutputStreamWriter w = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
w.write(rawData);
w.close();
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println("Response code : " + responseCode);
System.out.println(response.toString());
//Use Jsoup on response to parse it if it makes your work easier.
} catch(Exception e) {
e.printStackTrace();
}
}
}
Related
I understand that I cannot directly call a future method from a batch class. But from many other answers, I can see that it is possible to do so by creating a helper class and calling the future method there. But it is not working for me. Please check my code below.
Also, I have tried to do it with the queueable class as suggested in this link, but it is not working for me. The error was " Callout not allowed from this future method. Please enable callout by annotating the future method. eg: #Future(callout=true)"
But I am more interested in the first and simpler way to do this.
public class OrdersItemsHelper {
static Document tDoc;
static blob csvBlob;
//prepare csv file to send
public static void CreateCsvFile(List<Order_Line_Items__c> orderItemsList)
{
//Code to create file here
csvBlob = Blob.valueOf(finalstr);
tDoc = new Document();
tDoc.Name = 'sales_items_' +date.today();
tDoc.Type = 'csv';
tDoc.body = csvBlob;
tDoc.FolderId = [select id from folder where name = 'Emarsys Order Files'].Id;
tDoc.ContentType = 'application/vnd.ms-excel';
Insert tDoc;
system.debug('doc inserted');
sendFile();
}
#Future(callout = true)
public static void sendFile()
{
System.debug('I am creating the post request');
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setMethod('POST');
request.setHeader('Authorization','Security Token');
request.setHeader('Accept','text/plain');
request.setHeader('Content-Type', 'text/csv');
request.setHeader('Authorization', 'Bearer ');
request.setBodyAsBlob(csvBlob);
HttpResponse response = http.send(request);
system.debug('response: ' + response);
}
So I tried again by doing it in the queueable apex class. The thing I was missing was "Database.AllowsCallouts" in the class heading. Below is my queueable class which is working with the batch class to send a rest post request.
public class OrderItemFilePostHelper implements System.Queueable,Database.AllowsCallouts
{
private Blob csvBlob;
public EmarsysOrderItemFilePostHelper(Blob csvBlob) {
this.csvBlob = csvBlob;
}
public void execute(System.QueueableContext objContext)
{
System.debug('I am creating the post request');
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setMethod('POST');
request.setHeader('Authorization','Security Token');
request.setHeader('Accept','text/plain');
request.setHeader('Content-Type', 'text/csv');
request.setHeader('Authorization', 'Bearer ');
request.setEndpoint('https://webhook.site/b0746268-e95c-4f94-bcb6-61d4bea54378');
request.setBodyAsBlob(csvBlob);
HttpResponse response = http.send(request);
system.debug('response: ' + response);
}
}
I want to test http request/response. So I use WireMock.
I want to stub response for specific request:
Here code:
public class WireMockPersons {
#Rule
public WireMockRule wireMockRule = new WireMockRule(8089);
#Test
public void exactUrlOnly() {
stubFor(get(urlEqualTo("/some/thing"))
.willReturn(aResponse()
.withHeader("Content-Type", "text/plain")
.withBody("Hello world!")));
assertThat(testClient.get("/some/thing").statusCode(), is(200));
assertThat(testClient.get("/some/thing/else").statusCode(), is(404));
}
Code is not compile because no object testClient. How I can get testClient object?
testClient is your client library for the API you are mocking.
Looks like you have copied directly from the examples which are indicative only.
Replace testClient with the HTTP library of your choosing, for example HttpClient.
String url = "http://localhost:8089/some/thing";
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
HttpGet get = new HttpGet(url);
HttpEntity entity = client.execute(get).getEntity();
return EntityUtils.toString(entity, "UTF-8");
} catch (IOException e) {
throw new RuntimeException("Unable to call " + url, e);
}
I am trying to upload an image to a server using Angular as the front end and java ee web service jax rs rest easy as my back end. This my code for the angular/front end:
HTML page:
<md-card>
<input type="file" (change)="onChange($event)" placeholder="Upload files" >
</md-card>
For the component:
fileChange(event) {
let fileList: FileList = event.target.files;
let fileListLength = fileList.length;
if(fileListLength > 0) {
let formData:FormData = new FormData();
for (var i = 0; i < fileListLength; i++) {
formData.append("uploadFile[]", fileList[i]);
}
let headers = new Headers();
headers.append('Content-Type', 'multipart/form-data');
headers.append('Accept', 'application/json');
let options = new RequestOptions({ headers: headers });
this.http.post("http://localhost:8080/BCWEB/uploadProdImage", formData, options)
.map(res => res.json())
.catch(error => Observable.throw(error))
.subscribe(
data => console.log('success'),
error => console.log(error)
)
}
}
For the backend java ee restful web service:
private static final String SERVER_UPLOAD_LOCATION_FOLDER = "C://Users/007EAA/Downloads/tes/";
#POST
#Path("/uploadProdImage")
#Consumes("multipart/form-data")
public Response uploadFile2(MultipartFormDataInput input) {
String fileName = "";
Map<String, List<InputPart>> formParts = input.getFormDataMap();
List<InputPart> inPart = formParts.get("file");
for (InputPart inputPart : inPart) {
try {
// Retrieve headers, read the Content-Disposition header to obtain the original name of the file
MultivaluedMap<String, String> headers = inputPart.getHeaders();
fileName = parseFileName(headers);
// Handle the body of that part with an InputStream
InputStream istream = inputPart.getBody(InputStream.class,null);
fileName = SERVER_UPLOAD_LOCATION_FOLDER + fileName;
saveFile(istream,fileName);
} catch (IOException e) {
e.printStackTrace();
}
}
String output = "File saved to server location : " + fileName;
return Response.status(200).entity(output).build();
}
// Parse Content-Disposition header to get the original file name
private String parseFileName(MultivaluedMap<String, String> headers) {
String[] contentDispositionHeader = headers.getFirst("Content-Disposition").split(";");
for (String name : contentDispositionHeader) {
if ((name.trim().startsWith("filename"))) {
String[] tmp = name.split("=");
String fileName = tmp[1].trim().replaceAll("\"","");
return fileName;
}
}
return "randomName";
}
// save uploaded file to a defined location on the server
private void saveFile(InputStream uploadedInputStream,
String serverLocation) {
try {
OutputStream outpuStream = new FileOutputStream(new File(serverLocation));
int read = 0;
byte[] bytes = new byte[1024];
outpuStream = new FileOutputStream(new File(serverLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
outpuStream.write(bytes, 0, read);
}
outpuStream.flush();
outpuStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
The problem is No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had an HTTP status code of 500.
But when I try to add a user on the server, it gets added without any problem, so it's not a server problem. Can anyone help?
The issue is that your frontend and backend exist across different local hosts, and by default cross-origin requests are denied for security reasons.
You'll want to enable cross origin requests on your backend during testing, and disable it for production when your frontend and backend live in the same area. To enable cross origin, you'll need to add this provider snippet:
package com.yourdomain.package;
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public void filter(final ContainerRequestContext requestContext,
final ContainerResponseContext cres) throws IOException {
cres.getHeaders().add("Access-Control-Allow-Origin", "*");
cres.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
cres.getHeaders().add("Access-Control-Allow-Credentials", "true");
cres.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
cres.getHeaders().add("Access-Control-Max-Age", "1209600");
}
}
Info on CORS
Snippet pulled from this SO question
I am using Apache HttpClient to put/get customized object using REST APIs. Below is the sample code. My putObject() method works fine and I could serialize Person object and put properly. However, while getting the object, I got below error:
Exception in thread "main" java.lang.ClassCastException: [B cannot be cast to Person at MyTest.demoGetRESTAPI(MyTest.java:88) at MyTest.main(MyTest.java:21)
Seems the code to build Person object out of response entity is not correct
HttpEntity httpEntity = response.getEntity();
byte[] resultByteArray = EntityUtils.toByteArray(httpEntity);
Person person = (Person)SerializationUtils.deserialize(resultByteArray);
Am I doing somthing wrong while getting byte[] array and converting to Person object. Please help me out to solve this issue.
Complete Example Program:
import java.io.Serializable;
import org.apache.commons.lang.SerializationUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.SerializableEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
public class MyTest {
public static void main(String[] args) throws Exception {
putObject();
getObject();
}
public static void putObject() throws Exception
{
HttpClient httpClient = new DefaultHttpClient();
Person person = new Person();
person.setName("Narendra");
person.setId("1");
try
{
//Define a postRequest request
HttpPut putRequest = new HttpPut("http://localhost:9084/ehcache-server/rest/screeningInstance/2221");
//Set the API media type in http content-type header
putRequest.addHeader("content-type", "application/x-java-serialized-object");
//Set the request put body
SerializableEntity personSEntity = new SerializableEntity(SerializationUtils.serialize(person));
putRequest.setEntity(personSEntity);
//Send the request; It will immediately return the response in HttpResponse object if any
HttpResponse response = httpClient.execute(putRequest);
//verify the valid error code first
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != 201)
{
throw new RuntimeException("Failed with HTTP error code : " + statusCode);
}
}
finally
{
//Important: Close the connect
httpClient.getConnectionManager().shutdown();
}
}
public static void getObject() throws Exception
{
DefaultHttpClient httpClient = new DefaultHttpClient();
try
{
//Define a HttpGet request; You can choose between HttpPost, HttpDelete or HttpPut also.
//Choice depends on type of method you will be invoking.
HttpGet getRequest = new HttpGet("http://localhost:9084/ehcache-server/rest/screeningInstance/2221");
//Set the API media type in http accept header
getRequest.addHeader("accept", "application/x-java-serialized-object");
//Send the request; It will immediately return the response in HttpResponse object
HttpResponse response = httpClient.execute(getRequest);
//verify the valid error code first
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != 200)
{
throw new RuntimeException("Failed with HTTP error code : " + statusCode);
}
//Now pull back the response object
HttpEntity httpEntity = response.getEntity();
byte[] resultByteArray = EntityUtils.toByteArray(httpEntity);
Person person = (Person)SerializationUtils.deserialize(resultByteArray);
}
finally
{
//Important: Close the connect
httpClient.getConnectionManager().shutdown();
}
}
}
class Person implements Serializable{
String name;
String id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#Override
public String toString() {
return "Person [name=" + name + ", id=" + id + "]";
}
}
I got the solution. It was mistake in my code:
While putting object, I have written below code. That was doing two time serialization. First from Person object to byte[] and second from byte[] to byte[].
SerializableEntity personSEntity = new SerializableEntity(SerializationUtils.serialize(person));
putRequest.setEntity(personSEntity);
This is the right approach:
SerializableEntity personSEntity = new SerializableEntity(person);
putRequest.setEntity(personSEntity);
After getting binary from REST, code should be like below to get Object:
HttpEntity httpEntity = response.getEntity();
InputStream inputStream = null;
try {
inputStream = httpEntity.getContent();
Person p = (Person) SerializationUtils.deserialize(inputStream);
System.out.println("Person:" + p.getName());
}
finally {
inputStream.close();
}
This worked like CHARM !!
package java4s;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/vinay")
public class JsonFromRestful {
#POST
#Path("/{runID}/{tweetID}/{tweet : .*}")
#Produces(MediaType.TEXT_PLAIN)
public String sayPlainTextHello( #PathParam("runID") String rid,
#PathParam("tweetID") String tid,
#PathParam("tweet") String twt) throws IOException, InterruptedException {
StringBuffer resneel=new StringBuffer();
resneel.append(rid);
resneel.append(tid);
resneel.append(twt);
return return resneel.toString();
}
}
client test program
package neel;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.core.util.MultivaluedMapImpl;
/*
* excerpt of the maven dependencies
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.19</version>
</dependency>
*/
public class ClientTest {
public static void main(String[] args)
{
if(args.length != 4)
{
System.out.println("Incorrect parameters, usage:");
System.out.println("java -jar neelclienttest.jar run_id tweet_id tweet_to_annotate rest_api");
System.exit(1);
}
String runID = args[0];
String tweetID = args[1];
String tweet = args[2];
String uri = args[3];
try {
String annotations = annotate(uri, runID, tweetID, tweet);
System.out.println(annotations);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String annotate(String uri, String runID, String tweetID, String tweet) throws Exception
{
Client client = Client.create();
WebResource webResource = client.resource(uri);
MultivaluedMap<String,String> params = new MultivaluedMapImpl();
params.add("RunID", runID);
params.add("TweetID", tweetID);
params.add("Tweet", tweet);
ClientResponse response = webResource.
accept(MediaType.TEXT_PLAIN_TYPE).
post(ClientResponse.class, params);
// check if status code != 200 OK
if ( response.getStatus() != 200 )
throw new Exception ("The REST interface has answered with an unexpected status code" + response.getStatus());
return response.getEntity(String.class);
}
}
here i am giving command line arguements runid tweetid tweet and the path is http://localhost/cen_neel/vinay/ but it is showing java.lang exception. we created a webservice and whatever i have given clienttest is for testing. i dont need any changes in clienttest. please help if there is any error in my program. i tested the same program with restclient plugin like below
http://localhost/cen_neel/vinay/r12/v23/Chennai and i am getting response back correctly.
Here post(ClientResponse.class, params);. you're trying to post the URI information into the body of the request. That's not where they belong. Actually, based on your resource method, there shouldn't be a body at all. You can simply pass an empty string.
Instead, how you should be building the request, is with .path() on the WebResource to append path segments
ClientResponse response = webResource
.path(runID)
.path(tweetID)
.path(tweet)
.accept(MediaType.TEXT_PLAIN_TYPE)
.post(ClientResponse.class, "");
It seems completely pointless though, the way you are doing it. Why not just pass the entire URI, like you are in the Rest Client.
Anyway, this is not really a good design overall. Here are some improvements I would make.
The actual tweet should not be in the URI. It should be posted in the body. To accept it in the body, simply don't annotate it with #PathParam for the tweet method parameter, and get rid of the path template {tweet : .*}. Then you can post(ClientReponse.class, tweet). You should also add #Consumes(MediaType.TEXT_PLAIN) to the resource method, and use type to create the request. i.e.
.accept(MediaType.TEXT_PLAIN_TYPE)
.type(MediaType.TEXT_PLAIN_TYPE)
.post(ClientResponse.class, tweet);
If you are trying to create a new tweet, the id, should not be in the template. The id should not exist yet. When the tweet is created, the server should notify the client with the newly created id of the tweet, with a Location header.