I want to print both key and value in ForEach. I am able to get the Keyset but not individual key.
<set-variable variableName="fileContents" value="#[message.payload]" />
<foreach collection="#[message.payload]">
<logger message="#[fileContents.keySet()]" level="INFO" doc:name="Logger"/>
<logger message="#[message:payload]" level="INFO" doc:name="Logger"/>
</foreach>
If fileContents is a Map, then you should use collections=#[payload.entrySet()]. That way within the foreach you can do #[payload.key] and #[payload.value] (because the payload in each step will be an Entry).
Related
i want to log out to different files because there are too many and hard to fallow. For example i have hospital application and i want separate log file for every different action like appointment, reports and patient
public org.apache.logging.log4j.Logger logManager = LogManager.getLogger("appointment-log");
public org.apache.logging.log4j.Logger logManager = LogManager.getLogger("reports-log");
public org.apache.logging.log4j.Logger logManager = LogManager.getLogger("patient-log");
i can do reports log like below
<appender name="FILE-REPORTS" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOGS_HOME}${REPORTS_LOG}</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss};%msg%n
</Pattern>
</encoder>
<param name="Append" value="False" />
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${LOGS_HOME}REPORTS.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<logger name="reports-log" level="info" additivity="false">
<appender-ref ref="FILE-REPORTS"/>
<appender-ref ref="STDOUT"/>
</logger>
Everything is ok till here but i dont want to write appender for appointment and patient and many more, i want to use only 1 appender then i will pass file name from , psudo like below
<logger name="patient-log" level="info" additivity="false">
<appender-ref ref="PATIENT-AUDIT" **fileName="patient.log"**/>
<appender-ref ref="STDOUT"/>
</logger>
I am storing the output from DB in a flowvar #[flowvars.test] after which I am iterating the payload to remove few key, value pair. when the payload is modified inside the for loop the value which is stored in flowvars also getting modified.I am using mule 3.9 runtime.
<db:parameterized-query><![CDATA[select MachineName,TransactionId,SourceAPIName,Source,Target,ErrorCode,Severity,MailContent,ExceptionType,ExceptionMessage from Notification
where Notify='Y' and IsNotify='N']]>
</db:select>
</poll>
<expression-filter expression="#[payload.size()>0]" doc:name="Stop If No Records"/>
<set-variable variableName="test" value="#[message.payload]" doc:name="Variable"/>
<set-variable variableName="validatedEntries" value="#[[]]"
doc:name="ValidatedEntries" />
<logger level="INFO" doc:name="Logger"/>
<foreach collection="#[flowVars.test]" doc:name="For Each">
<logger level="INFO" doc:name="Logger"/>
<set-variable variableName="tempNotificationTable" value="#[payload.remove('TransactionID')]" doc:name="Temp NotificationTable"/>
<expression-component doc:name="Expression"><![CDATA[#[flowVars.validatedEntries.add(payload)]]]></expression-component>
</foreach>
For-Each will not create a deep copy of the object. Because of this, your original payload is getting changed.
I have the below flow which returns a list of values from DB with in mule.
I want to be able to get only the value part of the result from DB instead of a full linked list in the format of "column=value". I want to use the value part as part of a URL in the next http block. Please see my flow below. Any feedback will be helpful please.
<http:request-config name="HTTP_Request_Configuration" protocol="HTTPS" host="jsonplaceholder.typicode.com/#[flowVars.custID]" port="443" doc:name="HTTP Request Configuration"/>
<http:listener-config name="HTTP_Listener_Configuration1" host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration"/>
<flow name="dbcconnectorFlow">
<http:listener config-ref="HTTP_Listener_Configuration2" path="/lockStatus" allowedMethods="PUT" doc:name="HTTP"/>
<db:select config-ref="Oracle_Configuration" doc:name="Database">
<db:dynamic-query><![CDATA[select CUST_NO FROM CUSTOMERS WHERE LOCKED='N']]></db:dynamic-query>
</db:select>
<logger message="#[message.payload]"" level="INFO" doc:name="Logger"/>
<set-variable variableName="custID" value="#[message.payload[0]]" doc:name="Variable"/>
<http:request config-ref="HTTP_Request_Configuration" path="/" method="PUT" doc:name="HTTP"/>
</flow>
Ekow
One way to get only the value part of the result from DB is to put a transform message (Dataweave) component after the DB component and configure it as shown in this example:
<flow name="myprojectFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="HTTP"/>
<db:select config-ref="MySQL_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[select CompanyName from Customers limit 10]]></db:parameterized-query>
</db:select>
<response>
<dw:transform-message doc:name="Transform Message">
<dw:set-payload><![CDATA[%dw 1.0
%output application/json
---
payload.CompanyName[1]]]></dw:set-payload>
</dw:transform-message>
</response>
</flow>
The output is the first company name string in the array. The column name is not included.
Found a way around this. I had to convert the db results which was an object into xml using the object to xml transformer. Then use the splitter to split the results since I was expecting multiple output as below
[xpath3('//root/data/"xml_tag_of_required_data"', payload, 'NODESET')]. I then set the output as a variable and referenced the variable in the http endpoint URL.
I need to throw an exception if the query parameter say "requestId" is not present in request URL.
The URL looks like this: my.server.com?requestId=123&age=26
Here I'm logging the requestId in message property like this:
<message-properties-transformer scope="session" doc:name="Adding requestId">
<add-message-property key="requestId" value="#[message.inboundProperties.'http.query.params'.requestId]"/>
</message-properties-transformer>
If the URL does not contain the requestId it will be null. But in this case I want to do a check for requestId whether it is present or not.
Then
As per your requirement you can do the following :-
<choice doc:name="Choice">
<when expression="#[org.mule.util.StringUtils.isNotEmpty(message.inboundProperties.'http.query.params'.requestId)]">
<logger message="query parameter exist" level="INFO" doc:name="Logger"/>
</when>
<otherwise>
<logger message="query parameter does not exist" level="INFO" doc:name="Logger"/>
<!-- Throw your exception here -->
<scripting:component doc:name="Script">
<scripting:script engine="Groovy"><![CDATA[
throw new IllegalArgumentException('query parameter does not exist')
]]></scripting:script>
</scripting:component>
</otherwise>
</choice>
Here If Query parameter exists it will simply log in a logger and if Query parameter does not exists it will throw the exception you want ..
Thanks all for putting your thoughts. Finally I got a simple way using groovy where I don't need to put any choice router or any expression filters. He is my code :
if(!message.getInboundProperty("http.query.params").find{ it.key == "requestId" }){
throw new IllegalArgumentException('requestId does not exist');
}
Have you tried message filters?
<message-filter throwOnUnaccepted="true">
<expression-filter
expression="#[message.inboundProperties.'http.query.params'.requestId != empty]" />
</message-filter>
This will throw an FilterUnacceptedException when requestId is null, false, empty, zero or an empty collection.
You have to change the condition if the filter needs to accept zero.
Use the below expression to check the query parameter availability in HTTP URL
#[org.mule.util.StringUtils.isNotEmpty(message.inboundProperties.'http.query.params'.requestId)]
See below sample code that used choice router and based on query param availability it routes the control
<choice doc:name="Choice">
<when expression="#[org.mule.util.StringUtils.isNotEmpty(message.inboundProperties.'http.query.params'.requestId)]">
<logger message="Query param available in request level="INFO" doc:name="Logger"/>
</when>
<otherwise>
<logger message="Query param not available in request level="INFO" doc:name="Logger"/>
</otherwise>
</choice>
I would like to iterate through an array and use the value taken from the array to put it within an http inbound endpoint. How would I be able to iterate through this array and take the value from the array to place it as a variable within the http inbound endpoint?
The code that I used to try was:
<flow name="foreachFlow1" doc:name="foreachFlow1">
<poll frequency="2000">
<foreach collection="#[groovy:['localhost:8082', 'localhost:8083']]"
doc:name="For Each">
<http:outbound-endpoint exchange-pattern="request-response"
address="http://#[payload]" method="GET" doc:name="HTTP" />
</foreach>
</poll>
</flow>
and I get the error
Invalid content was found starting with element 'poll'
Inbound endpoints are message sources and can not be parametrized the way you're describing.
To achieve your goal, trying a <poll> message source to wrap a foreach that uses http:outbound-endpoint to perform GET (#method) request-response (#exchange-apttern) interactions.
The trick is to bring the results for the HTTP calls back through the foreach, which by default do not do it. The following illustrate a potential approach:
<flow name="foreachFlow1">
<poll frequency="2000">
<processor-chain>
<set-variable variableName="httpResponses" value="#[[]]" />
<foreach collection="#[groovy:['localhost:8082', 'localhost:8083']]">
<http:outbound-endpoint
exchange-pattern="request-response" address="http://#[payload]"
method="GET" />
<expression-component>httpResponses.add(message.payloadAs(java.lang.String))
</expression-component>
</foreach>
</processor-chain>
</poll>
<logger level="INFO" message="#[httpResponses]" />
</flow>
<!-- Test server stubs -->
<flow name="server8082">
<http:inbound-endpoint exchange-pattern="request-response"
address="http://localhost:8082" />
<set-payload value="This is 8082" />
</flow>
<flow name="server8083">
<http:inbound-endpoint exchange-pattern="request-response"
address="http://localhost:8083" />
<set-payload value="This is 8083" />
</flow>