MutableMessageBuilderFactory in Spring Integration - apache-kafka

I have a spring cloud stream consumer getting messages from Kafka. I want to modify the message headers, but currently the message I get is of type GenericMessage.
I saw this post and this code from spring integration core so I added to my configuration a bean of type MutableMessageBuilderFactory but I'm still getting the message as GenericMessage. Actually, the bean creating code doesn't even seem to get called, the getMessageBuilderFactory(BeanFactory beanFactory) in IntegrationUtils classs gets called multiple times and everytime beanFactory.getBean("messageBuilderFactory", MessageBuilderFactory.class) returns DefaultMessageBuilderFactory.
What might be the problem causing the factory I defined as bean not to work and the message to keep coming as GenericMessage?
Spring versions:
spring-boot: 1.5.21
spring-integration: 4.3.12

Messages are immutable and there are many reasons for that, but it's out of scope of this question. What you can do is create a new Message in your handler and return it. If you want to copy most of the previous message and then modify the header you can do this:
Message resultMessage = MessageBuilder.fromMessage(sourceMessage).setHeader("myExistingHeader", "foo").build();

Related

Mirth: Alerts triggered by errors in JS-based database writer don't have access to {messageId}?

Using mirth version 3.8.1. I've set up an alert for a channel's errors. When errors come from the destination transformer (which is Javascript), the alert is able to access the {messageId} variable and pull the correct id. However, when an error originates in the Javascript-based database writer, the alert just returns '{messageId}' instead of the value.
I tried a bunch of things...
The global map is accessible from the alert, but putting a message id in there would get overwritten by another processing thread.
Other destination types - http sender, tcp sender, channel writer, and even a non-javascript-based database writer destination all work.
I even stripped the database writer code down to just:
var dbConn;
dbConn = DatabaseConnectionFactory.createDatabaseConnection('com.mysql.cj.jdbc.Driver','jdbc:mysql://host:port/dbname','','');
Do I just have to raise specific exceptions within the db writer code and raise alerts when those exceptions are hit, and send the message id in the error string?
You stumbled across a bug. I opened an issue and a fix.
If not for another bug that also neglects to provide the messageId, you should be able to use alerts.sendAlert('Custom Error Message'). alerts is an instance of AlertSender from the User API that mirth creates for you. I created a fix for that as well.
The only workaround I know of at this time to manually send an alert that includes the messageId is to call the EventController directly. The caveat is that this is technically not supported as part of a public API and usage could break in future versions without notice.
com.mirth.connect.server.controllers.ControllerFactory
.getFactory()
.createEventController()
.dispatchEvent(new com.mirth.connect.donkey.server.event.ErrorEvent(
connectorMessage.getChannelId(),
connectorMessage.getMetaDataId(),
connectorMessage.getMessageId(),
com.mirth.connect.donkey.model.event.ErrorEventType.USER_DEFINED_TRANSFORMER,
connectorMessage.getConnectorName(),
null, /* connectorType */
'A TEST ERROR MESSAGE',
null /* throwable */
)
);
This will work as written from a filter, transformer, Javascript Writer, or Database Writer in javascript mode. In other contexts, connectorMessage won't be defined and you'll have to provide some of those values in a different way. If you don't need the messageId and don't want to throw an exception, just use alerts.sendAlert(errorMessage) since that doesn't require calling unsupported internal classes.

Notifying entities when entity state changes in Lagom

Assuming a Record entity, CreateRecord command and a RecordCreated event. I want to invoke some command on one or more other entities (in different modules). What would be the suggested approach to achieve this?
I was thinking about sending a message from the ReadSide handler of the Record entity, which could be received by corresponding service(s), which would convert it to a command and invoke on an entity.
EDIT, thanks #ignasi35: According to Message Broker API publishing of the messages could be possible with this code.
AggregateEventTag<RecordEvent> RECORD_EVENT_TAG = AggregateEventTag.of(RecordEvent.class);
public Topic<RecordMessage> recordsTopic() {
return TopicProducer.singleStreamWithOffset(offset -> {
return persistentEntityRegistry
.eventStream(RECORD_EVENT_TAG, offset)
.map(this::convertEventToRecordMessage);
});
}
Records are created, and corresponding events are persisted, but no messages are received by the following consumer:
#Singleton
public class RecordsConsumer {
#Inject
public RecordsConsumer(RecordService recordService){
recordService.recordsTopic().subscribe()
.atLeastOnce(Flow.fromFunction(this::displayMessage));
}
}
What am I doing wrong?
Finally solved it.
I ended up with a singleton service listening to RecordCreated events from PersistentEntityRegistry.eventStream. The service converts them to RecordMessage and exposes as a Topic (see my question above).
The issue with not receiving any enents from the exposed Topic was missing dependency to kafka-broker (strange that there was no warning about this, and the topic was just not exposed), in my case this was:
<dependency>
<groupId>com.lightbend.lagom</groupId>
<artifactId>lagom-javadsl-kafka-broker_2.12</artifactId>
</dependency>

Setting Scenario Endpoints

I am having problems setting an endpoint URI in a scenario for the Citrus Simulator. Here is how I am trying to build my scenario:
#Override
public void run(ScenarioDesigner scenario) {
scenario
.soap()
.receive().endpoint("{http://www.sikorsoftware.com/lov/schemas}LOVRequest")
.payload("<ns2:LOVRequest xmlns:ns2=\"http://www.sikorsoftware.com/lov/schemas\"><ns2:id>123456</ns2:id></ns2:LOVRequest>");
scenario
.soap()
.send()
.payload("<LOVResponse xmlns=\"http://www.sikorsoftware.com/lov/schemas\">" +
"Hi there!" +
"</LOVResponse>");
}
But I keep getting this message when I try to send a soap message:
o.s.ws.server.EndpointNotFound : No endpoint mapping found
for [SaajSoapMessage
{http://www.sikorsoftware.com/lov/schemas}LOVRequest]
What am I doing wrong. Should I be setting up my endpoints a different way?
Thanks,
Michael
The endpoint is always a reference to a Citrus Spring bean component, in particular the component id that is used to add the component to the Spring application context.
In addition to that the scenario endpoint is automatically referenced when using the scenario designer instance. So in case you want to receive the scenario triggering message you do not need any endpoint reference.
When your scenario is not called this is because of some other issue in your setup. Maybe the incoming request does not map to your scenario definition.

How to add a failure callback for kafka-python kafka.KafkaProducer#send()?

I would like to set a callback to be fired if a produced records fail. Initially, I would just like to log the failed record.
The Confluent Kafka python library provides a mechanism for adding a callback:
produce(topic[, value][, key][, partition][, on_delivery][, timestamp])
...
on_delivery(err,msg) (func) – Delivery report callback to call (from poll() or flush()) on successful or failed delivery
How can I achieve similar behaviour with kafka-python kafka.KafkaProducer#send() without having to use the deprecated SimpleClient using kafka.SimpleClient#send_produce_request()
Although it isn't documented, this is relatively straightforward. Whenever you send a message, you immediately get a Future back. You can append callbacks/errback's to that Future:
F = producer.send(topic=topic, value=message, key=key)
F.add_callback(callback, message=message, **kwargs_to_pass_to_callback_method)
F.add_errback(erback, message=message, **kwargs_to_pass_to_errback_method)
Relevant source code here:
https://github.com/dpkp/kafka-python/blob/1937ce59b4706b44091bb536a9b810ae657c3225/kafka/future.py#L48-L64
We really should document this, I filed https://github.com/dpkp/kafka-python/issues/1256 to track it.

JAX-RS(CXF) JSONProvider

I am new to JAX-RS, I am just starting with apache CXF, I am struck at "No message body writer has been found for response class" while trying to return "application/jason". I know, I can set the JSONProvider using spring context loader file, but I dont want to use spring. Is there any way to set JSONProvider to the application directly?
I made a mistake in my code, instead "application/json" I wrote "application/jason", I corrected it, and it is working. And I found that no need to set JSON Provider explicitly.