Mule - Using Salesforce Connector with a Spring Component - spring

I'm using mule standalone 3.4. I am trying to create a flow using the Salesforce connector to perform a query operation and then pass the payload to a spring component. The result is the component doesn't get called.
<flow name="sfcdContact" doc:name="sfcdContact">
<quartz:inbound-endpoint repeatInterval="2000"
startDelay="3000"
jobName="sfcdContact">
<quartz:event-generator-job/>
</quartz:inbound-endpoint>
<sfdc:query config-ref="Salesforce"
query="${salesforce.query.contact}"
doc:name="sfcdContactQuery"/>
<component>
<spring-object bean="salesForceConsumer"/>
</component>
<catch-exception-strategy doc:name="Catch Exception Strategy">
<flow-ref name="ErrorHandling"/>
</catch-exception-strategy>
</flow>
If I remove the sfdc portion from the flow, the spring component is successfully invoked. If I remove the component portion from the flow and replace it with:
<logger message="\#\#\# query operation payload \#[payload]" level="INFO" doc:name="Logger"/>
The results are successfully entered into the log. So it seems the pieces work correctly individually.
I have the logs set to debug, and no errors are reported.
Here's the Java code:
public class SalesForceConsumer {
public Object consume(#Payload Object payload) throws Exception {
System.out.println("SalesForceConsumer::consume called");
return payload;
}
}
I also tried modifying the signature to:
public Object consume(#Payload HashMap<String,Object> payload)
Which is what the doc indicates is returned from the connector.
Is there any reason why the Salesforce connector can't be combined with a bean, or do I have it configured incorrectly? Thank-you.

I ran your code on Mule EE 3.4 and it worked just fine.
The console output:
INFO 2015-03-26 18:37:51,903 org.mule.api.processor.LoggerMessageProcessor: \#\#\# query operation payload \[{FirstName=Test, Id=null, type=Contact}]
SalesForceConsumer::consume called
The flow:
<spring:beans>
<spring:bean id="salesForceConsumer" name="salesForceConsumer" class="com.acme.util.SalesForceConsumer"/>
</spring:beans>
<sfdc:config name="Salesforce" username="XXXX" password="XXXX" securityToken="XXXX" url="https://login.salesforce.com/services/Soap/u/28.0" doc:name="Salesforce">
<sfdc:connection-pooling-profile initialisationPolicy="INITIALISE_ONE" exhaustedAction="WHEN_EXHAUSTED_GROW"/>
</sfdc:config>
<flow name="sfcdContact" doc:name="sfcdContact">
<quartz:inbound-endpoint repeatInterval="2000" startDelay="3000" jobName="sfcdContact">
<quartz:event-generator-job/>
</quartz:inbound-endpoint>
<sfdc:query config-ref="Salesforce" query="select FirstName from Contact" doc:name="sfcdContactQuery"/>
<logger message="\#\#\# query operation payload \#[payload]" level="INFO" doc:name="Logger"/>
<component>
<spring-object bean="salesForceConsumer"/>
</component>
</flow>

Related

Setting up WS-Security in MULE without properties file (WSS4JInInterceptor with signaturePropRefId)

I'm tryring to set up WS-Security in a CXF Proxy MULE Project. I currently have it working with a properties file, but I would like to take some info out of the properties file and insert it in the DataBase so it can be secured there but I can't find a way to make it work.
The relevant data in my project now looks like this:
CXF Proxy in flow:
<cxf:proxy-service doc:name="CXF Server" wsdlLocation="${wss.http.protocol}://${wss.http.host}:${wss.http.port}${wss.http.base_path}?${wss.http.wsdl_file}" payload="envelope" bindingId="${wss.http.binding_id}" namespace="${wss.http.namespace}" service="${wss.http.service}" >
<cxf:inInterceptors>
<spring:bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<spring:bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<spring:constructor-arg>
<spring:map>
<spring:entry key="action" value="Signature" />
<spring:entry key="signaturePropFile" value="ws.properties" />
</spring:map>
</spring:constructor-arg>
</spring:bean>
</cxf:inInterceptors>
</cxf:proxy-service>
ws.properties file:
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=JKS
org.apache.ws.security.crypto.merlin.file=myTrustStore.jks
org.apache.ws.security.crypto.merlin.keystore.password=myTrustStorePass
I'd need to take those file and keystore.password parameters out of the files of the project and set them in the DataBase in order to be injected.
I have vainly (as labels like util:properties are throwing a 'The prefix "util" for element "util:properties" is not bound' error) tried an approach similar to the one shown here:
http://cxf.547215.n5.nabble.com/WS-Security-Properties-Reference-td5505704.html
I've also tried to set the properties file this way in order to get the relevant data from the BD, but this data is not getting injected:
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=JKS
org.apache.ws.security.crypto.merlin.file=${wss.trustKeystore.file}
org.apache.ws.security.crypto.merlin.keystore.password=${wss.trustKeystore.password}
Am I doing anything wrong?
Can this be solved in any of the ways exposed (or any other)? If so, how?
Thanks.
EDIT due to a new scenario for this problem:
When I load the configuration for the interceptor from a properties file everything works fine, but I need to inject those configuration properties from DB, so I decided to configure it by using a java.util.properties object in the XML file in order to inject the values later. As a previous step to stablishing the injections, this is the code I have:
<mule xmlns:mulexml="http://www.mulesoft.org/schema/mule/xml"
xmlns:tls="http://www.mulesoft.org/schema/mule/tls"
xmlns:http="http://www.mulesoft.org/schema/mule/http"
xmlns:cxf="http://www.mulesoft.org/schema/mule/cxf"
xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.mulesoft.org/schema/mule/xml http://www.mulesoft.org/schema/mule/xml/current/mule-xml.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core
http://www.mulesoft.org/schema/mule/core/current/mule.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/cxf
http://www.mulesoft.org/schema/mule/cxf/current/mule-cxf.xsd
http://www.mulesoft.org/schema/mule/tls
http://www.mulesoft.org/schema/mule/tls/current/mule-tls.xsd">
<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="5081" doc:name="HTTP Listener Configuration"/>
<http:request-config name="HTTP_Request_Configuration" host="${conf.prop.host}" port="${conf.prop.port}" doc:name="HTTP Request Configuration" connectionIdleTimeout="60000" responseTimeout="60000"/>
<spring:beans>
<spring:bean id="WrongResultException" name="WrongResultException" class="transform.WrongResultException"/>
<spring:bean name="wsCryptoProperties" class="java.util.Properties">
<spring:constructor-arg>
<spring:map>
<spring:entry key="org.apache.ws.security.crypto.provider" value="org.apache.ws.security.components.crypto.Merlin"/>
<spring:entry key="org.apache.ws.security.crypto.merlin.keystore.type" value="JKS"/>
<spring:entry key="org.apache.ws.security.crypto.merlin.keystore.password" value="my_truststore_password"/>
<spring:entry key="org.apache.ws.security.crypto.merlin.file" value="my_truststore.jks"/>
</spring:map>
</spring:constructor-arg>
</spring:bean>
</spring:beans>
<flow name="HttpsCall">
<http:listener config-ref="https-listener-configured-in-domain-app" path="/my_path/my_service" doc:name="HTTPS"/>
<logger message="HTTPS call" level="INFO" doc:name="Logger HTTPS"/>
<flow-ref name="HttpCall" doc:name="HttpCall"/>
</flow>
<flow name="HttpCall">
<http:listener config-ref="http-listener-configured-in-domain-app" path="/my_path/my_service" doc:name="HTTP"/>
<cxf:proxy-service doc:name="CXF Server" wsdlLocation="${service.protocol}://${service.host}:${service.port}${service.base_path}?${service.wsdl_file}" payload="envelope" bindingId="${service.binding_id}" namespace="${service.namespace}" service="${service.service}" >
<cxf:inInterceptors>
<spring:bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<spring:bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<spring:constructor-arg>
<spring:map>
<spring:entry key="action" value="Signature" />
<!-- This is how the Crypto object is configured when using a properties file
<spring:entry key="signaturePropFile" value="security_conf_file.properties" />-->
<spring:entry key="signaturePropRefId" value="wsCryptoProperties"/>
</spring:map>
</spring:constructor-arg>
</spring:bean>
</cxf:inInterceptors>
</cxf:proxy-service>
<message-properties-transformer doc:name="Message Properties">
<add-message-property key="SOAPAction" value="#[message.inboundProperties.SOAPAction]"/>
</message-properties-transformer>
<cxf:proxy-client payload="envelope" doc:name="CXF Client" />
<http:request config-ref="HTTP_Request_Configuration" path="${service.base_path}" method="POST" doc:name="HTTP" />
<exception-strategy ref="mule-serviceCatch_Exception_Strategy" doc:name="Reference Exception Strategy"/>
</flow>
<catch-exception-strategy name="mule-serviceCatch_Exception_Strategy">
<logger message="Exception: #[message]" level="INFO" doc:name="Logger"/>
<transformer ref="WrongResultException" doc:name="Transformer Reference"/>
<mulexml:object-to-xml-transformer doc:name="Object to XML"/>
</catch-exception-strategy>
The fact is that everything compiles properly even when configuring the properties via java.util.Properties but, when calling to the service, an error is thrown saying that the properties were not loaded correctly:
WARN 2017-05-03 12:08:27,448 [[mule_domain_app].http-listener-configured-in-domain-app.worker.01] org.apache.ws.security.handler.WSHandler: The Crypto reference wsCryptoProperties specified by signaturePropRefId could not be loaded
WARN 2017-05-03 12:08:27,467 [[mule_domain_app].http-listener-configured-in-domain-app.worker.01] org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor:
org.apache.ws.security.WSSecurityException: General security error (WSSecurityEngine: No crypto property file supplied to verify signature)
at
org.apache.ws.security.message.token.X509Security.getX509Certificate(X509Security.java:100) ~[wss4j-1.6.18.jar:1.6.18]
at
org.apache.ws.security.message.token.SecurityTokenReference.getKeyIdentifier(SecurityTokenReference.java:491) ~[wss4j-1.6.18.jar:1.6.18] ...
And so on...
Can anybody throw some light over this issue? I'm completely stuck.
maybe you can provide this two parameters when you are starting your mule runtime.
./mule -M-Dorg.apache.ws.security.crypto.merlin.file=myTrustStore.jks -M-Dorg.apache.ws.security.crypto.merlin.keystore.password=myTrustStorePass
inside your mule configuration file, you should be able to access the values with: ${org.apache.ws.security.crypto.merlin.file} and ${org.apache.ws.security.crypto.merlin.keystore.password}
Not pretty sure if this would be a valid solution in your use case but maybe it could give you new ideas...
Let's see if this will solve the problem... I could replicate the case of getting values from a database and setup a connector. I made it slightly different but I guess that the concept is the only important matter.
In my case, I get properties from a derby in memory database and then I use this props for setting up an http:listener-config
First, I added a springBean to hold my properties:
<spring:beans>
<spring:bean id="propertiesBean" name="propertiesBean" class="com.mmartinez.test.DerbyLoadProperties" />
</spring:beans>
Inside the DerbyLoadProperties class, is necessary to implements InitializingBean and FactoryBean. The factoryBean will allow you to return the Properties object containing your properties, in this case coming from the database.
public class DerbyLoadProperties implements InitializingBean, FactoryBean {
private Properties prop = new Properties();
#Override
public void afterPropertiesSet() throws Exception {
initializeDatabaseAndExtractProperties();
//Inside this method I initialize the in-memory-db and also add the host and port properties from DB
//prop.put("http.hostmario", host);
//prop.put("http.portmario", port);
}
#Override
public Class getObjectType() {
return Properties.class;
}
#Override
public Object getObject() throws Exception {
return prop;
}
#Override
public boolean isSingleton() {
return false;
}
Now I can use my propertiesBean as a property-placeholder
<context:property-placeholder properties-ref="propertiesBean" />
In the last step, I will setup my http:listener-config, in your case the cxf:proxy-service....
<http:listener-config port="${http.portmario}" host="${http.hostmario}" name="testListener" doc:name="HTTP Listener Configuration" />
Is working fine for me.
Solved!
This line was missing beetween the entries of the map passed in the WSS4JInInterceptor constructor:
<spring:entry key="wsCryptoProperties" value-ref="wsCryptoProperties"/>
Doing this, an injection in the values of the props of the java.util.Properties object works as a charm.
Hope this helps anybody in the future!

Mule Exception Strategy Magento Inventory Input

I have a Mule flow which updates Magento Invtory through SOAP API. Everything runs great until I try to update an item which is not in the Magento Database. I then get an exception.
ERROR 2016-06-17 12:31:06,523 [[bwgs-to-magento].bwgs-to-magentoFlow.stage1.02] org.mule.retry.notifiers.ConnectNotifier: Failed to connect/reconnect: Work Descriptor. Root Exception was: Product not exists.. Type: class org.apache.axis.AxisFault
My exception strategy is this:
<choice-exception-strategy doc:name="Choice Exception Strategy">
<catch-exception-strategy when="#[exception.causedExactlyBy(org.mule.api.MessagingException)]" doc:name="Catch Exception Strategy">
<logger message="error" level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
</choice-exception-strategy>
My desired result is when an exception occurs, log it, but keep processing the flow.
Edit:
I have also tried the following exception strategy:
<choice-exception-strategy doc:name="Choice Exception Strategy">
<catch-exception-strategy when="#[exception.causeMatches(org.mule.api.*)]" enableNotifications="true" doc:name="Catch Exception Strategy">
<logger message="#[exception.cause.message]" level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
</choice-exception-strategy>
Here is the error syntax:
ERROR 2016-06-20 10:47:03,080 [[bwgs-to-magento].bwgs-to-magentoFlow.stage1.02] org.mule.exception.DefaultMessagingExceptionStrategy:
Message : Failed to invoke updateInventoryStockItem. Message payload is of type: String[]
Type : org.mule.api.MessagingException
Code : MULE_ERROR--2
Payload : [Ljava.lang.String;#191acd5
JavaDoc : http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/MessagingException.html
Exception stack is:
1. Product not exists. (org.apache.axis.AxisFault)
org.apache.axis.message.SOAPFaultBuilder:222 (null)
2. Product not exists. (org.mule.module.magento.api.MagentoException)
org.mule.module.magento.api.MagentoClientAdaptor:83 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/module/magento/api/MagentoException.html)
3. Failed to invoke updateInventoryStockItem. Message payload is of type: String[] (org.mule.api.MessagingException)
org.mule.devkit.processor.DevkitBasedMessageProcessor:133 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/MessagingException.html)
The best way to handle this scenario is your flow design. Put the Magento operation and the exception strategy in their own private flow and reference it from another flow. This way the exception will be caught and handled in the private flow and processing will return to the main flow where you can continue doing anything you want. For example:
<flow name="main-flow">
<flow-ref name="magento-flow" />
<logger level="INFO" message="This will continue processing" />
</flow>
<flow name="magento-flow">
<magento ... />
<choice-exception-strategy doc:name="Choice Exception Strategy">
<catch-exception-strategy when="#[exception.causeMatches(org.mule.api.*)]" enableNotifications="true" doc:name="Catch Exception Strategy">
<logger message="#[exception.cause.message]" level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
</choice-exception-strategy>
</flow>
In the MagnetoFlow make the flow end at DB level with flowRef and rest of the logic will continue in the next flow.If suppose exception happens it will caught in exception strategy. Here you log the exception and keep continue with the flow Ref of pendingLogic_MagnetoFlow. Check in choice whether the payload is available to continue( because here flow if flow continue from exception payload mightn't present), if so use the sessionVars where you have stored in session variable to continue with other logics.
<flow name="magnetoFlow">
<set-session-variable variableName="originalPayload" value="#[payload]" doc:name="Session Variable"/>
---DB here----
<flow-ref name="pendingLogicFrom_MagnetoFlow" doc:name="Flow Reference"/>
<catch-exception-strategy doc:name="Catch Exception Strategy" when="#[exception.causeMatches(org.mule.api.*)]">
<logger message="#[exception.cause.message]" level="INFO" doc:name="Logger"/>
<flow-ref name="pendingLogicFrom_MagnetoFlow" doc:name="pendingLogicFrom_MagnetoFlow"/>
</catch-exception-strategy>
</flow>
<flow name="pendingLogicFrom_MagnetoFlow">
<choice doc:name="Choice">
<when expression="#[check the payload is empty or not here ]">
<set-payload value="#[seesionVars.originalPayload]" doc:name="Set Payload"/>
</when>
<otherwise>
<logger level="INFO" doc:name="Logger"/>
</otherwise>
</choice>
<logger level="INFO" doc:name="Logger"/>
---other normal logic here ---
</flow>
Check this out.

Apache Camel dataFormat

Im using Camel to handle requests from a webservice and route those request to somewhere else (i will send them to RabbitMQ, but this is not relevant for my question).
Im using the standard Dataformat in camel-cxf endpoint which is POJO, but when i receive the packet in the camel route, im getting something that im not expecting.
Let me show you what i have right now, and i hope someone can point me in the right direction :)
Im using SOAPUI to send the request to the webservice:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:es:tf:mm:types">
<soapenv:Header/>
<soapenv:Body>
<urn:PromoEvent>
<urn:id>601234567</urn:id>
<urn:text>qwerty</urn:text>
<urn:date>01012001</urn:date>
</urn:PromoEvent>
</soapenv:Body>
</soapenv:Envelope>
Now, I have the following cxf endpoint bean definition in my camel-context.xml file, which by default, uses the POJO dataformat:
<cxf:cxfEndpoint id="Promo"
address="/Promo"
serviceClass="es.tf.mm.mmPortType"/>
And finally, i defined a camel route where im printing some logs and following you can see the results:
<route id="fromMySOAPws" autoStartup="true">
<from uri="cxf:bean:Promo"/>
<log message="Body: ${body}"/>
<log message="Body in: ${in.body}"/>
<log message="Body 0: ${in.body[0]}"/>
<log message="Body 1: ${in.body[1}"/>
<log message="Body 2: ${in.body[2]}"/>
<log message="Body 3: ${in.body[3]}"/>
<transform>
<simple>${in.body[0]}</simple>
</transform>
<unmarshal ref="jaxbWsDf"/>
<process ref="PromoProcessRequest"/>
<to uri="rabbitmq://rabbitmqhostname:5672/exchange_name?connectionFactory=#customConnectionFactory&autoDelete=false"/>
<bean ref="PromoResponse" method="generateResponse(0,"event published in rabbitmq")"/>
</route>
Here you can see the PromoProcessRequest Java class:
public class PromoProcessRequest implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
EventPromoType request = (EventPromoType)exchange.getIn().getBody();
Map<String, Object> eventFields = new LinkedHashMap<String, Object>();
eventFields.put("id", request.getId());
eventFields.put("text", request.getText());
eventFields.put("date", request.getDate());
exchange.getOut().setBody(eventFields);
}
}
Results:
Body: qwerty
Body in: qwerty
Body 0: javax.xml.ws.Holder#6ecf43c8
Body 1: qwerty
Body 2: 1012001
Body 3:
Thank you all in advance :)
#EDIT:
As Souciance correctly asked, what is unexpected for me, is to have just one of the fields (text:'qwerty') as the whole {body} of the request.
Since im using the standard POJO dataFormat, i need to call a process before Camel sends the message to rabbit and create a JSON with all the fields.
Im updating the code to show you the whole Camel route and also to include the process method which is where im having the issues, since im trying to cast the body of the request.
Hope this clarifies everything a little bit, but ofc, feel free to ask for more details if needed.
#EDIT2:
As fiw asked, here is the jaxbWsDf definition which is declared inside the camelContext tag:
<dataFormats>
<jaxb id="jaxbWsDf" prettyPrint="true" contextPath="es.tf.mm.types"/>
</dataFormats>
Also i would like to replicate here out my answer to the fiw second comment. When i compile the wsdl, in the auto-generated Java class, i cant see the #XmlRootElement and i think this is because the wsdl schema is declared in a external .xsd file. Am i right? Any other idea of why that XmlRootElement does not appear after compiling my webservice?
Thanks again!

Configuring JMS connectionfactory in mule

Could anyone suggest me how to configure connectionfactory in mule using connectionFactory-ref
I am trying to configure connectionfactory in mule using connectionFactory-ref[this is the url I am following ::: http://www.mulesoft.org/documentation-3.2/display/32X/JMS+Transport+Reference].
In the above mentioned documentation - mentioned -
Configuring the ConnectionFactory
One of the most important attributes is connectionFactory-ref. This is a reference to the ConnectionFactory object which creates new connections for your JMS provider. The object must implement the interface javax.jms.ConnectionFactory.
ConnectionFactory
So to implement the above below is my mule configuraion xml
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:smtps="http://www.mulesoft.org/schema/mule/smtps"
xmlns:scripting="http://www.mulesoft.org/schema/mule/scripting" xmlns:https="http://www.mulesoft.org/schema/mule/https"
xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:jms="http://www.mulesoft.org/schema/mule/jms" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans" version="EE-3.5.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.mulesoft.org/schema/mule/smtps http://www.mulesoft.org/schema/mule/smtps/current/mule-smtps.xsd
http://www.mulesoft.org/schema/mule/https http://www.mulesoft.org/schema/mule/https/current/mule-https.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.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/jms http://www.mulesoft.org/schema/mule/jms/current/mule-jms.xsd
http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd">
<spring:bean name="connectionFactory" class="com.ers.connections.ConnectionFactoryImpl"/>
<jms:activemq-connector name="Active_MQForApex" connectionFactory-ref="connectionFactory" validateConnections="true" doc:name="Active MQ"/>
<flow name="apexwritequeueFlow1" doc:name="apexwritequeueFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="niviTest" doc:name="HTTP"/>
<logger message="Payload ::: #[payload]" level="INFO" doc:name="Logger"/>
<jms:outbound-endpoint queue="ANS.RecOps.Incoming" connector-ref="Active_MQForApex" doc:name="JMS"/>
</flow>
</mule>
Below java class
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import org.apache.activemq.ActiveMQConnectionFactory;
public class ConnectionFactoryImpl implements javax.jms.ConnectionFactory {
#Override
public Connection createConnection() throws JMSException {
// Create a ConnectionFactory
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("21233", "123", "ssl://xxxx.autonet-yyy.com:443");
return connectionFactory.createConnection();
}
#Override
public Connection createConnection(String arg0, String arg1)
throws JMSException {
// TODO Auto-generated method stub
return null;
}
}
However I am getting this error
. Root Exception was: Unsupported ConnectionFactory type: com.ers.connections.ConnectionFactoryImpl. Type: class java.lang.IllegalArgumentException
ERROR 2014-12-28 11:53:26,141 [main] org.mule.module.launcher.application.DefaultMuleApplication: null
java.lang.IllegalArgumentException: Unsupported ConnectionFactory type: com.ers.connections.ConnectionFactoryImpl
Thank you in advance.
Any suggestions most appreciated.
Thank you and regards
Nivi
If you don't have any really good reason, that you do not show in the post, to write your own ConenctionFactory implementation you should use the one provided by the JMS provider directly.
So you should use a bean definition like this
<spring:bean id="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
</spring:bean>
You are using the ActiveMQ connector and it is expecting a factory class of type org.apache.activemq.ActiveMQConnectionFactory. If you really need a custom factory, your ConnectionFactoryImpl class should extend the activemq factory:
import org.apache.activemq.ActiveMQConnectionFactory;
public class ConnectionFactoryImpl extends ActiveMQConnectionFactory {
// Override the methods you need
}
Then you can reference it in connectionFactory-ref attribute of the connector.
Your implementation probably does not provide any special feature, if this is the case please just use the default connector:
<jms:activemq-connector name="JmsConnector" specification="1.1" />
However if you have some special behaviour that you want to use, with the activemq connector, you just need a connection factory that implements org.apache.activemq.ActiveMQConnectionFactory, this is because these two lines. Then just use something like the following:
<spring:beans>
<spring:bean name="myActiveMqConnectionFactory"
class="org.apache.activemq.spring.MyActiveMQConnectionFactory"
p:brokerURL="vm://esb-amq-broker" <--- Just some example property />
</spring:beans>
<jms:activemq-connector name="myJmsConnector"
specification="1.1"
connectionFactory-ref="AmqConnectionFactory"
persistentDelivery="true" />
However please twink twice about the need of doing this, the original activemq connector probably provides almost anything you need with the exeption of connection caching. If that is what you need please consider using this.

Mule ESB: Setup JMS Endpoint for WMQ Queue

currently I am working with mule and need to write in WMQ Queue. But instead of using WMQ endpoint, I want to do it by using JMS Endpoint. Here is my configuration:
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:jms="http://www.mulesoft.org/schema/mule/jms" xmlns:jetty="http://www.mulesoft.org/schema/mule/jetty" xmlns:scripting="http://www.mulesoft.org/schema/mule/scripting" xmlns:vm="http://www.mulesoft.org/schema/mule/vm" xmlns:wmq="http://www.mulesoft.org/schema/mule/ee/wmq" xmlns:mulexml="http://www.mulesoft.org/schema/mule/xml" xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns:json="http://www.mulesoft.org/schema/mule/json" xmlns:data-mapper="http://www.mulesoft.org/schema/mule/ee/data-mapper" xmlns:ajax="http://www.mulesoft.org/schema/mule/ajax" xmlns:jersey="http://www.mulesoft.org/schema/mule/jersey" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans" version="EE-3.4.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.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/jersey http://www.mulesoft.org/schema/mule/jersey/current/mule-jersey.xsd
http://www.mulesoft.org/schema/mule/ajax http://www.mulesoft.org/schema/mule/ajax/current/mule-ajax.xsd
http://www.mulesoft.org/schema/mule/ee/data-mapper http://www.mulesoft.org/schema/mule/ee/data-mapper/current/mule-data-mapper.xsd
http://www.mulesoft.org/schema/mule/json http://www.mulesoft.org/schema/mule/json/current/mule-json.xsd
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd
http://www.mulesoft.org/schema/mule/xml http://www.mulesoft.org/schema/mule/xml/current/mule-xml.xsd
http://www.mulesoft.org/schema/mule/ee/wmq http://www.mulesoft.org/schema/mule/ee/wmq/current/mule-wmq-ee.xsd
http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/current/mule-vm.xsd
http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd
http://www.mulesoft.org/schema/mule/jetty http://www.mulesoft.org/schema/mule/jetty/current/mule-jetty.xsd
http://www.mulesoft.org/schema/mule/jms http://www.mulesoft.org/schema/mule/jms/current/mule-jms.xsd">
<wmq:connector name="WMQ" hostName="localhost" port="1414" queueManager="localmanager" validateConnections="true" doc:name="WMQ" ccsId="819"/>
<data-mapper:config name="map_to_xml" transformationGraphPath="map_to_xml.grf" doc:name="map_to_xml"/>
<data-mapper:config name="xml_to_json" transformationGraphPath="xml_to_json.grf" doc:name="xml_to_json"/>
<jms:connector name="jmsConnector"
connectionFactoryJndiName="jms/ConnectionFactory"
jndiInitialFactory="com.ibm.websphere.naming.WsnInitialContextFactory"
specification="1.1"
connectionFactory-ref="MQConnectionFactory">
<spring:property name="jmsSupport" ref="customJmsSupport"/>
</jms:connector>
<spring:beans>
<spring:bean id="customJmsSupport" class="CustomJms11Support">
<spring:constructor-arg ref="jmsConnector" />
</spring:bean>
<spring:bean name="MQConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<spring:property name="hostName" value="localhost"/>
<spring:property name="port" value="1414"/>
<spring:property name="queueManager" value="localmanager"/>
<spring:property name="transportType" value="1"/>
</spring:bean>
</spring:beans>
<flow name="RequestFlow" doc:name="RequestFlow">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8088" path="uebermittleAusweisdaten" doc:name="HTTP" contentType="text/html"/>
<expression-filter expression="#[message.payload !='/favicon.ico']" doc:name="Expression"/>
<jersey:resources doc:name="REST">
<component class="de.fraport.sources.RestClass"/>
</jersey:resources>
<set-variable variableName="id" value="#[message.id]" doc:name="Message ID"/>
<json:json-to-object-transformer returnClass="java.util.Map" doc:name="JSON to Object"/>
<data-mapper:transform config-ref="map_to_xml" doc:name="Map To XML">
<data-mapper:input-arguments>
<data-mapper:input-argument key="id">#[flowVars['id']]</data-mapper:input-argument>
</data-mapper:input-arguments>
</data-mapper:transform>
<flow-ref name="Subflow1" doc:name="Flow Reference"/>
<parse-template location="D:\Workspace\ajax_rest\src\main\app\www\index.html" doc:name="Parse Template"/>
</flow>
<sub-flow name="Subflow1" doc:name="Subflow1">
<mulexml:xslt-transformer encoding="ISO8859-1" maxIdleTransformers="2" maxActiveTransformers="5" xsl-file="D:\Workspace\ajax_rest\mobako.sender.xsl" doc:name="SOAP Envelope"/>
<mulexml:dom-to-xml-transformer outputEncoding="ISO8859-1" doc:name="DOM to XML"/>
<outbound-endpoint doc:name="JMS" address="jms://LSMH.ZKSEAP.SERVICEBUS" connector-ref="jmsConnector" encoding="ISO8859-1"/>
<!-- <wmq:outbound-endpoint queue="LSMH.ZKSEAP.SERVICEBUS" encoding="ISO8859-1" connector-ref="WMQ" doc:name="ZKSEAP IN"/> -->
<set-property propertyName="MULE_CORRELATION_ID" value="#[function:dateStamp:yyyy-MM-dd HH:mm:ss]" doc:name="Set Correlation ID"/>
<request-reply>
<vm:outbound-endpoint path="sender">
<message-properties-transformer scope="outbound">
<delete-message-property key="MULE_REPLYTO"/>
</message-properties-transformer>
</vm:outbound-endpoint>
<vm:inbound-endpoint path="response">
<logger level="INFO" message="#[string:XXXXXX 1: #[message.inboundProperties]"/>
</vm:inbound-endpoint>
</request-reply>
</sub-flow>
<flow name="ResponseFlow" doc:name="ResponseFlow">
<inbound-endpoint address="jms://ZKSEAP.LSMH.SERVICEBUS" connector-ref="jmsConnector" doc:name="ZKSEAP OUT"/>
<!-- <wmq:inbound-endpoint queue="ZKSEAP.LSMH.SERVICEBUS" connector-ref="WMQ" doc:name="ZKSEAP OUT" encoding="UTF-8"/> -->
<set-property propertyName="MULE_CORRELATION_ID" value="#[function:dateStamp:yyyy-MM-dd HH:mm:ss]" doc:name="Set Correlation ID"/>
<data-mapper:transform doc:name="XML To JSON" config-ref="xml_to_json"/>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<vm:outbound-endpoint path="response" doc:name="Response Outbound" exchange-pattern="one-way"/>
</flow>
</mule>
I have successfully read message from WMQ Queue by using JMS endpoint. However, when I tried to write some message in WMQ Queue by using JMS Endpoint, I got following error from my server:
2014-07-22 10:11:27,064 [Axis2 Task] ERROR WMQMsg - Expected MQ
message format ' MQSTR ', but received 'MQHRF2 ' 2014-07-22
10:11:27,064 [Axis2 Task] WARN QMgrConnection - Moving msg into dead
letter queue after 1 try/tries:
414D51206C6F63616C6D616E616765721A0CCE5320003C0 2 [Fatal Error] :1:1:
Content ist nicht zulõssig in Prolog. ERROR: 'Content ist nicht
zulõssig in Prolog.' 2014-07-22 10:11:27,064 [Axis2 Task] WARN ESBMsg
- Error prettifying ESBMsg for log printing
I know that this error occured because I tried to write into Non-JMS Queue. Also I know that I have to solve it by setting "?targetClient=1". However, when I tried to add the targetClient attribute into my Queue URL, I still got the error (it seems that the attribute was recognized as URL too by WMQ).
Then, from my research, I found out that I can not directly set the "?targetClient" in the url. Instead of that, I need to create a Java Class to set the "?targetClient". To create those class, I follow some instructions from following URL
Create Custom JMSSupport Class
But unfortunatelly, it also did not work for me. Anyone has an idea about how can I solve it? Thanks.
NB: In Apache Camel, I can simply solve it by adding:
<setHeader headerName="CamelJmsDestinationName">
<constant>queue:///LSMH.ZKSEAP.SERVICEBUS?targetClient=1</constant>
</setHeader>
Is there something similar in Mule ESB?
Just solved the problem:
It is right that we need to create a java class to set the targetClient. And to do so, we can follow the link that I gave above. However, we will need to change the code a bit.
Here is the right code:
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Session;
import org.mule.api.endpoint.ImmutableEndpoint;
import org.mule.transport.jms.Jms11Support;
import org.mule.transport.jms.JmsConnector;
import com.ibm.mq.jms.JMSC;
import com.ibm.mq.jms.MQQueue;
/**
* Implements WebSphere MQ specific JMS support for Mule. The class
* overrides the createDestination method to intercept JMS Queue object
* creation and sets the targetClient=1 property on created MQQueue
* objects. This is necessary to prevent non-JMS consumers from being
* choked by RFH2 headers.
*/
public class CustomJms11Support extends Jms11Support {
public CustomJms11Support(JmsConnector connector) {
super(connector);
}
#Override
public Destination createDestination(Session session, String name, boolean
topic, ImmutableEndpoint ie) throws JMSException {
Destination destination = super.createDestination(session, name, topic, ie);
if (destination instanceof MQQueue){
((MQQueue) destination).setTargetClient(JMSC.MQJMS_CLIENT_NONJMS_MQ);
}
return destination;
}
}
And then, we will need to set a property called "JMS_IBM_Character_Set" (If not we will get "Expected MQ message characterSet '819', but received '1208'" error) before send the request to JMS endpoint. Here is how I configure it:
<set-property propertyName="JMS_IBM_Character_Set" value="ISO8859_1" doc:name="Property"/>
And just for your information, by changing the WMQ endpoint to JMS endpoint, for sure it improve the performance.
Hopefully it would be useful :D

Resources