How to send a message to an endpoint in Mule 4 to trigger a flow - mule

With Mule 3 it was possible to send messages asynchronously to an endpoint using MuleClient:
MuleClient client = new MuleClient(muleContext);
client.dispatch("vm://vm.queue", "Message Payload", null);
Is there a way to migrate this functionality in Mule 4 since MuleClient has been removed?
I came across a post that suggested getting the flow by name and publishing the message to the flow as follows
Flow flow = registry.lookupByName("MyFlow").get();
InputEvent event = new DefaultInputEvent();
event.message(Message.of(payload));
flow.execute(event);
but I get a ClassNotFoundException for the class org.mule.runtime.internal.event.DefaultInputEvent

Using Harshank's recommendation I was able to push messages to a flow simply by getting a reference to the flow and triggering the flow by sending messages to the source.
Flow flow = registry.lookupByName(flowName).get();
ComponentLocation location = DefaultComponentLocation.from(flowName + "/source");
...
Message message = Message.of(payload);
CoreEvent coreEvent = CoreEvent.builder(EventContextFactory.create(flow, location)).message(message).build();
flow.process(coreEvent);
This is a much cleaner solution than what is implemented in the blog and works from beans initialized in the Spring module. As aled mentioned, this is bad practice, but in the interest of time it is a solution.

Related

Native way to send custom object in JMS queue? (citrus-simulator)

I'm looking for a native (correct, in terms of the framework) way to send thirdparty (custom) Object to JMS in citrus-simulator?
I have tried:
scenario
.send()
.payloadModel(myObject);
but in JMS queue myObject appears as com.consol.citrus.message.DefaultMessage instead of com...myObject.
Example:
Scenario - receives http POST request (as trigger) and send's JMS Object to message queue.
config
...
.useObjectMessages(true)
...
scenario
...
import com.temafon.data.MORequest;
#Scenario("morequest")
#RequestMapping(value = "/simulator/morequest",method = RequestMethod.POST)
public class JmsMoRequestScenario extends AbstractSimulatorScenario {
#Override
public void run(ScenarioDesigner scenario) {
MORequest request = new MORequest(12345678901L, "USSD", "1172", "ON",
11L);
request.setSourcePort(3);
scenario
.receive()
.payload("getmorequest");
scenario
.send("jms.queue.destination")
.payloadModel(request);
After this case, I expect to get in jms.queue.destination something like screen 1
Expectation
Reality
P.S. I have implemented workaround already, with JavaActionBuilder and jmsTemplate.send in additional class and
scenario
.java(//Object).method(//instance");
But it doesn't seems like correct citrus-simulator way
Setting the payloadModel() in Citrus Java DSL will always result in some kind of marshalled representation of the object and this is not what you want. Neither is using .useObjectMessages(true) working for you because this results in the whole Citrus message object to be used as message payload.
You need to define a complete Citrus message object and that will remain untouched in terms of payload creation for the JMS destination. Citrus is then automatically using a JMS object message with proper object payload.
MORequest request = new MORequest(12345678901L, "USSD", "1172", "ON", 11L);
request.setSourcePort(3);
scenario
.receive()
.payload("getmorequest");
scenario
.send("jms.queue.destination")
.message(new JmsMessage(request));
Note that I am using the .message() fluent API instead of the payloadModel() API. The message API receives a Citrus message object such as com.consol.citrus.jms.message.JmsMessage or com.consol.citrus.message.DefaultMessage
Your custom domain model object request is used as constructor arg and will result in the JMS message as object payload as is. Of course MORequest must be of type java.io.Serializable

How to put failed custom object of javax.mail.Message into jms queue (using Activemq)

I am creating utiltiy which send mail using my outlook account, to do so I am creating object of javax.mail.Message and send it, if message sending is failed due to SendingFailedException, I want to add those messages into jms queue, and at the other end listener will run at every 10 min interval to consume these messages from the queue and try to resend those messages.
I have gone through some of the stackoverflow topics related to same, they instructed to change message into xml or in JSON, I just want to know how to deal with it, if that would be the way to implement this.
Thanks in advance
Using the MimeMessage.writeTo method you can turn the message into a byte stream. Collect it in a ByteArrayOutputStream and then include the bytes in the JMS message. At the other end, you can reconstitute the message using the MimeMessage constructor that takes an InputStream.
For example:
ByteArrayOutputStream bos = new ByteArrayOutputStream();
msg.writeTo(bos);
byte[] data = bos.toByteArray();
// put the data in a JMS message
// in the receiver, extract the byte array from the message
byte[] data = ...
MimeMessage msg = new MimeMessage(session, data);
Sorry, I can't help you with the JMS part.

OperationContext.Current.OutgoingMessageProperties in BizTalk

Have to add OperationContext.Current.OutgoingMessageProperties to outgoing BizTalk message
How to implement below code in BizTalk?
ConcurrentPrograms_ARClient client1 = new ConcurrentPrograms_ARClient(binding, address);
using (new OperationContextScope(client1.InnerChannel))
{
OperationContext.Current.OutgoingMessageProperties.Add("Property Name", "Property Value");
client1.OPERATION(params...);
}
You might want to take a look at WCF message inspectors.
You can implement one in a separate project and configure it as a behavior in your send port where you would then have full control over both the request and the reply message.

ActiveMQ: multi-consumers connected to one queue but only one consumer recieve all the messages

I was currently using NMS to develop application based ActiveMQ(5.6).
We have several consumers(exe) trying to recieving massgaes from the same queue(not topic). While all the messages just all go to one consumer though I have make the consumer to sleep for seconds after recieving a message. By the way, we don't want the consumers recieving the same messages other consumers have recieved.
It is mentioned in the official website that we should set Prefetch Limit to decide how many messages can be streamed to a consumer at any point in time. And it can both be configured and coded.
One way I tried is to code using PrefetchPolicy class binding the ConnectionFactory class like bellow.
PrefetchPolicy poli = new PrefetchPolicy();
poli.QueuePrefetch = 0;
ConnectionFactory fac = new ConnectionFactory("activemq:tcp://Localhost:61616?jms.prefetchPolicy.queuePrefetch=1");
fac.PrefetchPolicy = poli;
using (IConnection con = fac.CreateConnection())
{
using (ISession se = con.CreateSession())
{
IDestination destination = SessionUtil.GetDestination(se, queue, DestinationType.Queue);
using (IMessageConsumer consumer = se.CreateConsumer(queue1))
{
con.Start();
while (true)
{
ITextMessage message = consumer.Receive() as ITextMessage;
Thread.Sleep(2000);
if (message != null)
{
Task.Factory.StartNew(() => extractAndSend(message.Text)); //do something
}
else
{
Console.WriteLine("No message received~");
}
}
}
}
}
But no matter what prefetch value I set the behavior of the consumers stay the same as before.
And I've tried the second way tying to get the result, namely configure the server conf file. I change the activemq.xml of the server like bellow.
" producerFlowControl="true" memoryLimit="5mb" />
" producerFlowControl="true" memoryLimit="5mb">
But though I've set the dispatchpolicy the messages still go to one consumer.
I want to know that:
Whether this behavior can be achieved by just configuring the server xml file to enable all the consumers recieve messages from one queue? If so, how to configure this and what is wrong with my configuration? If not, how can I use codes to achieve the goal?
Thanks.
Take a look at "Message Groups" feature.
I had the same problem. Only one consumer processed all messages. I found in my code I used group header during send:
request.Properties["NMSXGroupID"] = "cheese";
According to official docs:
Standard JMS header JMSXGroupID is used to define which message group
the message belongs to. The Message Group feature then ensures that
all messages for the same message group will be sent to the same JMS
consumer - while that consumer stays alive. As soon as the consumer
dies another will be chosen.
See full details at http://activemq.apache.org/message-groups.html

How can I delete/remove an ActiveMQ subscriber using NMS API

I need to remove/delete my topic subscriber. I found this http://activemq.apache.org/manage-durable-subscribers.html
However, it's not good enough for us. We want to control the timing of removing a subscriber, and no matter there are any message or not. Besides, our program is written by C#. So the best solution for us is NMS API.
Thanks.
Here are the code,
Apache.NMS.ActiveMQ.ConnectionFactory factory = new Apache.NMS.ActiveMQ.ConnectionFactory(m_brokerURI);
m_connection = factory.CreateConnection(username, password);
Apache.NMS.ActiveMQ.Connection con = (Apache.NMS.ActiveMQ.Connection)m_connection;
ISession session = m_connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
try
{
session.DeleteDurableConsumer(strQueueName);
}
catch (Exception ex)
{
// log the error message
}
Update
Our scenario is quite simple.
A client built a queue and subscribed a consumer on a topic.
the client side closed the connection.
delete the consumer on the server side(as the example code in the last update)
Here is the snapshot of activemq broker via jconsole:
jconsole snapshot
We would like to remove the subscriber “7B0FD84D-6A2A-4921-967F-92B215E22751” by following method,
But always got this error "javax.jms.InvalidDestinationException : No durable subscription exists for: 7B0FD84D-6A2A-4921-967F-92B215E22751"
strSubscriberName = “7B0FD84D-6A2A-4921-967F-92B215E22751”
session.DeleteDurableConsumer(strSubscriberName);
To delete a durable subscription from the NMS API you use the DeleteDurableConsumer method defined in ISession. You must call this method from a Connection that uses the same client Id as was used when the subscription was created and you pass the name of the subscription that is to be removed. The method will fail if there is an active subscriber though so be prepared for that exception.
In the sample code you don't set a Client Id on the connection. When working with durable subscriptions you must, must, MUST always use the same client Id and subscription name. So in you same you will get this error until you set the client Id to the same value as the connection that created the subscription in the first place.