Inbound properties are lost in transition between two flows - properties

There are two flows Flow1, Flow2.
In Flow1 i am able to get some inbound properties and i copy these properties to outbound scope.
println 'Copying inbound properties to session:'
message.inboundPropertyNames.each { prop ->
message.setOutboundProperty(prop, message.getInboundProperty(prop))
println 'Setting ' + prop + ' --> ' + message.getInboundProperty(prop)
}
But i am not able to get these outbound properties in Flow2.

If you are calling flow 2 via an outbound-endpoint, the properties you put in the outbound scope will be moved back to the inbound scope. So you will need to access them as inboundProperties in flow 2.
Also, you could also use the copy-properties transformer to handle the copying for you:
<copy-properties propertyName="•" />

Related

[wso2][APIM 3.2] conditional engagement of handler does not work

I try to write my own WSO2 3.2 APIM Handler.
My purpose is :
engage Handler when a dedicated property is set on API
consume the request and use the binary response to decrypt part of it
change the content type of the response after decryption
I successfuly write my handler and modify the velocity_template.xml as follow (following the documentation):
#if($apiObj.additionalProperties.get('encrypted') == "true"))
<handler class="org.rudi.wso2.mediation.EncryptedMediaHandler">
<property name="encryptedMimeType" value="$apiObj.additionalProperties.get('encrypted_mime_type')"/>
<property name="mimeType" value="$apiObj.additionalProperties.get('mime_type')"/>
<property name="providerUuid" value="dummy"/>
</handler>
#end
But this does not work and the handler is not engaged.
If I remove the #if condition the handler is engaged but the properties are not interpreted (for exemple the "mimeType" field is explicitly set to "$apiObj.additionalProperties.get('mime_type')" and not to the value of the additionnalProperty set on API.
What is wrong ?
How could I use the additionnal properties added on API ?
Next when the Handler is called, I did not find any way to read the response of the endpoint.
I find code to change the response ou the response status code to write fault for exemple
But I did not find a way to read the binary response send by my endpoint to work on it.
Help will be appreciated!
UPDATED
For the second part of the question, I create a method as follow:
private void replaceBody(SOAPBody body) throws IOException {
OMElement element = body.getFirstElement();
if (element.getLocalName().equalsIgnoreCase(BINARY_LOCAL_NAME)) {
OMNode subChild = element.getFirstOMChild();
if (subChild instanceof OMText && ((OMText) subChild).isBinary()) {
OMText textNode = ((OMText) subChild);
DataHandler originalDataHandler = (DataHandler) textNode.getDataHandler();
InputStream modifiedInputStream = modify(originalDataHandler.getInputStream());
DataHandler newDataHandler = new DataHandler(new StreamingOnRequestDataSource(modifiedInputStream ));
OMText newTextNode = body.getOMFactory().createOMText(newDataHandler, true);
textNode.insertSiblingBefore(newTextNode);
textNode.detach();
}
}
}
And I lookup for SOAPBody as follow :
org.apache.axis2.context.MessageContext axis2MC = ((Axis2MessageContext) messageContext)
.getAxis2MessageContext();
RelayUtils.buildMessage(axis2MC, true);
axis2MC.setProperty(RelayConstants.FORCE_RESPONSE_EARLY_BUILD, Boolean.TRUE);
SOAPBody body = axis2MC.getEnvelope().getBody();
I test the behaviour on small file but I think we need to do more stuff to handle big file ou chunked api.
Any advice?
Regarding velocity_template.xml & API Properties Configurations
The velocity_template.xml file is used to construct the API Synapse Artifacts to deploy them in the Gateway. As it is a common template file, you have to place your conditions and customizations in the correct sections of the template to reflect in the Synapse Artifact.
If you are trying to publish a REST API, then place your code block after this section in the velocity_template.xml
#foreach($handler in $handlers)
<handler xmlns="http://ws.apache.org/ns/synapse" class="$handler.className">
#if($handler.hasProperties())
#set ($map = $handler.getProperties() )
#foreach($property in $map.entrySet())
<property name="$!property.key" value="$!property.value"/>
#end
#end
</handler>
#end
<!-- place your block here -->
This makes sure, that your handler is engaged after all mandatory Handlers of the API Managers are engaged. If you want to engage your handler in the middle, then add a condition within #foreach block to append your handler. You can follow this doc for more detailed information.
Once the velocity_template.xml changes are made, re-publish the API by selecting the Gateway environments to deploy the updated Synapse Artifacts. If it is a distributed environment, make sure to update the velocity_template.xml of the Publisher node.
Also, check for any typos in your code block: I see an extra ) at the end of the #if condition.
#if($apiObj.additionalProperties.get('encrypted') == "true"))
...

ServiceStack.RabbitMq - how to set custom attributes on messages

We use ServiceStack.RabbitMq and I could not find a way to put a custom attribute on the rabbit mq message. I want the publisher to set the attribute on the message and the worker to read it.
A variant is to move that attribute as part of request body but I have a lot of requests and in all honesty the request should not know at all about this kind of information - as that is metadata of the message.
Any idea how this can be achieved?
You can use the Message Filters in RabbitMqServer to add and introspect message properties, e.g:
var mqServer = new RabbitMqServer("localhost")
{
PublishMessageFilter = (queueName, properties, msg) => {
properties.AppId = "app:{0}".Fmt(queueName);
},
GetMessageFilter = (queueName, basicMsg) => {
var props = basicMsg.BasicProperties;
receivedMsgType = props.Type; //automatically added by RabbitMqProducer
receivedMsgApp = props.AppId;
}
};
You could either add the custom attribute to the object you are pushing down the queue or add that attribute to the rabbit message metadata header table. RabbitMQ messages have various metadata attributes that can be set when a message is published.
Check this

Camel Iterator or How to use Camel Splitter but keep body unchanged

I want to iterate String with a delimiter "," and then send message to several endpoint. The problem is if I use Splitter, it would replace the body content of my message.
from("switchyard://ICamelServiceProcess")
.process(new Processor() {
String recipients = "abc";
recipients += "," + "bcd";
exchange.getIn().setHeader("recipients", recipients);
}
.to("switchyard://ICamelServiceRoute");
In Service ICamelServiceRoute, I want to iterate through header.recipients value with delimiter "," and then create a file with a named of each iteration.
Could you please tell me some solution.
Thank you.
You can save the original body in a exchange property before the splitter, and restore it from the property when finish splitter. With Camel 2.15 or latter
<setProperty propertyName="originalBody">
<simple>${body}</simple>
</setPropery>
<split>
<!-- Splitter function -->
</split>
<setBody>
<simple>${exchageProperty[originalBody]}</simple>
</setBody>
All exchange properties will be deleted when finish the camel context execution. Note that you can save Java Object in exchange properties, but only until the camel context ending

How do you set message properties in Mule using Groovy?

How do you set message properties in Mule using Groovy?
I need to set a message property from within a Groovy Scripting Component. Documentation on the subject does not appear to be easy to find.
You can set individual properties as follows:
message.setInvocationProperty('myFlowVariable', 'value') // sets a flow variable, like <set-variable/>
message.setOutboundProperty('myProperty', 'value') // sets an outbound message property, like <set-property/>
message.setProperty('myInboundProperty', 'value', PropertyScope.INBOUND) // sets an inbound property
In the scripting component you have available the message binding that is an instance of org.mule.api.MuleMessage, thus you can use the method org.mule.api.MuleMessage.addProperties(Map, PropertyScope) to add any property you need.
It depends on which version of Mule EE (and so then Groovy) you are using, but in recent versions of Mule (3.7.x) the easiest way is:
flowVars ['name_of_variable'] = 'value'
flowVars ['name_of_variable'] = 14
This for variables with Invocation scope, if you wan to store variable for Session scope, then:
sessionVars ['name_of_variable'] = 'value'
sessionVars ['name_of_variable'] = 14
Please use this site from Mulesoft for Scripting as reference.
https://docs.mulesoft.com/mule-user-guide/v/3.7/script-component-reference
Here is how I figured it out:
add schema to your flow if missing:
xmlns:scripting="http://www.mulesoft.org/schema/mule/scripting"
http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd
now let's set session-variable 'account' with a custom Foo object using Groovy:
<scripting:transformer doc:name="Script">
<scripting:script engine="groovy"><![CDATA[
com.test.Foo f = new com.test.Foo();
f.setAccountId('333');
return message.setSessionProperty('account',f);]]>
</scripting:script>
</scripting:transformer>
above script will turn your Payload to NullPayload, because it is a transformer. If that' a concern, try this instead:
<enricher target="#[sessionVars['account']]">
<scripting:transformer doc:name="Script">
<scripting:script engine="groovy"><![CDATA[
com.test.Foo f = new com.test.Foo();
f.setAccountId('333');
return f;]]>
</scripting:script>
</scripting:transformer>
</enricher>
Enjoy. :)

How copy selected property (not all) from camel to activiti

Camel scenario:
read file
do something e.g store content in database
run activiti process and pass variable from previous step
RouteBuilder:
from("file:/home/work/Inbox")
.to("bean:sourceFileService?method=storeFile")
.to("activiti:Receive?copyVariablesFromProperties=true")
During call bean sourceFileService property 'sourceFileId' is set.
This variable should be transferred to the process Receive as variable.
If I don't use copyVariablesFromProperties any variable is not set in process.
One the other side when copyVariablesFromProperties=true then camel try pass all properties and exception occurs:
ActivitiException: couldn't find a variable type that is able to serialize GenericFile
(because one of property is object represents read file, there are 7 other unwanted property )
How pass only selected property to activiti endpoint or in camel any next 'to' ?
change sourceFileService's storeFile method signature as follows;
public String storeFile(... your other params, #OutHeaders Map headers) {
...
headers.put("sourceFileId", "32132132");
....
}
and you can access the set sourceFileId in your activiti endpoint
I have found that the use of copyVariablesFromProperties is not necessary.
The same is achieved by
.setBody().properties()
.to("activiti:Receive")
When in body is Map camel set variables for activiti process using that map.
But I still get exception for the same reason (pass unwanted, not serializable object).
The only solution I have found is
from("file:/home/work/Inbox")
.to("bean:sourceFileService?method=storeFile")
.setBody(method(Helper.class))
.to("activiti:Receive")
where
public class Helper {
#Handler
public Map getProcessVariables(Exchange exchange) {
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("sourceFileId, exchange.getProperty("sourceFileId"));
return variables;
}
}