Java Jersey PUT Method and working Client - java

I am developing an Dynamic Web Application with Eclipse. I have e working MySQL-Database which is connected over a class called 'Data Access Object' (=DAO) that works with JDBC. I want to create entries into this database. The functions are ready. With ready I mean tested and OK. On the same application I implemented Java Jersey's RESTful WebService. It is working well, I can call the service and it returns my desired information. But now to my question:
How can I send a String containing XML? The String has to be parsed in the WebMethod to build and execute the query.
My WebService looks as follows:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.ws.rs.Consumes;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
#Path("/input")
public class Input {
//DAO instance to have connection to the database.
//Not used yet.
//private DAO dao = new DAO();
#PUT
#Consumes(MediaType.TEXT_XML)
#Path("/result")
public void putIntoDAO(InputStream xml) {
String line = "";
StringBuilder sb = new StringBuilder();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(xml));
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(sb.toString());
}
}
As you see I tried to print the incoming Stream to the console.
I repeat the most important things:
I know how to parse XML.
I know my DAO works properly.
I know my WebService works as well.
What I would like to know:
How do I send an XML-String to my WebService?
How do I access this String in my PUT-method?
Thank you for your attention and try to help me. I appreciate even every try to.
Kind regards
L.

How do I access this String in my PUT-method?
You can simply code the method to take an argument of type String and Jersey will map this from the incoming XML request, so:
#PUT
#Consumes(MediaType.TEXT_XML)
#Path("/result")
public void putIntoDAO(String xml) {
// ...
}
Should work, with the String containing the full request body.
How do I send an XML-String to my WebService?
This depends on what you're using to send the request to the service, which could be anything which communicates over HTTP. I'll assume you're using Java and sticking with Jersey, so one option is you can use the Jersey Client in the following way:
Client client = Client.create();
WebResource webResource = client.resource("http://localhost:8080/input/result");
String input = "<xml></xml>";
ClientResponse response = webResource
.type("application/xml")
.put(ClientResponse.class, input);
See the Jersey Client documentation for more.

The answer Ross Turner posted is completely correct and working. Here is an option using Apache HttpComponents.
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
public class Runner {
public static void main(String[] args) {
try {
HttpClient httpClient = new DefaultHttpClient();
HttpPut putRequest = new HttpPut("http://localhost:8080/HelloFromJersey/input/result");
StringEntity input = new StringEntity("Hello, this is a message from your put client!");
input.setContentType("text/xml");
putRequest.setEntity(input);
httpClient.execute(putRequest);
httpClient.getConnectionManager().shutdown();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
The server prints:
Hello, this is a message from your put client!

Related

How can I create an elastic search index with the JAVA high level REST client?

I was going through these docs to create an elastic search index from Elastic's high level JAVA REST client. It seems to skip over steps for authenticating with my elastic cloud account.
Can someone please point me toward the relevant documentation?
I launched my elastic search instance and copied the endpoint URL into my client code.
I initially had connection errors and now there are none. Only authentication errors. So, I'm pretty sure I'm connecting with the correct endpoint URL and need to authenticate somehow - perhaps with a header.
Now, I am seeing this error:
Elasticsearch exception [type=security_exception, reason=action
[indices:data/write/index] requires authentication]
I can view the endpoint of my Elastic Search deployment with no problems from Postman with this command:
GET https://:#d97215aee2.us-east-1.aws.found.io:9243
I can also create an index using this command from Postman...
PUT https://elastic:4YQIMXfoSZ9mXPgY1fj7T5BU#d97218f74f6d48489b355dd7d665aee2.us-east-1.aws.found.io:9243/. Yet, I cannot do the same from the Java code.
Here is the state of my Java code. It is pretty much the code from these tutorial pages.
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-getting-started-initialization.html
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.4/java-rest-high-document-index.html
import java.io.IOException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import org.apache.http.HttpHost;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
#Path("/elasticsearch")
public class ElasticSearchService {
#POST
public void createElasticIndex() throws IOException {
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("d9<deleted a bunch of characters for privacy>7d665aee2.us-east-1.aws.found.io", 9243, "https")));
IndexRequest request = new IndexRequest(
"posts",
"doc",
"1");
String jsonString = "{" +
"\"user\":\"kimchy\"," +
"\"postDate\":\"2013-01-30\"," +
"\"message\":\"trying out Elasticsearch\"" +
"}";
request.source(jsonString, XContentType.JSON);
client.close();
}
}
I have also tried updating the URL address with our username and password as suggested by this post: ElasticSearch authentication error with ElasticCloud?
Essentially, I updated my URL like this...
RestClient.builder(
new HttpHost(
"<my user name>:<my password>#d97218<hidden characters>d665aee2.us-east-1.aws.found.io",
9243, "https")));
This did not work for me. I am guessing this person wasn't using the new Elastic
High Level REST client.
I received this error:
org.glassfish.jersey.server.internal.process.MappableException:
java.io.IOException: :#d97265aee2.us-east-1.aws.found.io: invalid IPv6 address
Found the answer here: enter link description here
Updated code that works:
import java.io.IOException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.RestStatus;
#Path("/elasticsearch")
public class ElasticSearchService {
private static final String ELASTIC_SEARCH_USER_NAME = <my elastic search username>;
private static final String ELASTIC_SEARCH_PASSWORD = <my elastic search password>;
private static final String ELASTIC_SEARCH_ENDPOINT_URL = <my elastic search endpoint url>
private static final Integer ELASTIC_SEARCH_PORT = 9243;
#POST
public void createElasticIndex() throws IOException {
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(ELASTIC_SEARCH_USER_NAME, ELASTIC_SEARCH_PASSWORD));
RestClientBuilder builder = RestClient
.builder(new HttpHost(
ELASTIC_SEARCH_ENDPOINT_URL,
ELASTIC_SEARCH_PORT, "https"))
.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
#Override
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
}
});
RestHighLevelClient client = new RestHighLevelClient(builder);
IndexRequest request = new IndexRequest(
"contacts",
"doc",
"1");
String jsonString = "{" +
"\"user\":\"frank\"," +
"\"postDate\":\"2020-03-02\"," +
"\"message\":\"created this document from Java\"" +
"}";
request.source(jsonString, XContentType.JSON);
try {
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
System.out.println(response);
} catch (ElasticsearchException e) {
if (e.status() == RestStatus.CONFLICT) {
}
}
client.close();
}
}
This code creates an index called contacts and adds a document to that index.
You can use both synchronous and asynchronous API of elastic search to create index. But it depends on requirement.
Find the below link of elastic search documentation which explain both synchronous and asynchronous API use.
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-high-create-index.html
Sample code:-
Synchronous API :-
CreateIndexRequest request = new CreateIndexRequest("twitter");
request.settings(Settings.builder()
.put("index.number_of_shards", 3)
.put("index.number_of_replicas", 2)
);
CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
Asynchronous API:-
client.indices().createAsync(request, RequestOptions.DEFAULT, listener);
Asynchronous API adds advantages of thread and makes API to work better way. Concern in asynchronous API is to receive response. Below is the snippet how can you receive response.
PlainActionFuture<CreateIndexResponse > future = new PlainActionFuture<>();
client.indices().createAsync(request, RequestOptions.DEFAULT, future);
CreateIndexResponse response = future.actionGet();
If you know how to insert documents through API then this way will much more easy for you to do anything similar API (DELETE,POST,PUT...)
First, you will need RestHighLevelClient and all you have to do
String index = "/indexName/_doc";
Request request = new Request("POST", index);
request.setJsonEntity(
"{ \"message\": \" example add insert\" }"
);
client.getLowLevelClient().performRequest(request);
This will execute like how API does.

How to get TWILIO CALL info using Java Rest Client

Having next code, which use RestEasy to get to a Twilio CALL info:
import java.util.Base64;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import com.twilio.rest.api.v2010.account.Call;
public class RestGetCallInfo1 {
public static void main(String[] args) {
try {
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget = client.target("https://api.twilio.com/2010-04-01/Accounts/AC99999999/Calls/CA77777777777.json");
String credentials = "AC99999999:888888888";
String base64encoded = Base64.getEncoder().encodeToString(credentials.getBytes());
Response response = target.request().header(HttpHeaders.AUTHORIZATION, "Basic " + base64encoded).get();
int status = response.getStatus();
if (status == 200) { //OK
Call call = response.readEntity(Call.class); //<------------- This fails!
System.out.println(call);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
}
I want to ask you:
What 'Rest' libraries/tools does twilio-7.47.2-jar-with-dependencies.jar use inside (in order to use that instead of RestEasy)?
How can I get the JSON call object properly? with the actual code I get:
javax.ws.rs.ProcessingException: Unable to find a MessageBodyReader of content-type application/json and type class com.twilio.rest.api.v2010.account.Call
EDIT: I am able to get the Call info in JSon format with:
String call = response.readEntity(String.class);

Efficient way to handle post requests on Java Vert.x?

This is how I am currently handling post requests on my vert.x server:
router.post("/test").handler(context -> context.request().bodyHandler(body -> {
try {
JsonObject jsonObject = new JsonObject(body.toString());
...
} catch(Exception e) { }
}));
I am sending test requests using Postman where the body has data as "raw - application/json".
This works. But, is this the right way?
I also tried sending the data as parameters in "form-data" but I am not able to get the parameters. The following prints out the entire request, I can see the data, but cannot parse it to a json or map.
router.post("/test").handler(context ->
context.request().bodyHandler(System.out::println));
Any help is appreciated. Thanks.
There are many ways you can program you request handlers.
You can find different approaches in this documentation https://vertx.io/docs/vertx-web/java/
Here is an approach I prefer when writing my handlers.
package org.api.services.test;
import org.api.services.test.CustomDTO;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
public class TestApi extends AbstractVerticle {
#Override
public void start(Future<Void> startFuture) throws Exception {
super.start(startFuture);
Router router = Router.router(vertx);
router.route().handler(BodyHandler.create());
//register a router for post request that accepts only requests with */json MIME type on exact path /test.
router.post("/test/").consumes("*/json").handler(this::testHandler);
...
}
private void testHandler(RoutingContext routingContext) {
//recommended way to extract json
JsonObject jsonObject = routingContext.getBodyAsJson();
//automatically map json to custom object
CustomDTO customDTO = Json.decodeValue(routingContext.getBodyAsString(), CustomDTO.class);
...
}
}
If you are sending request containing form-data you can extract 2 ways:
If you add router.route().handler(BodyHandler.create()); than all form attributes will be merged as request parameters.
By default, the body handler will merge any form attributes into the request parameters. If you don’t want this behaviour you can use disable it with setMergeFormAttributes.
You can extract them by using routingContext.request().getParam("attribute_name")
If you are not using any BodyHandler you need to set routingContext.request().setExpectMultipart(true); and than access the form attributes like this routingContext.request().formAttributes()
If you need "form-data", you should add "BodyHandler" before your handle.
final Router router = Router.router(vertx);
router.route().handler(BodyHandler.create());
....
context.request().getParam("id")

Receiving "Request Entity Cannot be Empty" from paramaterized RESTful GET operation

New to java programming and still learning. I've built a RESTful service and I'm trying to pass in a parameter for a GET routine and I'm getting back a state 400 saying that the "Request entity cannot be empty". When I call the non-parameterized GET, the data comes back just fine. I've stripped down all the functionality of the parameterized GET to just return a simple string and I'm still getting the same message. Searched all over and can't find anything that's very helpful.
Below is the code that I'm running for the service. The method "GetChildAllInfo" makes a call to a local mySQL instance and returns a list of objects; that one works just fine. The parameterized one returns nothing, not even an exception.
Any help would be tremendously appreciated. Even if it's a ridiculously simple solution like a syntax error that I may have missed. AND I'm willing to accept any other advice on what you see in the code as well. Thanks!
package allowanceManagerChild;
import java.util.Set;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.Produces;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PUT;
import javax.ws.rs.core.MediaType;
import com.google.gson.Gson;
#Path("allowanceManagerChild")
public class AllowanceManagerChild {
#Context
private UriInfo context;
/**
* Creates a new instance of AllowanceManagerChild
*/
public AllowanceManagerChild() {
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public String getJson() {
String response = "";
Set<Child> children = Child.GetAllChildInfo();
for (Child child : children){
Gson gson = new Gson();
String json = gson.toJson(child);
response = response + json;
}
return response;
}
#GET
#Path("/{childID}")
#Produces(MediaType.APPLICATION_JSON)
public String getJson(int childID) {
String response = "";
try{
// Set<Child> children = Child.GetChildInfo(id);
// for (Child child : children){
// Gson gson = new Gson();
// String json = gson.toJson(child);
// response = response + json;
// }
response = "Made it here"; //Integer.toString(childID);
}
catch(Exception e){
response = e.toString();
}
return response;
}
/**
* PUT method for updating or creating an instance of AllowanceManagerChild
* #param content representation for the resource
*/
#PUT
#Consumes(MediaType.APPLICATION_JSON)
public void putJson(String content) {
}
}
Adding the #PathParam annotation to the method parameter might help:
#GET
#Path("/{childID}")
#Produces(MediaType.APPLICATION_JSON)
public String getJson(#PathParam("childID") int childID) {
See the RESTful Web Services Developer's Guide for more details.

ArrayList issue in HTTP Servlet

I'm using Floodlight REST API in order to monitor a created virtual network in mininet. My goal is to display an arraylist of all the switches, hosts and statistics for the switches on a web browser using Apache Tomcat web server and HTTP Servlet. The application successfully displays all the switches and hosts, but fails when I'm adding the statistics for the switches.
When I'm mapping JSON string to java objects, the server returns the error in this line:
ArrayList<Switch> queues = mapper.readValue(queueJson, new TypeReference<ArrayList<Switch>>() {
});
The error is:
HTTP status 500 - can not deserialize instance of java.util.arraylist out of start_object token
I have testet it without the switch statistics (Queues) part (with only hosts and devices) and everything works fine, but when I'm adding the queues ArrayList, it returns the above mentioned error.
How can I solve this issue ?. My code is shown below. Thanks in advance
package core;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.restlet.data.MediaType;
import org.restlet.resource.ClientResource;
import org.restlet.resource.ResourceException;
import pojos.Device;
import pojos.Switch;
#WebServlet("/PrintInfo")
public class PrintInfo extends HttpServlet {
private static final long serialVersionUID = 1L;
public PrintInfo() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// create ClientResource object
// List at the switches in the network
ClientResource cResourceSwitches = new ClientResource("http://127.0.0.1:8080/wm/core/controller/switches/json");
StringWriter sWriterSwitches = new StringWriter();
// List all the devices (hosts) in the network
ClientResource cResourceDevices = new ClientResource("http://127.0.0.1:8080/wm/device/");
StringWriter sWriterDevices = new StringWriter();
// List the statistics of the switches in the network
ClientResource cResourceQueues = new ClientResource("http://127.0.0.1:8080/wm/core/switch/all/queue/json");
StringWriter sWriterQueues = new StringWriter();
// get JSON data about switches; the data is put in a string writer
try {
// Getting data from Floodlight as a JSON string
cResourceSwitches.get(MediaType.APPLICATION_JSON).write(sWriterSwitches);
cResourceDevices.get(MediaType.APPLICATION_JSON).write(sWriterDevices);
cResourceQueues.get(MediaType.APPLICATION_JSON).write(sWriterQueues);
} catch (ResourceException e) {
request.setAttribute("error", "Connection with FLoodLight failed!");
request.getRequestDispatcher("WEB-INF/connectionError.jsp").forward(request, response);
return;
}
// put data from string writer into a string object
String switchesJson = sWriterSwitches.toString();
String devicesJson = sWriterDevices.toString();
String queueJson = sWriterQueues.toString();
// map JSON data to Java objects
// ObjectMapper converts between JSON - Java
ObjectMapper mapper = new ObjectMapper();
ArrayList<Switch> switches = mapper.readValue(switchesJson, new TypeReference<ArrayList<Switch>>() {
});
ArrayList<Device> devices = mapper.readValue(devicesJson, new TypeReference<ArrayList<Device>>() {
});
ArrayList<Switch> queues = mapper.readValue(queueJson, new TypeReference<ArrayList<Switch>>() {
});
// put objects in the request so we can use them later in the JSP
request.setAttribute("switches", switches);
request.setAttribute("devices", devices);
request.setAttribute("queues", queues);
// redirect to the jsp
request.getRequestDispatcher("WEB-INF/showInfo.jsp").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
}
}
Solved. The Switch class in "ArrayList" can't be used for switch statistics. A new class has to be implemented, which returns the values in
http://127.0.0.1:8080/wm/core/switch/all/queue/json
URI.

Categories

Resources