How to convert the Core message to a JMS message? - activemq-artemis

I need to convert org.apache.activemq.artemis.core.message.impl.CoreMessage to javax.jms.Message. How can i do this? Maybe there is a required util method somewhere in the code, or it needs to be done manually?
I want to intercept the following events:
afterSend
afterDeliver
messageExpired
And then send the message to a direct endpoint Camel route which requires a javax.jms.Message instance.

My recommendation would be to simply copy the message and route the copy to the address of your choice, e.g.:
public class MyPlugin implements ActiveMQServerMessagePlugin {
ActiveMQServer server;
#Override
public void registered(ActiveMQServer server) {
this.server = server;
}
#Override
public void afterSend(ServerSession session,
Transaction tx,
Message message,
boolean direct,
boolean noAutoCreateQueue,
RoutingStatus result) throws ActiveMQException {
Message copy = message.copy();
copy.setAddress("foo");
try {
server.getPostOffice().route(copy, false);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Then a Camel consumer can pick up the message and do whatever it needs to with it. This approach has a few advantages:
It's simple. It would technically be possible to convert the org.apache.activemq.artemis.api.core.Message instance into a javax.jms.Message instance, but it's not going to be straight-forward. javax.jms.Message is a JMS client class. It's not used on the server anywhere so there is no existing facility to do any kind of conversion to/from it.
It's fast. If you use a javax.jms.Message you'd also have to use a JMS client to send it and that would mean creating and managing JMS resources like a javax.jms.Connection and a javax.jms.Session. This is not really something you want to be doing in a broker plugin as it will add a fair amount of latency. The method shown here uses the broker's own internal API to deal with the message. No client resources are necessary.
It's asynchronous. By sending the message and letting Camel pick it up later you don't have to wait on Camel at all which reduces the latency added by the plugin.

org.apache.activemq.artemis.jms.client.ActiveMQMessage
This looks like the implementation of javax.jms.Message with an underlying org.apache.activemq.artemis.api.core.client.ClientMessage which extends CoreMessage

Related

Sleuth tracing is not working for transactional Kafka producers

Currently, we are using transactional Kafka producers. What we have noticed is that the tracing aspect of Kafka is missing which means we don't get to see the instrumentation of Kafka producers thereby missing the b3 headers.
After going through the code, we found that the post processors are not invoked for transactional producers which means the TracingProducer is never created by the TraceProducerPostProcessor. Is there a reason for that? Also, what is the work around for enabling tracing for the transactional producers? It seems there is not a single place easily to create a tracing producer (DefaultKafkaProducerFactory #doCreateTxProducer is private)
Screen shot attached(DefaultKafkaProducerFactory class). In the screenshot you can see the post processors are invoked only for raw producer not for the case for transactional producer.
Your help will be much appreciated.
Thanks
DefaultKafkaProducerFactory#createRawProducer
??
createRawProducer() is called for both transactional and non-transactional producers:
Something else is going on.
EDIT
The problem is that sleuth replaces the producer with a different one, but factory discards that and uses the original.
https://github.com/spring-projects/spring-kafka/issues/1778
EDIT2
Actually, it's a good thing that we discard the tracing producer here; Sleuth also wraps the factory in a proxy and wraps the CloseSafeProducer in a TracingProducer; but I see the same result with both transactional and non-transactional producers...
#SpringBootApplication
public class So67194702Application {
public static void main(String[] args) {
SpringApplication.run(So67194702Application.class, args);
}
#Bean
public ApplicationRunner runner(ProducerFactory<String, String> pf) {
return args -> {
Producer<String, String> prod = pf.createProducer();
prod.close();
};
}
}
Putting a breakpoint on the close()...
Thanks Gary Russell for the very quick response. The createRawConsumer is effectivly called for both transactional and non transactional consumers.
Sleuth is using the TraceConsumerPostProcessor to wrap a Kafka consumer into a TracingConsumer. As the ProducerPostProcessor interface extends the Function interface, we may suppose the result of the function could/should be used but the createRawConsumer method of the DefaultKafkaProducerFactory is applying the post processors without using the return type. Causing the issue in this specific case.
So, couldn't we modify the implementation of the createRawConsumer to assign the result of the post processor. If not, wouldn't it be better to have post processors extending a Consumer instead of a Function?
Successful test made by overriding the createRawConsumer method as follow
#Override
protected Producer<K, V> createRawProducer(Map<String, Object> rawConfigs) {
Producer<K, V> kafkaProducer = new KafkaProducer<>(rawConfigs, getKeySerializerSupplier().get(), getValueSerializerSupplier().get());
for (ProducerPostProcessor<K, V> pp : getPostProcessors()) {
kafkaProducer = pp.apply(kafkaProducer);
}
return kafkaProducer;
}
Thank you for your help.

How can I send RoutingContext object from routing verticle to some other verticle using vertx.eventBus().send() method?

From my routing verticle which has route URL, I want to send RoutingContext object to another verticle. I believe we can only use vertx.eventBus().send() to send message from routing verticle to some other action verticle. Can I send RoutingContext object as a message?
In router verticle I am doing
vertx.eventBus().<RoutingContext>send("address", routingContext)
and in consumer verticle I am doing
vertx.eventBus().<RoutingContext>consumer("address").handler(message -> {
RoutingContext routingContext = message.body();
LOGGER.info("routingContext body = "+routingContext.getBodyAsString());
});
but looks like vertx itself is not able to execute 'vertx.eventBus().send'
Could anyone please let me know how could I send RoutingContext object using vertx.eventBus().send method?
If you want to send an object over Vert.x EventBus which is not a JsonObject or a plain Java object like a String, for example, you need to implement your own codec.
What that means is basically describing which parts of the object you want to transfer.
You can see examples of implementing your custom codec here:
https://github.com/vert-x3/vertx-examples/blob/master/core-examples/src/main/java/io/vertx/example/core/eventbus/messagecodec/util/CustomMessageCodec.java
It still doesn't make much sense to implement it for RoutingContext, in my opinion. Just transfer the parts that you actually need, not the entire object.

Scala folding using Akka

I implemented in Java what I called a "foldable queue", i.e., a LinkedBlockingQueue used by an ExecutorService. The idea is that each task as a unique id that if is in the queue while another task is submitted via that same id, it is not added to the queue. The Java code looks like this:
public final class FoldablePricingQueue extends LinkedBlockingQueue<Runnable> {
#Override
public boolean offer(final Runnable runnable) {
if (contains(runnable)) {
return true; // rejected, but true not to throw an exception
} else {
return super.offer(runnable);
}
}
}
Threads have to be pre-started but this is a minor detail. I have an Abstract class that implements Runnable that takes a unique id... this is the one passed in
I would like to implement the same logic using Scala and Akka (Actors).
I would need to have access to the mailbox, and I think I would need to override the ! method and check the mailbox for the event.. has anyone done this before?
This is exactly how the Akka mailbox works. The Akka mailbox can only exist once in the task-queue.
Look at:
https://github.com/jboner/akka/blob/master/akka-actor/src/main/scala/akka/dispatch/Dispatcher.scala#L143
https://github.com/jboner/akka/blob/master/akka-actor/src/main/scala/akka/dispatch/Dispatcher.scala#L198
Very cheaply implemented using an atomic boolean, so no need to traverse the queue.
Also, by the way, your Queue in Java is broken since it doesn't override put, add or offer(E, long, TimeUnit).
Maybe you could do that with two actors. A facade one and a worker one. Clients send jobs to facade. Facade forwards then to worker, and remember them in its internal state, a Set queuedJobs. When it receives a job that is queued, it just discard it. Each time the worker starts processing a job (or completes it, whichever suits you), it sends a StartingOn(job) message to facade, which removes it from queuedJobs.
The proposed design doesn't make sense. The closest thing to a Runnable would be an Actor. Sure, you can keep them in a list, and not add them if they are already there. Such lists are kept by routing actors, which can be created from ready parts provided by Akka, or from a basic actor using the forward method.
You can't look into another actor's mailbox, and overriding ! makes no sense. What you do is you send all your messages to a routing actor, and that routing actor forwards them to a proper destination.
Naturally, since it receives these messages, it can do any logic at that point.

Cancel GWT RequestFactory request

Is there a way to cancel/abort request factory requests? Using GWT 2.3
There is no way to cancel a request after the fire() method has been called. Consider building a custom Receiver base class such as the following:
public abstract class CancelableReceiver<V> extends Receiver<V> {
private boolean canceled;
public void cancel() {
canceled = true;
}
#Override
public final void onSuccess(V response) {
if (!canceled) {
doOnSuccess(response);
}
}
protected abstract void doOnSuccess(V response);
}
The pattern can be repeated for other methods in the Receiver type.
Another option would be to create an alternative com.google.web.bindery.requestfactory.shared.RequestTransport type, instead of using DefaultRequestTransport. Downside to this (and upside to BobV's approach) is that you won't know when in the request on the server you kill it, so it might have already run some of your methods - you won't get feedback from any of them, you'll just stop the outgoing request.
I suspect this is why RF doesn't have this feature already, as RPC does. Consider even the case of RPC though or RequestBuilder - how do those notify the server that they've changed their mind, and to not run the request? My understanding is that they don't - the only way they are shut down early is when they try to read/write to the response, and get a tcp error, as the connection has been closed. (It's possible I am mistaken, and that another thread keeps an eye on the state of the tcp connection and calls thread.stop(Throwable), but stop has been deprecated for quite a while.)
One thought would be to send a message to the server, telling it to kill off other requests from the same session - this would require active participation in your server code though, possibly made generic in a ServiceLayerDecorator subtype, probably in at least invoke, loadDomainObject(s), and getSetter, among others. This pretty clearly is to involved to ask GWT to build it for you though...

Callback between EJBs / local EJB calls

Can you register EJB A as callback in an MDB B?
B.register(Aref)
in B: A.callback()
What would be Aref if the EJBs use local calls?
SessionContext.getEJBLocalObject()?
What you ask is not really possible in the proposed way.
If B is a Message Driven Bean, then it's never possible to call a method on it. In the messaging paradigm, the type of the receiver of a message is unknown. You thus can't reference an instance of the MDB. Instead, you post messages to a queue or topic and if your MDB is configured to listen to that its onMessage() method will be invoked.
Secondly, in EJB you don't often pass references around like in your example code. What kind of EJB bean is A supposed to be? A stateless session bean, or a stateful session bean?
In case it's a stateless session bean, the instance might not matter and you can probably just inject it:
#MessageDriven
public class NSMessageDrivenBean implements MessageListener {
#EJB
private A yourABean;
public void onMessage(Message message) {
// process message and then call A
yourABean.someMethod();
}
}
If the callback needs to be done to a type that is unknown in advance (depending on the message being send), then one mechanism for this is via a JMS reply.
In the message being send to the message driven bean, you then include code like this:
message.setJMSReplyTo(someDestination);
message.setJMSCorrelationID(someCorrelationID);
someDestination represents your callback, it's a destination to which something is listening, and this something can then invoke the call on the stateless session bean (in the context of the client).
E.g. something like:
connection.createSession(false, Session.AUTO_ACKNOWLEDGE).createConsumer(someDestination).setMessageListener(
new MessageListener() {
#Override
public void onMessage(Message message) {
yourABean.someMethod();
}
}
In this case, someDestination can be a temporary destination.