Accessing Individual SSE Payloads in Response using Java - java

We are currently using Apache HttpClient (5) to send a POST request to a server. The response is sent back to us using server side events (SSE) with multiple payloads using the standard format:
data: {...}
Currently we have code like this which sends the request and receives the response:
// Set the socket timeout
final ConnectionConfig connConfig = ConnectionConfig.custom()
.setSocketTimeout(socketTimeout, TimeUnit.MILLISECONDS)
.build();
// Custom config
final BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager();
cm.setConnectionConfig(connConfig);
// Build the client
try (final CloseableHttpClient client = HttpClientBuilder.create().setConnectionManager(cm).build()) {
// Execute the request
return client.execute(request.getRequest(),
// Get and process the response
response -> HttpResponse.builder()
.withCode(response.getCode())
.withContent(EntityUtils.toByteArray(response.getEntity()))
.build()
);
}
This all works great except I need to access the individual incoming response payloads (data {...}) in the response as they arrive instead of waiting for them all to finish before being able to access the response.
If this isn't possible using Apache I am open to other options providing they can send a normal HTTP(S) POST.

Ok I couldn't get it to work with the Apache Client but I did find this video that showed how to do it using the native HttpClient.
// Create the client
final HttpClient client = HttpClient.newHttpClient();
// Make the request
final HttpResponse<Stream<String>> response = client.send(request, HttpResponse.BodyHandlers.ofLines());
// Status code check
if (response.statusCode() != 200) ...;
// This will consume individual events as they arrive
response.body().forEach(System.out::println);

Related

SparkJava GET Handler Returning NULL After Serialization of Long

I'm trying to write a simple server with SparkJava but I am having considerable difficulty serialize a long using Gson and transmitting the JSON to an OkHttp client program inside a GET handler. The server returns NULL, more specifically response.body.string() is
<html><body><h2>404 Not found</h2></body></html>
Any ideas on what the issue could be? thanks.
Here is the GET handler:
get("routingEngine/getDefaultRoute/distance", (request,response) ->{
response.type("application/json");
long distance = 100;
return gson.toJson(distance);
});
Here is the client code making the simple request (please disregard the parameters (requestParameters) being passed in along with the request, they just provide information to an irrelevant before filter):
// build url
HttpUrl url = new HttpUrl.Builder()
.scheme("http")
.host("127.0.0.1")
.port(4567)
.addPathSegment("routingEngine")
.addPathSegment("getDefaultRoute")
.addPathSegment("distance")
.build();
// build request
Request getDefaultRouteDistanceRequest = new Request.Builder()
.url(url)
.post(RequestBody.create(JSON,gson.toJson(requestParameters)))
.build();
// send request
Call getDefaultRouteDistanceCall = httpClient.newCall(getDefaultRouteDistanceRequest);
Response getDefaultRouteDistanceResponse = getDefaultRouteDistanceCall.execute();
// parse response
// testing
System.out.println(getDefaultRouteDistanceResponse.body().string());
The last line leads to the following output
<html><body><h2>404 Not found</h2></body></html>
The endpoint you created was a GET endpoint and the call being made is for POST.

Apache Http Client execute request without sending the enclosing entity

I do have the following scenario:
1) The Client sends a HTTP request with an enclosing entity to a Server, via a socket.
2) The Server uploads the enclosing entity to another location, let's call it Storage.
I am required to implement only the Server.
So far, I was able to implement it using Apache HTTP Components library using something like:
// The request from the client
org.apache.http.HttpRequest request = ...;
// The org.apache.http.entity.InputStreamEntity will
// read bytes from the socket and write to the Storage
HttpEntity entity = new InputStreamEntity(...)
BasicHttpEntityEnclosingRequest requestToStorage = new ......
requestToStorage.setEntity(entity);
CloseableHttpClient httpClient = ...
CloseableHttpResponse response = httpClient.execute(target, requestToStorage );
So far so good. Problem is, the Storage server requires authentication. When the Server makes the first request (via Apache Http Client API), the Storage responds with 407 Authentication Required. The Apache Http Client makes the initial handshake then resends the request, but now there is no entity since it has already been consumed for the first request.
One solution is to cache the entity from the Client, but it can be very big, over 1 GB.
Question Is there a better solution, like pre-sending only the request's headers?
Use the expect-continue handshake.
CloseableHttpClient client = HttpClients.custom()
.setDefaultRequestConfig(
RequestConfig.custom()
.setExpectContinueEnabled(true)
.build())
.build();

How to send x-www-form request on java?

Above is what im trying to send
In java this is what I have
RequestBody formBody = new FormBody.Builder()
.add("param1", "abc")
.add("param2", "abc")
.add("param3", "abc")
.build();
Request request = new Request.Builder()
.url("http://localhost:3001/addsomething")
.post(formBody)
.build();
doesn't seem to work. I have OkHttpClient but I'm not sure how to use it to send the above result
What are you confused about? I'm a little unsure. I did a little research but it seems the only thing you're missing is a client, and then sending the request you've created and receive a response back.
To create a client, look at the most updated documentation on OkHttpClient, but this is what I found:
OkHttpClient client = new OkHttpClient();
And then send your request using that client using:
Response response = client.newCall(request).execute();
Then you can proceed to do something with that response.
All you have to understand is that you're creating a request (essentially asking the server for some information). Depending on your request, you'll get a response back (as in above), which you can then use to get whatever you're looking for.

Azure Event Hub Authorization from Android

I‘m working on an application that sends data to an azure event hub. This is similar to the blog post here:http://sreesharp.com/send-events-from-android-app-to-microsoft-azure-event-hubs/
However, I updated the connection code to use OkHttp:
public void sendMessageOkHttp(String dataPacket, String connectionString, String sasKey){
// Instantiate the OkHttp Client
OkHttpClient client = new OkHttpClient();
// Create the body of the message to be send
RequestBody formBody = new FormBody.Builder()
.add("message", dataPacket)
.build();
// Now create the request and post it
Request request = new Request.Builder()
.header("Authorization", sasKey)
.url(connectionString)
.post(formBody)
.build();
Log.i(TAG,"about to send message");
// Now try to send the message
try {
Log.i(TAG,"sending message....");
Response response = client.newCall(request).execute();
Log.i(TAG,"message sent");
Log.i("Azure Response",String.valueOf(response.message()));
// Do something with the response.
} catch (IOException e) {
e.printStackTrace();
}
}
However this returns a response from the event hub "Unauthorized". The sas key I am using is for a shared access policy that I created with send and listen permissions. It is the primary key.
What am I doing wrong here? The Azure documentation doesnt really help me in this case because it focused on using the Azure Java libraries that are not Android compatible (i.e. they require Java 1.8)
It's not the SAS Key you send in the Authorization header, it's the SAS Token. Here are like 5 or six different languages for generating the SAS Token from the key: https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-sas-overview

Elasticsearch Java client: can't connect to the remote server

I need to connect to the remotely located ElasticSearch index, using the url provided here:
http://api.exiletools.com/info/indexer.html
However, I can't figure out how to do this in Java.
Docs on ES Java Client don't really have much info at all.
I also did not find any JavaDocs for it, do they exist?
Now, there are working examples written in Python, which confirm that the server is up and running, connection part looks like this:
es = Elasticsearch([{
'host':'api.exiletools.com',
'port':80,
'http_auth':'apikey:DEVELOPMENT-Indexer'
}])
What I tried to do:
client = new TransportClient()
.addTransportAddress(new InetSocketTransportAddress("apikey:DEVELOPMENT-Indexer#api.exiletools.com/index", 9300));
also tried ports 9200 and 80
This results in:
java.nio.channels.UnresolvedAddressException
and NoNodeAvailableException
The Shop Indexer API offers an HTTP entry point on port 80 to communicate with their ES cluster via the HTTP protocol. The ES TransportClient is not the correct client to use for that as it will only communicate via TCP.
Since Elasticsearch doesn't provide an HTTP client out of the box, you need to either use a specific library for that (like e.g. Jest) or you can roll up your own REST client.
An easy way to achieve the latter would be using Spring's RestTemplate:
// create the REST template
RestTemplate rest = new RestTemplate()
// add the authorization header
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "DEVELOPMENT-Indexer");
// define URL and query
String url = "http://api.exiletools.com/index/_search";
String allQuery = "{\"query\":{\"matchAll\":{}}}";
// make the request
HttpEntity<String> httpReq = new HttpEntity<String>(allQuery, headers);
ResponseEntity<String> resp = rest.exchange(url, HttpMethod.POST, httpReq, String.class)
// retrieve the JSON response
String body = resp.getBody();

Categories