Mule CXF Marshall Response - cxf

I am using cxf:jaxws-client in Mule 3 and the response I get from my web service call is of type ReleasingInputStream. I have tried adding the http-response-to-message-transformer, but that generates an error - does anyone know how I can retrieve the response as an object as opposed to a ReleasingInputStream?
Many thanks.

To solve the issue put the <cxf-client> inside the <outbound-endpoint> section (NOT BEFORE IT), by modifying the following code
<cxf:jaxws-client
clientClass="com.xyz.services.WSServices"
port="WSServicesSoap"
wsdlLocation="classpath:wsdl-file.wsdl"
operation="GimmeDataOperation" />
<outbound-endpoint exchange-pattern="request-response" address="http://localhost:8083/OutboundService" />
which produces a ReleasingInputStream output to
<outbound-endpoint exchange-pattern="request-response" address="http://localhost:8083/OutboundService" >
<cxf:jaxws-client
clientClass="com.xyz.services.WSServices"
port="WSServicesSoap"
wsdlLocation="classpath:wsdl-file.wsdl"
operation="GimmeDataOperation" />
</outbound-endpoint>
that returns the expected object.

I was just having this same problem. I solved it by adding an ObjectToString transformer to the response side of the outbound endpoint like this:
<mule>
<object-to-string-transformer name="ObjectToString"/>
<flow>
...
...
...
<cxf:jaxws-client clientClass="com.my.ClientClass"
port="MyPort"
wsdlLocation="classpath:MyWsdl.wsdl"
operation="MyOperation" />
<outbound-endpoint address="http://some.address/path/to/service"
exchange-pattern="request-response"
responseTransformer-refs="ObjectToString" />
...
...
...
</flow>
</mule>

The whole point of jaxws-client is to receive the unmarshaled Java object, so getting the WS response as a String or ReleasingInputStream should not even be an option.
To make the <cxf:jaxws-client> "work" as one would expect the WS client to work - put the INSIDE of the <outbound-endpoint> you will be getting a correct Java object as a payload.

Related

Mule 4 dynamic queries in the Database Connector

In my flow in Mule 4 I am trying to query a database for specific data.
For example I want to run a query like this:
SELECT * FROM mulesoft WHERE plant = CCCNNB;
The thing is both plant and CCNNB need to be dynamic. They will come through an API request. I can handle the value to be dynamic, but I get empty results whenever I try to make the field dynamic.
I first create a variable which stores the json from the request:
set-variable value="#[payload]" doc:name="Set Variable" doc:id="8ed26865-d722-4fdb-9407-1f629b45d318" variableName="SORT_KEY"/>
Request looks like this:
{
"FILTER_KEY": "plant",
"FILTER_VALS": "CCNNB"
}
Afterwards in the db connector I configure the following:
<db:select doc:name="Select" doc:id="13a66f51-2a4e-4949-b383-86c43056f7a3" config-ref="Database_Config">
<db:sql><![CDATA[SELECT * FROM mulesoft WHERE :filter_key = :filter_val;]]></db:sql>
<db:input-parameters ><![CDATA[#[{
"filter_val": vars.SORT_KEY.FILTER_VALS,
"filter_key": vars.SORT_KEY.FILTER_KEY
}]]]></db:input-parameters>
Replacing :filter_key with plant works but as soon as I try to make it dynamic I get nothing in the response. It does not fail though, response code is 200 but I get nothing inside it.
How can I make this work?
You can directly use the stored variables in the query itself.
Query Should be an expression in DataWeave.
#["SELECT * FROM $(vars.table) WHERE $(vars.SORT_KEY.FILTER_KEY) = :filter_val"]
<db:select config-ref="Database_Config">
<db:sql><![CDATA[#["SELECT * FROM $(vars.table) WHERE $(vars.SORT_KEY.FILTER_KEY) = :filter_val"]]]></db:sql>
<db:input-parameters ><![CDATA[#[{
"filter_val": vars.SORT_KEY.FILTER_VALS
}]]]>
</db:input-parameters>
</db:select>
There is another way also to read values from payload to build a dynamic query as below
#["SELECT * FROM mulesoft
WHERE " ++ vars.SORT_KEY.FILTER_KEY ++ " = '" ++ vars.SORT_KEY.FILTER_VALS ++ "'"]
Below is the XML that is created for this, as a POC
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:os="http://www.mulesoft.org/schema/mule/os"
xmlns:salesforce="http://www.mulesoft.org/schema/mule/salesforce"
xmlns:db="http://www.mulesoft.org/schema/mule/db"
xmlns:xml-module="http://www.mulesoft.org/schema/mule/xml-module"
xmlns:http="http://www.mulesoft.org/schema/mule/http"
xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core"
xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/db http://www.mulesoft.org/schema/mule/db/current/mule-db.xsd
http://www.mulesoft.org/schema/mule/os http://www.mulesoft.org/schema/mule/os/current/mule-os.xsd">
<http:listener-config name="HTTP_Listener_config1"
doc:name="HTTP Listener config"
doc:id="6d5de64b-1355-4967-9352-4b324f02c7ad">
<http:listener-connection host="0.0.0.0"
port="8081" />
</http:listener-config>
<db:config name="Database_Config" doc:name="Database Config"
doc:id="d5c4d49c-aef3-4d4a-a7b5-470da3354127">
<db:my-sql-connection host="localhost"
port="3306" user="root" password="admin123" database="Mysql" />
</db:config>
<flow name="testFlow"
doc:id="8cfea1b0-d244-40d9-989c-e136af0d9f80" initialState="started">
<http:listener doc:name="Listener"
doc:id="265e671b-7d2f-4f3a-908c-8065a5f36a07"
config-ref="HTTP_Listener_config1" path="test" />
<set-variable value="#[payload]" doc:name="Set Variable"
doc:id="265a16c5-68d4-4217-8626-c4ab0a3e38e5" variableName="SORT_KEY" />
<db:select doc:name="Select"
doc:id="bdf4a59c-0bcc-46ac-8258-f1f1762c4e7f"
config-ref="Database_Config">
<db:sql><![CDATA[#["SELECT * FROM mulesoft.mulesoft WHERE " ++ vars.SORT_KEY.FILTER_KEY ++ " = '" ++ vars.SORT_KEY.FILTER_VALS ++ "'"]]]></db:sql>
</db:select>
<ee:transform doc:name="Transform Message"
doc:id="72cbe69f-c52e-4df9-ba5b-dd751990bc08">
<ee:message>
<ee:set-payload><![CDATA[%dw 2.0
output application/json
---
payload]]></ee:set-payload>
</ee:message>
</ee:transform>
</flow>
</mule>
Explanation of the Flow
I am using the payload that is in Question
Seting a variable name "SORT_KEY", value of this varibale is complete payload that we receive.
then creating a dynamic query inside the Db connector
using transform message sending the data as response, that we received from DataBase
So, there are several issues here. One, the creation of the sql statement.
You can do DW inside the DB:SELECT component if you want, as shown by previous answers. Either the
#["SELECT * FROM myTable" ++ vars.myWhere]
OR
#["SELECT * FROM myTable $(vars.myWhere)"]
work.
The problem you will run into is that DataSense doesn't like this. Without the literal text for the column names, DataSense can't figure out what columns to retrieve so it raises an error "Unable to resolve value for the prameter: sql". This leaves an error in your code, which always gives me angst. I wish Mulesoft would resolve this problem.
BTW, if you do dynamic SQL, you should STILL use input parameters for each value to avoid SQL injections.
I have an "Idea" posted here to fix the bogus error: https://help.mulesoft.com/s/ideas#0872T000000XbjkQAC

PrettyPrint feature does not work in Apache Camel

I have been trying to leverage the PrettyPrint feature to display the result of my API that is using Apache Camel. Here is the context. I have this route in my code
// Route Definition for processing Health check request
from("direct:processHealthCheckRequest")
.routeId("health")
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200))
.setBody(constant(healthCheckResponse));
When I'm using Postman to test my API, the display is in pretty mode even though it is not set to true, like so
{
"status": "UP"
}
Now when I'm using the following code to set the PrettyPrint to false, I'm still getting the same result. It looks like the PrettyPrint feature is not working as it is supposed to
// Route Definition for processing Health check request
from("direct:processHealthCheckRequest")
.routeId("health")
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200))
.setBody(constant(healthCheckResponse))
.unmarshal()
.json(JsonLibrary.Jackson, HealthCheckResponse.class, false);
I'm expecting the result to be displayed on one line like here without changing the type from JSON to string.
{"status": "UP"}
Could someone please advice on this?
I've bumped into the same issue always when manually setting the HTTP_RESPONSE_CODE header. I don't know why it technically happens - without it the HTTP response always returns proper JSON for me.
Setting CONTENT_TYPE header to application/json has solved it:
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
The solution that finally worked was to set the following in my application.properties file.
camel.rest.data-format-property.prettyPrint=false
or not to provide that property at all.
Try this:
<removeHeaders id="removeHeaders_http*" pattern="CamelHttp*"/>
<setHeader headerName="Content-type" id="content_setHeader">
<constant>application/x-www-form-urlencoded</constant>
</setHeader>
Same with Java DSL:
.removeHeaders("CamelHttp*")
.setHeader("Content-type", constant("application/x-www-form-urlencoded"))

Spring AOP is being invoked unexpectedly

I have configured Spring AOP for 2 different packages in our application to log exceptions.
There are 2 different configurations for each package:
<aop:config>
<aop:aspect id="aspectLoggging" ref="abcExceptionAspect">
<aop:pointcut id="pointCut"
expression="execution(* com.abc.*.*(..))" />
<aop:before method="logBefore" pointcut-ref="pointCut" />
<aop:after-throwing method="logExceptionABC"
throwing="error" pointcut-ref="pointCut" />
<aop:after method="logAfter" pointcut-ref="pointCut" />
</aop:aspect>
</aop:config>
<aop:config>
<aop:aspect id="aspectLoggging" ref="xyzlogAspect">
<aop:pointcut id="pointCut"
expression="execution(* com.xyz.*.*(..))" />
<aop:before method="logBefore" pointcut-ref="pointCut" />
<aop:after method="logAfter" pointcut-ref="pointCut" />
<aop:after-throwing method="logExceptionXYZ"
throwing="error" pointcut-ref="pointCut" />
</aop:aspect>
</aop:config>
In a service method call, there are calls to the methods of the classes belonging to each of these packages:
public void method()
{
method1(); -> package abc
method2(); -> package xyz
}
Some exception occurs in method2 which invokes logExceptionXYZ method where we are wrapping it in a generic exception, say ExceptionXYZ, and throwing it further.
But some how after this, the logExceptionABC method also gets invoked and throws a generic exception , say ExceptionABC.
I'm not able to understand as why logExceptionABC method is getting invoked?
Please let me know if someone knows about such an issue!
Regards,
Rahul
Same id is being assigned to both the aop:aspect tags. Similar is the case with the aop:pointcut tags as well.
Try with assigning unique IDs.

apache camel spring dsl check if body contains string

I am trying to check :
<simple>${body} contains 'verification'</simple>
Body is the json:
{"verification": {"email": "bb#wp.pl", "code": "1234"}}
But this condition doesn't work. I've tried as well:
<simple>${body} contains 'verification'</simple>
<simple>${bodyAs(String)} contains 'verification'</simple>
<simple>${body.verification} != null</simple>
Could you please suggest me something?
I guess the body is maybe not a String, then try with
<simple>${bodyAs(String)} contains 'verification'</simple>
And btw what version of Camel do you use?
Actually this case:
<simple>${bodyAs(String)} contains 'verification'</simple>
didn't work cause:
In Camel the message body can be of any types. Some types are safely readable multiple times, and therefore do not 'suffer' from becoming 'empty'.
It fixes by Stream caching

Mule - Dynamic file inbound endpoint error

My ESB flow needs to get files from a dynamic folder. This folder name changes based on month and year. Hence, I configured my inbound-endpoint as shown below but I am getting below error. I really appreciate any help on this.
Flow:
<flow name="DataMapperTestFlow" doc:name="DataMapperTestFlow">
<file:inbound-endpoint path="C:\#[new Date().format('yyyy\\MMMM')]" moveToDirectory="C:\#[new Date().format('yyyy\\MMMM')]\backup" pollingFrequency="10000" responseTimeout="10000" doc:name="File">
<file:filename-regex-filter pattern=".*.xls" caseSensitive="true"/>
</file:inbound-endpoint>
<custom-transformer class="ExcelToJava" doc:name="Java"/>
<jdbc-ee:outbound-endpoint exchange-pattern="one-way" queryKey="insertTestHeaders" connector-ref="NewDatabase" doc:name="InsertHeaders"/>
<set-payload value="#[payload.excelData.excelRows]" doc:name="Set Payload"/>
<jdbc-ee:outbound-endpoint exchange-pattern="one-way" queryKey="insertTestRows" connector-ref="NewDatabase" doc:name="InsertRows"/>
</flow>
Error:
org.mule.api.endpoint.MalformedEndpointException: The endpoint
"file:///C:/#[new Date().format('yyyy/MMMM')]" is malformed and cannot
be parsed. If this is the name of a global endpoint, check the name
is correct, that the endpoint exists, and that you are using the
correct configuration (eg the "ref" attribute). Note that names on
inbound and outbound endpoints cannot be used to send or receive
messages; use a named global endpoint instead.. Only Outbound
endpoints can be dynamic
"Only Outbound endpoints can be dynamic" quite says it all. You can have a look at the Mule Requester Module if it suits your needs, or try creating endpoints/flows programmatically with a scheduler and Java/Groovy/etc code.

Resources