Netty client pipeline getting response in a specific object? - java

Since all the examples I have seen just output to console in the ClientHandler I'm wondering about a proper way to get this data into a specific object. Let's say in some controller class the user can press a button to request or refresh some data from the server. I have a reference to the channel in this object that sends the request to the server and once the server done the work it sends it back where it ends up in the clients pipeline. Now I need to get the data out and into the object that requested it.
I can think of two options. Implement a observer pattern and send the data back to the object once it's complete and decoded. I'll add the requesting object as a listener once it has send the data and remove it once it received it.
Or perhaps I can just implement a handler interface for this controller class? When it expects data I add it to the pipeline and when it has received the data I remove it from the pipeline? Some pseudo:
public class SomeControllerClass extends ChannelInboundHandlerAdapter {
//...
public void onButtonClick() {
// Send a request to the server.
channel().writeAndFlush(new someDataRequest);
// Add this controller to the pipeline to handle the response once it arrived and decoded.
channel().pipeline().addLast("someHandler", this);
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
// Do stuff with the data in this class
// Remove this from the pipeline.
channel().pipeline().remove("someHandler");
}
//...
}
Is this anywhere along the lines on how I need to approach this problem? I'm removing it from the pipeline because I'm worried other objects that expect similar data will handle the data too.
In other words, all I'm trying to make is a popup window that shows "loading" until data is received from server and ready to present it in that popup.

Related

Is there a generic Event a AWS Lambda function can receive, and then determine which type of event is it?

I'm currently learning about AWS Lambda and how to trigger it from other services. I've managed to use SNS topic (with help of this tutorial) to publish a json like:
{
"name":"Bojack",
"lastName":"Horseman",
"job":"Horsin around"
}
and triggers the Lambda function:
public class LambdaHandler implements RequestHandler<SNSEvent, MyResponse> {
public MyResponse handleRequest(SNSEvent request, Context context){
String input = request.getRecords().get(0).getSNS().getMessage();
MyRequest myRequest = new Gson().fromJson(input, MyRequest.class);
context.getLogger().log(MyRequest.toString());
// do some logic
return null;
}
}
It works great!
However, now I'm trying to figure out how to add a new service that can also trigger this function.
For example SQS, or kinesis. AFAIK these services send different json input to the lambda function, and I'm not sure about how to receive it since I'm currently using SNSEvent
Is there a way to receive a Generic Event and inside the handler determine which service was the one who send it? So that way I can parse it to that specific event and get the message
I've read about AWS Lambda Event Source Mapping but I'm not sure if that's the way to go. Also I didn't really understand it

Server Sent Event with Spring with having a thread being freed from request

I need to show off an example of server sent events. I learned about it in a spring talk. People used Webflux there to show the reactive principles. I understood the part on how this will free thread resources because the request thread won't be blocked until the job is done and the server returns the response.
I have an example here but actually I don't really know how I can make this thread resource example be clear enough.
I do not want to use the WebFlux framework here. Just need to know what to put into a separate thread here - if necessary at all?!
As you can see I have a GetMapping to subscribe to the event stream. And then I have a GetMapping to launch or fire an event. This example is fast for sure but should be considered as heavy database call.
So I actually need to have the whole logic be separated in another thread right? So the request thread is free as soon as possible?
#RestController
public class EventStreamRequestHandler {
#Autowired
ObjectMapper objectMapper;
SseEmitter sseEmitter = new SseEmitter(1000000L);
#GetMapping("/get/event/stream")
public SseEmitter getStream() {
return this.sseEmitter;
}
#GetMapping("/launch/event")
public void fireEvent() throws IOException {
Person peter = new Person("Peter", "25");
String valueAsString = objectMapper.writeValueAsString(peter);
SseEmitter.SseEventBuilder sseEventBuilder = SseEmitter.event()
.id("foo")
.name("awesome-event")
.data(valueAsString);
sseEmitter.send(sseEventBuilder);
}
}
Yes, Server sent events are supposed to send messages to the client asynchronously without client keep on polling for message.
The sending of messages from client to server needs to be done asynchronously. With the way you have done it. When a GET request is sent to /get/event/stream an SseEmitter will be created but messages will only be sent when a GET request is sent to /launch/event. And the GET request thread for /launch/event will be used to send the message.
Sometime back I wrote post to send SSE messages using a different thread. I hope this helps.
But I don't recommend storing the SseEmitter in an instance variable as it will overridden by multiple requests. You must at least make it ThreadLocal

Invoke route from Processor

I'm using Camel to integrate 2 systems. I have defined different routes and one of the routes consumes from a specific rabbitmq queue and send it to a REST service. Nothing fancy here, the route looks like this:
public class WebSurfingRabbitToRestRoute extends RouteBuilder{
#Override
public void configure() throws Exception {
from("rabbitmq://rabbit_host:port/Rabbit_Exchange").
setHeader("CamelHttpMethod", constant("POST")).
setHeader("Content-Type", constant("application/json")).
bean(TransformResponse.class, "transform").
to("http4://rest_service_host:port/MyRestService).
}
}
As you can see, i process every message before sending it to the rest service since i need to adjust some things. The problem comes when i find out that sometimes (i dont know how or when), the system that publish into rabbit, send 2 messages concatenated at once.
What i expect to get is a simple json like this:
[{field1:value1, field2:value2}]
What i sometimes get is:
[{field1:value1, field2:value2},{field1:value3, field2:value4}]
So when i face this scenario, the rest service im routing the message to, fails (obviously).
In order to solve this, i would like to know if there is a way to invoke a route from inside a processor. From the previous snippet of code you can see that Im calling the transform method, so the idea will be to do something like the following pseudo-code, because after the route is already fired, i cant split the events and send them both within the same route "instance", so i thought about invoking a different route that i can call from here which will send the message2 to the very same rest service.
public class TransformRabbitmqResponse {
public String transform(String body) throws Exception {
// In here i do stuff with the message
// Check if i got 2 messages concatenated
// if body.contains("},{") {
// split_messages
// InvokeDifferentRoute(message2)
//}
}
}
Do you guys think this is possible?
One option (though I am not sure this is the best option) would be to split this up into two different routes using a direct endpoint.
public class WebSurfingRabbitToRestRoute extends RouteBuilder{
#Override
public void configure() throws Exception {
from("rabbitmq://rabbit_host:port/Rabbit_Exchange")
.setHeader("CamelHttpMethod", constant("POST"))
.setHeader("Content-Type", constant("application/json"))
.bean(TransformResponse.class, "transform");
from("direct:transformedResponses")
.to("http4://rest_service_host:port/MyRestService");
}
}
And then in your transform bean, you can use camel Producer Template to publish the transformed payload(s) to your new direct endpoint (assuming you are using json?).
producerTemplate.sendBody("direct:transformedResponses", jsonString);

persisting data of webservice response to forward to websocket

I am trying to fetch data through webservice and forward it to the browser through websocketing. So that, I can validate the response of webservice based on the individual websocket opened connection.
Basically, it would be
SERVER1 ---->WEBSERVICE CALL ----> SERVER TO VALIDATE DATA <====> open from client <----WEBSOCKET----> listens to IP through <====>CLIENT
The client is opening a connection to start listening for a particular data for a given MAC address.
I am facing a problem to bypass the data received from webservices to the listener port and IP.
So that, I am trying to persist it using JPA (ODB) objectDB, we could able to store into .odb, but whereas, when trying to make a request to fetch .odb from another application server(CLIENT) to the validator server(SERVER TO VALIDATE DATA). I am getting nothing.
I feel that might be because of lack of session handler among different webapps.
#ServerEndpoint("/echo") //websocket
#Path("/json/metallica") //webservice
public class JSONService {
#POST
#Path("/post")
#Consumes(MediaType.APPLICATION_JSON)
public Response createTrackInJSON(Track track) {
// where I am storing into db---------**** step
}
// connection OPENED from differnet **webapp**
#OnMessage
public void echoTextMessage(Session session, String msg, boolean last) {
if (session.isOpen()) {
//I couldn't able to fetch the data from db which I stored in ---------**** step.
}
}
I am getting empty results. Any suggestions where I am going wrong.
Thanks.

How to redirect user and pass a message to the destination page with Jersey and Dropwizard?

I have a POJO resource which defines some HTTP endpoints and returns Dropwizard Views. Some of these endpoints simply perform an action (eg. update the db) and then forward the user to another endpoint. For example, the user is at the location GET /foo and submits a form. This directs them to the endpoint POST /foo/submit, their submission is processed, and then forwards them to GET /foo/done. This prevents resubmission of the form if they refresh the page, for example. This forwarding is currently accomplished with Jersey's Response.seeOther() method (returning a Response instead of a View).
What I would like to be able to do is, when the handling method handles their submission, generate some sort of message (error message, warning, successful, etc) and pass that message to the page we forward to. For example, at GET /foo/done, I would like it to say at the top of the page, "Submission complete!" or "Submission failed because...".
I've done some searching around and a lot of people are suggesting to throw a WebApplicationException - except not all of my cases are errors. Sometimes I'd like to just show a confirmation of a successful action. But I can't figure out how to get the receiving method to receive a message. I've done it before in Python by having the handling method accept an optional dictionary but unfortunately I'm on Java 7 so I don't have the ability to give methods optional parameters with default values.
Thanks for your help.
Redirects will simply send GET requests. GET request should not have any body. To send arbitrary data with GET requests, simply send it in the query string (of course there should be no confidential information here). For example
#Path("foo")
public class FooResource {
#GET
#Path("done")
public String getDone(#QueryParam("message") String message) {
return message;
}
#POST
#Path("submit")
public Response postData() {
String message = UriComponent.encode(
"You have perefected submitting!",
UriComponent.Type.QUERY_PARAM_SPACE_ENCODED);
return Response.seeOther(URI.create("/api/foo/done?message=" + message)).build();
}
}

Categories