Sending HTTP request with Java Play (WSClient initialization) - java

I have the following piece of code taken from the official Play 2.6 docs that define a client class,
import javax.inject.Inject;
import play.libs.ws.*;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.CompletionStage;
public class MyClient implements WSBodyReadables, WSBodyWritables {
private WSClient ws;
#Inject
public MyClient(WSClient ws) {
this.ws = ws;
sendRequest();
}
public void sendRequest() {
WSRequest request = ws.url("http://example.com");
WSRequest complexRequest = request.addHeader("headerKey", "headerValue")
.setRequestTimeout(Duration.of(1000, ChronoUnit.MILLIS))
.addQueryParameter("paramKey", "paramValue");
CompletionStage<? extends WSResponse> responsePromise = complexRequest.get();
}
}
Now I have a socket actor that handles incoming socket messages. I want to fire an HTTP request every time a new message comes through the socket.
My problem is I don't know how to initialize MyClient class to use its sendRequest method.
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
out.tell("I received your message: " + message, self());
MyClient a = new MyClient(); //problem here
}
}

You must inject it, the same way you did in MyClass:
public class MyActor extends UntypedAbstractActor {
private MyClient client;
#Inject
public MyActor(MyClient client) {
this.client = client;
}
#Override
public void onReceive(Object message) throws Exception {
client.sendRequest();
}
}
If there is some problem that dont let you use this (ex you dont control how the actor is created), add more info to your question.

Related

Akka classic - sending custom class message types

I'm attempting to follow best practices for sending messages between Akka actors and reading the following :
https://github.com/akka/akka/blob/v2.6.15/akka-docs/src/test/java/jdocs/actor/ActorDocTest.java#L101-L129
https://doc.akka.io/docs/akka/current/actors.html
It seems best practice is to define a static class that contains the message to be sent.
From reading the docs I've defined the following :
import akka.event.Logging;
import akka.event.LoggingAdapter;
import akka.persistence.AbstractPersistentActor;
class RecoveryActor extends AbstractPersistentActor {
public static class Msg1 {}
public static class Msg2 {}
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
/**
* Handler that will be called on recovery.
* #return
*/
#Override
public Receive createReceiveRecover() {
return receiveBuilder()
.match(Msg1.class, this::receiveMsg1)
.match(Msg2.class, this::receiveMsg2)
.build();
}
private void receiveMsg1(Msg1 msg) {
log.info("in receive message 1");
}
private void receiveMsg2(Msg2 msg) {
log.info("in receive message 2");
}
/**
* The normal receive method.
* #return
*/
#Override
public Receive createReceive() {
return receiveBuilder()
.match(String.class, s -> s.equals("cmd"), s -> persist("evt", this::handleEvent))
.build();
}
private void handleEvent(String event) {
System.out.println("in handle event");
}
#Override
public String persistenceId() {
return "simple-accountant"; //best practice, the id should be unique.
}
}
But I'm unsure how to send messages using the Msg1 and Msg2
I've defined a new class to send a message :
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
public class ActorMessaging {
public static void main(String args[]){
final ActorSystem system = ActorSystem.create("example");
final ActorRef actor = system.actorOf(Props.create(RecoveryActor.class));
actor.tell(RecoveryActor.Msg1);
}
}
But it fails with compiler error :
java: cannot find symbol
symbol: variable Msg1
location: class recoverydemo.RecoveryActor
How can I send messages to the Actor of type Msg1?
Is this best practice for sending messages between actors, wrapping the messages in a custom class ?
actor.tell is accepting object. RecoveryActor.Msg1 is not that, it's not even class reference. How about trying to send instance of Msg1 like this:
actor.tell(new RecoveryActor.Msg1(), actorRef)
In order to "talk" to remote actor, you first need to obtain reference to it. That's usually done by ActorSystem
Silly mistake on my part. I overrode the incorrect method. I should have overridden createReceive instead :
public Receive createReceive() {
return receiveBuilder()
.match(RecoveryActor.Msg1.class, this::receiveMsg1)
.match(Msg2.class, this::receiveMsg2)
.build();
// return receiveBuilder()
// .match(String.class, s -> s.equals("cmd"), s -> persist("evt", this::handleEvent))
// .build();
}

How to test java.net.http (Java 11) requests BodyPublisher?

I'm trying to test my code which uses the new Java 11 java.net.http.HttpClient.
In my production code I have something like this:
HttpClient httpClient = ... (gets injected)
HttpRequest request = HttpRequest.newBuilder().uri(URI.create("http://localhost:1234"))
.POST(HttpRequest.BodyPublishers.ofByteArray("example".getBytes()))
.build();
return httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray());
And in my test I mock the HttpClient and so get the java.net.http.HttpRequest. How do I get/test its request body (= my "example")? I can call request.bodyPublisher() to get a HttpRequest.BodyPublisher, but then I'm stuck.
I've tried to cast it to jdk.internal.net.http.RequestPublishers.ByteArrayPublisher (which it actually is), but it won't compile because the corresponding package is not exported by the module.
I've checked the available methods in the HttpRequest.BodyPublisher-interface (.contentLength(), .subscribe(subscriber)) but I guess it's not possible with them.
I've tried to just create a new BodyPublisher and compare them using .equals(), but there is no real implementation of it and so the comparison was always false.
If you are interested in how body will look like in handler you can know it with help of HttpRequest.BodyPublisher Subscriber. We call subscription.request in order to receive all body items and collect them.
Our custrom subscriber:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Flow;
public class FlowSubscriber<T> implements Flow.Subscriber<T> {
private final CountDownLatch latch = new CountDownLatch(1);
private List<T> bodyItems = new ArrayList<>();
public List<T> getBodyItems() {
try {
this.latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return bodyItems;
}
#Override
public void onSubscribe(Flow.Subscription subscription) {
//Retrieve all parts
subscription.request(Long.MAX_VALUE);
}
#Override
public void onNext(T item) {
this.bodyItems.add(item);
}
#Override
public void onError(Throwable throwable) {
this.latch.countDown();
}
#Override
public void onComplete() {
this.latch.countDown();
}
}
Usage in the test:
#Test
public void test() {
byte[] expected = "example".getBytes();
HttpRequest.BodyPublisher bodyPublisher =
HttpRequest.BodyPublishers.ofByteArray(expected);
FlowSubscriber<ByteBuffer> flowSubscriber = new FlowSubscriber<>();
bodyPublisher.subscribe(flowSubscriber);
byte[] actual = flowSubscriber.getBodyItems().get(0).array();
Assert.assertArrayEquals(expected, actual);
}

camel - how to propagate a correlationId through producerTemplates

This post relates to this get exchange from within pojo without changing it's interface
and the solution to this problem was to use MDC.
here is the code to do so: (taken from camel test code)
given this interface for instance
public interface IEcho {
String echo(String param);
}
and configuration like so :
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.junit.Test;
import org.slf4j.MDC;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import static org.junit.Assert.assertEquals;
public class RetrieveCorrelationIdTest {
#Test
public void testCamel() throws Exception {
DefaultCamelContext ctx = new DefaultCamelContext();
try {
ctx.setUseMDCLogging(true);
ctx.addRoutes(createRouteBuilder());
ctx.start();
Object body = ctx.createProducerTemplate().requestBody("direct:a", "text in body");
assertEquals("TEXT IN BODY", body);
} finally {
ctx.stop();
}
}
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
IEcho proxy = (IEcho) ReflectHelper.simpleProxy(IEcho.class, new Proxybean(getContext()));
from("direct:a").routeId("route-a")
.setHeader("CUSTOM-CORRELATION-ID", constant("correlationIdsetInHeader"))
.process(exchange -> MDC.put("CUSTOM-HEADER-MDC", "correlationIdsetWithMDC"))
.bean(proxy, "echo(${body})");
from("direct:b").routeId("route-b")
.process(exchange -> {
String customHeader = (String) exchange.getIn().getHeader("CUSTOM-CORRELATION-ID");
String mdcHeader = MDC.get("CUSTOM-HEADER-MDC");
assertEquals(customHeader, mdcHeader);
exchange.getIn().setBody(((String)exchange.getIn().getBody()).toUpperCase());
})
.to("mock:result");
}
};
}
class Proxybean implements InvocationHandler {
CamelContext ctx;
Proxybean(CamelContext ctx) {
this.ctx = ctx;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("echo")) {
// how to get the CUSTOM-CORRELATION-ID here ????µ
// only possible with MDC ?
String mdcHeader = MDC.get("CUSTOME-HEADER-MDC");
String result =
(String) ctx.createProducerTemplate()
.requestBodyAndHeader("direct:b", args[0], "CUSTOME-HEADER", mdcHeader);
return result;
}
return null;
}
}
}
see comments in code:
// how to get the CUSTOM-CORRELATION-ID here ????µ
// only possible with MDC ?
I can access some data even without the exchange using MDC
so my questions:
if I want to get a correlationId spanning from an endpoint calling beans method that calls other method exposed through a proxy that uses a producerTemplate to make the call etc etc...
Is that possible without MDC, does camel offers another way to retrieve this information?

How to make blocking/synchronous calls into an Akka actor system?

Akka 2.4.1 Java API here. I don't have the bandwidth right now to learn Scala, so I would ask that code examples here also use the Java API.
I have an existing ActorSystem that is chock full of asynchronous actors and which works beautifully. I now have a need to reuse this actor system in a synchronous context like so:
// Groovy pseudo-code; NOT inside the actor system here!
ComputationRequest request = new ComputationRequest(1, 7, true)
MasterActor master = actorSystem.get(...)
ComputationResult result = actorSystem.tell(master, request)
Nowhere in Akka's documentation do I see a clear example of sending equests into an actor system (from the outside) and then retrieving the results. Could I use Futures here perhaps? What's the standard way of handling this pattern in Akka (code samples)?
There is the ask pattern does what you want. It expects the target actor to "return" a response by telling it to getSender(). You'll get a Future for the response and can work with that (blocking, if you must).
import akka.dispatch.*;
import scala.concurrent.ExecutionContext;
import scala.concurrent.Future;
import scala.concurrent.Await;
import scala.concurrent.Promise;
import akka.util.Timeout;
ComputationRequest request = new ComputationRequest(1, 7, true);
MasterActor master = actorSystem.get(...);
Timeout timeout = new Timeout(Duration.create(5, "seconds"));
Future<Object> future = Patterns.ask(master, request, timeout);
ComputationResult result = (ComputationResult) Await.result(future, timeout.duration());
You can inject a callback, wrapped into an actor, into akka system and use it as a "sender" with tell mechanics. Full example:
import akka.actor.*;
import akka.dispatch.Await;
import akka.dispatch.Future;
import akka.pattern.Patterns;
import akka.util.Timeout;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
public class Main {
public static void main(String[] args) throws Exception {
// init your akka system
final ActorSystem system = ActorSystem.create("Cambria");
final ActorRef worker = system.actorOf(new Props(Worker.class), "worker");
worker.tell(new Work(10));
// make callback
final Consumer<Object> callback = a -> System.out.println("from the other side: " + a);
// wrap call back into sub-actor
class TheSpy extends UntypedActor {
#Override
public void onReceive(final Object message) throws Exception {
callback.accept(message);
}
}
// inject callback into the system
final ActorRef theSpy = system.actorOf(new Props(TheSpy::new), "spy");
// find actor you want to hack
final ActorSelection found = system.actorSelection("/user/worker");
// send it a message and observe using callback)
found.tell(new Work(20), theSpy);
final Timeout timeout = new Timeout(5, TimeUnit.SECONDS);
final Future<Object> future = Patterns.ask(worker, new Work(30), timeout);
final Work result = (Work) Await.result(future, timeout.duration());
System.out.println(result);
system.shutdown();
system.awaitTermination();
}
}
public class Worker extends UntypedActor {
public void onReceive(Object message) {
if (message instanceof Work) {
Work work = (Work) message;
System.out.println("work = " + work);
getSender().tell(new Work(work.getStart() + 1));
} else {
unhandled(message);
}
}
}
public class Work {
private final int start;
public Work(int start) {
this.start = start;
}
public int getStart() {
return start;
}
#Override
public String toString() {
return "Work{" +
"start=" + start +
'}';
}
}

Akka: finding the actor ref using a path

I am new to Akka and I am trying to start an Actor and send messages to that actor from various other actors. The receiver is called Hero and the senders are Messengers
Here is my Hero class
import akka.actor.UntypedActor;
public class Hero extends UntypedActor {
#Override
public void onReceive(Object arg0) throws Exception {
System.out.println("Received = " + arg0);
}
}
I start the Hero using the below code
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
public class TestHero {
public static void main(String[] args) {
ActorSystem system = ActorSystem.create("testHero");
ActorRef master = system.actorOf(Props.create(Hero.class), "master");
master.tell("I am here", ActorRef.noSender());
}
}
When I run the above code I get the message "Received = I am Here".
Now I have my Messenger class's constructor as follows
private static ActorRef hero;
public Messenger() {
ActorSelection master = context().actorSelection("akka://localhost/user/serviceA/master");
hero = master.anchor();
}
When I print the hero object it is always null. What am I missing here? Is this the right way to search for an Actor. The point is these 2 actors will be running in 2 different JVMs.
I enabled remoting and modified the Messenger class as below.
import akka.actor.ActorRef;
import akka.actor.ActorSelection;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
public class Messenger extends UntypedActor {
private static ActorRef hero;
public Messenger() {
ActorSelection master = context().actorSelection("akka.tcp://testHero#127.0.0.1:2552/user/master");
System.out.println(master);
hero = master.anchor();
}
#Override
public void onReceive(Object arg0) throws Exception {
System.out.println("msg = " + arg0);
}
public static void main(String[] args) {
ActorSystem system = ActorSystem.create("test");
ActorRef actor = system.actorOf(Props.create(Messenger.class), "msgnr");
System.out.println(actor.getClass() + " >> " + actor);
System.out.println(hero);
actor.tell("Hi", hero);
}
}
The output is given below
class akka.actor.RepointableActorRef >> Actor[akka://test/user/msgnr#-975452280]
null
ActorSelection[Anchor(akka://test/deadLetters), Path(/user/master)]
msg = Hi
How to wait till the Messenger is created so that hero actor ref is instantiated?
I solved the issue by adding an application.conf file to the Messenger also.

Categories