Read properties from database and use it instead of mule-app.properties - mule

I have been able to read the properties from a table in the database as it was described here Reading mule config from database
Now, I am not able to apply these properties to the flow configs and also access them as out bound properties in the Java Processor classes through the MuleEventContext's message.
Update: below is my flow XML code
<flow name="push-data">
<poll doc:name="Push Poll">
<fixed-frequency-scheduler frequency="${push.data.poll.frequency}" timeUnit="MINUTES" />
<set-property propertyName="tempFilePath" value="${temp.csv.file.path}" doc:name="Property"/>
<component class="com.reports.processors.PushDataProcessor" doc:name="PushDataProcessor"/>
<logger message="worked!!!" level="INFO" doc:name="Logger"/>
<exception-strategy ref="push-report-data_Catch_Exception_Strategy" doc:name="Reference Exception Strategy"/>
</flow>
I am trying to set the properties "push.data.poll.frequency" and "temp.csv.file.path". Earlier, these properties existed in the "mule-app.properties" file.
So, My question is, How do I set the properties loaded from the database to the flow. Please keep in mind that I have already loaded the properties from the database as described in the link above. I just want to be able to set these properties to the flow rather than taking them from the mule-app.properties.
EDIT: To add some more information,
I am using a class with #Configuration annotation. The class as described in the link above, loads the properties from the database. Below is the source code.
#Configuration(name="databasePropertiesProvider")
#Component
public class DatabasePropertiesProvider {
#Autowired(required=true)
private MyService myService;
#Bean
public Properties getProperties() throws Exception {
Properties properties = new Properties();
// get properties from the database
Map<String,String> propertiesMap = myService.getMuleAppPropertiesFromDB();
if(null != propertiesMap && !CollectionUtils.isEmpty(propertiesMap))
properties.putAll(propertiesMap);
return properties;
}
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}}
But this class runs after the app is initialized. Previously, I had configured the PropertySourcesPlaceholderConfigurer in the xml config with the factory-bean as the DatabasePropertiesProvider class. But since DatabasePropertiesProvider has a dependency on MyService class, and the dependency was not getting resolved due to MyService bean not initializing in the container before the property config, I had to make some changes to DatabasePropertiesProvider(the version above) so that this runs after the app initialization.
But now, the problem is that I am unable to access those properties that are loaded from the database.
UPDATE 2: I found a solution. Apparently I was trying to autowire the #Service MyService in the databasePropertiesProvider class. The autowiring was failing with null due to which I made some more modifications to the databasePropertiesProvider class so that It runs after the app is initialized.
Now when I look at it, I realized that I dont need to connect to the database through all the service and repository layers. I moved the query execution code from the repository class to the databasePropertiesProvider class and now the properties are loaded during initialization time and the flows can get the properties without making any changes.
Thanks for all your help guys. Made me do a lot of thinking.
Regards,
Zulfiqar

I found a solution. Apparently I was trying to autowire the #Service MyService in the databasePropertiesProvider class. The autowiring was failing with null due to which I made some more modifications to the databasePropertiesProvider class so that It runs after the app is initialized.
Now when I look at it, I realized that I dont need to connect to the database through all the service and repository layers. I moved the query execution code from the repository class to the databasePropertiesProvider class and now the properties are loaded during initialization time and the flows can get the properties without making any changes.
The whole code looks like this
XML Config:-
<bean class="net.intigral.reports.provider.properties.DatabasePropertiesProvider" id="databasePropertiesProvider">
<property name="entityManager" ref="entityManager" />
</bean>
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="properties">
<bean factory-bean="databasePropertiesProvider" factory-method="getProperties" />
</property>
</bean>
Java Code:-
public class DatabasePropertiesProvider {
EntityManager entityManager;
public Properties getProperties() throws Exception {
Properties properties = new Properties();
// get properties from the database
Map<String,String> propertiesMap = getMuleAppPropertiesFromDB();
if(null != propertiesMap && !CollectionUtilsIntg.isEmpty(propertiesMap))
properties.putAll(propertiesMap);
return properties;
}
public EntityManager getEntityManager() {
return entityManager;
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
#SuppressWarnings("unchecked")
private Map<String,String> getMuleAppPropertiesFromDB() {
Map<String,String> collect = null;
String query = "select key, value from MuleAppProps muleAppProps";
List<Object[]> results = entityManager.createQuery(query).getResultList();
if (CollectionUtilsIntg.isNotEmpty(results)) {
collect = results.stream().collect(Collectors.toMap(o -> (String)o[0], o -> (String)o[1]));
}
return collect;
}}
Now, I am able to load the properties the same way I used to load from mule-app.properties in the FLOWs.

Let your db contains following properties values with key/value pair as below :-
A simple example like below you can refer to read values from Database:-
<spring:beans>
<spring:bean id="dataSource" name="myCon" class="org.enhydra.jdbc.standard.StandardDataSource">
<spring:property name="url" value="jdbc:sqlserver://YourIpAddress\\SQLEXPRESS:1433;databaseName=YourDB;user=sa;password=yourDBPassword" />
<spring:property name="driverName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
</spring:bean>
<!-- Required to connect to datasource -->
<spring:bean name="PropertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<spring:property name="properties" ref="CommonsConfigurationFactoryBean" />
</spring:bean>
<spring:bean name="CommonsConfigurationFactoryBean"
class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean">
<spring:constructor-arg ref="DatabaseConfiguration" />
</spring:bean>
<spring:bean name="DatabaseConfiguration" class="org.apache.commons.configuration.DatabaseConfiguration">
<spring:constructor-arg type="javax.sql.DataSource" ref="dataSource" />
<spring:constructor-arg index="1" value="YourTableName" />
<spring:constructor-arg index="2" value="Key" />
<spring:constructor-arg index="3" value="Value" />
</spring:bean>
</spring:beans>
<db:generic-config name="Database_Configuration" dataSource-ref="dataSource" doc:name="Generic Database Configuration" />
<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration" />
<flow name="firstflow" processingStrategy="synchronous">
<http:listener config-ref="HTTP_Listener_Configuration" path="/test" doc:name="HTTP" />
<set-payload value="File name ${file.name} File path ${file.path}" doc:name="Set Payload" />
</flow>
You need to add commons-configuration.jar, spring.jar and spring-modules-jakarta-commons.jar in your classpath
If you want to access properties values in Java class you can inject it using Spring property in init-method of Spring bean.
refer:- http://www.codeproject.com/Articles/28893/Loading-Application-Properties-from-a-Database

Related

Mule XML Streaming - (Mule xmltoxmltransformation)

Trying to use the Mule XML streaming feature as have to process very large xml files. Followed the documentation, the document does not have concrete examples.
When I inspected the payload I get the XMLUtils class and not the XMLStreamReader class as stated in the documentation.
The flow is as follows have a file connector which passes payload to a custom transformer, the transformer passes the data to a spring bean which is going to have event based processing.
In the spring bean. At run time the spring bean gets the XMLUtils class and not the XMLStreamReader class.
Mule - Config:
<spring:beans>
<spring:bean id="OracleCDMMapper" class="oraclecdmstream.OracleCDMMapper">
</spring:bean>
<spring:bean id = "OraclePaySlip" class="com.nect.transform.OracleCDMPaySlip" ></spring:bean>
</spring:beans>
<flow name="mulefileconnectorexampleFlow1" >
<file:inbound-endpoint path="C:/c-OracleCloud/src/main/resources" pollingFrequency="600000" moveToDirectory="C:/c-OracleCloud/src/main/resources/back" doc:name="File Input" >
<!-- <file:filename-regex-filter pattern="(^*.xml$)" caseSensitive="false"/>
--> <file:filename-wildcard-filter pattern="*.xml"></file:filename-wildcard-filter>
</file:inbound-endpoint>
<logger message="Transferring file : #[message.inboundProperties['originalFilename']]" level="INFO" doc:name="Logger"/>
<logger message ="Logger 1 " level="INFO" doc:name ="Logger1" />
<!-- Call the XMLSTREAMER -->
**<custom-transformer name="XmlToXSR" class="org.mule.module.xml.transformer.XmlToXMLStreamReader" doc:name="XMLTOORACLE">**
</custom-transformer>
<component doc:name="Java">
<spring-object bean="OracleCDMMapper"/>
</component>
-->
<logger message ="I am Complete " level="INFO" doc:name ="LoggerMurali" />
</flow>
</mule>
Here is the Javacode:
Spring Bean
public class OracleCDMMapper implements Callable {
private final Logger logger = LoggerFactory.getLogger(OracleCDMMapper.class);
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
// TODO Auto-generated method stub
MuleMessage muleMessage = eventContext.getMessage();
logger.info("In the Spring Component");
logger.info(muleMessage.getPayload().getClass().toString());
**javax.xml.stream.XMLStreamReader xsr = (XMLStreamReader) muleMessage.getPayload(javax.xml.stream.XMLStreamReader.class);**
Any help will be much appreciated
I've verified and you are right, in the code the supposed returning class should be a DelegateXMLStreamReader class that implements XMLStreamReader, but the returned class is an anonymous inner class of XMLUtils that at runtime cannot be casted to any Stream like class. It seems to be a defect.
If you really need the control of the xml stream, you could use a custom java component:
<component class="com.foo.CustomJavaComponent" doc:name="Java"/>
.
public class CustomJavaComponent implements Callable{
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
MuleMessage muleMessage = eventContext.getMessage();
FileInputStream fis = (FileInputStream)muleMessage.getPayload();
//Do something with this stream
return "Hello world";
}
}
And get the input stream to do whatever you want.

Mule - Create a custom property for use in flow

I am trying to get the OS name available in my flow so I can adjust variable depending on the operating system running.
I am new to spring beans, but so far the below will call the set function ( I see it in the log) but I need to be able to access the osName from inside my flow.
java class:
public class CustomVariables {
public CustomVariables(){}
public String osName;
public String getOsName(){
System.out.println("got value: "+ osName);
return osName;
}
public void setOsName(String name){
osName = System.getProperty("os.name").toLowerCase();
System.out.println("set value: "+ osName); //this prints in console on startup
}
}
mule.xml:
<spring:beans>
<spring:bean class="netstockconnector.CustomVariables">
<spring:property name="osName" value="{os.name}"> </spring:property>
</spring:bean>
</spring:beans>
in flow:
<logger message="${osName}" level="INFO" doc:name="Logger"></logger>
This just prints to the console "${osName}" rather than "mac os x" for instance.
Any ideas?
There is a much simpler solution...
<logger message='#[System.getProperty("os.name")]' level="INFO" doc:name="Logger"></logger>
To trigger the Mule Expression Language, the expression to evaluate should be between #[expression to evaluate]. By default MEL imports a set of java classes which includes java.lang.System, hence the direct utilization in the expression.

jasypt property placeholder not working

I have this properties file:
secret.key = ENC(foobar)
region = ABC
Then in the config.xml:
<spring:beans>
<encryption:encryptor-config id="eConf" password-sys-property-name="MULE_ENCRYPTION_PASSWORD" algorithm="PBEWithMD5AndDES" password="" />
<encryption:string-encryptor id="stringEnc" config-bean="eConf" />
<encryption:encryptable-property-placeholder encryptor="stringEnc" location="${env}.properties" />
</spring:beans>
But the property placeholders don't work, for example:
<sqs:config secretKey="${secret.key}" region="${region}"></sqs-config>
Does anyone know why?
Encrypted password needs to be write within ENC() function and should be encrypted.
Let's consider in properties file where password value is Login#123... Now the encrypted value in properties file will be :-
password=ENC(B0u7D8wLwq/ugin31KNpP78gBcLP7VIN)
Step1 :- We can generate Key using following commands in Command prompt of \jasypt-1.9.2\bin directory :- encrypt input="Login#123" password=sqlpassword algorithm=PBEWithMD5AndDES
Step2 :- In runtime Environment we need to give (Right click->Run As->Run Configuration->Environment) :- Variable :- MULE_ENCRYPTION_PASSWORD and Value:-sqlpassword
In your Mule config, you need configure it as following :-
<spring:beans>
<spring:bean id="environmentVariablesConfiguration" class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
<spring:property name="algorithm" value="PBEWithMD5AndDES"/>
<spring:property name="passwordEnvName" value="MULE_ENCRYPTION_PASSWORD"/>
</spring:bean>
<!-- The will be the encryptor used for decrypting configuration values. -->
<spring:bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<spring:property name="config" ref="environmentVariablesConfiguration"/>
</spring:bean>
<!-- The EncryptablePropertyPlaceholderConfigurer will read the -->
<!-- .properties files and make their values accessible as ${var} -->
<!-- Our "configurationEncryptor" bean (which implements -->
<!-- org.jasypt.encryption.StringEncryptor) is set as a constructor arg. -->
<spring:bean id="propertyConfigurer" class="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer">
<spring:constructor-arg ref="configurationEncryptor"/>
<spring:property name="locations">
<spring:list>
<spring:value>conf/yourPropertyFile.properties</spring:value>
</spring:list>
</spring:property>
</spring:bean>
Then you can use encrypted values like :- ${password}
Reference :- http://blogs.mulesoft.org/encrypting-passwords-in-mule/
and http://pragmaticintegrator.wordpress.com/2014/03/09/using-encrypted-passwords-with-mule-esb/
and https://code.google.com/p/soi-toolkit/issues/detail?id=183
and http://soi-toolkit.googlecode.com/svn-history/r2022/wiki/UG_PropertyFile.wiki
I had similar issue, i did configure everything as explained in Activemq web site . In my case issue was PropertyPlaceholderConfigurer bean was loaded for to load other properties before the EncryptablePropertyPlaceholderConfigurer bean. So remove PropertyPlaceholderConfigurer bean's if any just add EncryptablePropertyPlaceholderConfigurer bean even for other non-encrypted properties as explained in Activemq then it works fine.

Accessing the MuleMessage in soap based web service

In a soap based web service i want to access the Mule message properties. Is there a way of doing this i know one way of using RequestContext.getEvent().getMessage() but this i guess is deprecated. An other way of accessing the MuleMessage properties in the web service. Can someone please provide any pointers on this.
Code Snippet
<flow name="MyWebService" doc:name="MyWebService">
<http:inbound-endpoint exchange-pattern="request-response" address="${WEB_SERVICE_PROTOCOL}://${WEB_SERVICE_HOST}:${WEB_SERVICE_PORT}/MyWebService?wsdl" tracking:enable-default-events="true">
<cxf:jaxws-service serviceClass="com.XXX.XXX.service.MyWebService" doc:name="SOAP"/>
</http:inbound-endpoint>
<component doc:name="My Web Service">
<spring-object bean="WebServiceImpl"/>
</component>
</flow>
Depending on what is your purpose for obtaining the message properties, one option is to use a cxf interceptor to access the message. See the following example.
adding the interceptor:
<cxf:jaxws-service serviceClass="org.example.HelloWorld">
<cxf:inInterceptors>
<spring:bean class="org.example.MyInterceptor"/>
</cxf:inInterceptors>
</cxf:jaxws-service>
interceptor class:
package org.example;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.mule.api.MuleEvent;
import org.mule.api.MuleMessage;
public class MyInterceptor extends AbstractSoapInterceptor {
public MyInterceptor() {
super(Phase.USER_PROTOCOL);
}
#Override
public void handleMessage(SoapMessage message) throws Fault {
MuleEvent muleEvent = (MuleEvent)message.getContextualProperty("mule.event");
MuleMessage muleMessage = muleEvent.getMessage();
System.out.println(muleMessage.toString());
}
}
You can achieve this by not implementing the service interface at all and deal with the SOAP requests as Mule messages (where properties are accessible) instead of dealing with deserialized objects in service classes.
Here is an example fragment, assuming you've generated the necessary classes and interfaces from the WSDL with wsdl2java:
<flow name="WebServiceFlow">
<http:inbound-endpoint exchange-pattern="request-response"
address="http://localhost:8080/services/some" />
<cxf:jaxws-service
serviceClass="com.amce.SomePortType" />
<choice>
<when
expression="#[cxf_operation.localPart == 'SomeOperation']">
<flow-ref name="HandleSomeOperation" />
</when>
If you have access to MuleMessage then you get the required properties by using the method
Set<String> getPropertyNames(PropertyScope scope);
available in MuleMessage class. To get the MuleMessage you would need access to MuleClient; have you got access to MuleClient? if yes, then use:
muleClient = muleContext.getClient();
MuleMessage result = muleClient.send(webaddress, "", props);
Is this what you are trying to acheive?

Reading mule config from database

Is it possible to read mule configuration file path (file endpoints), smtp host /user/password (smtp endpoints) from database.We finally want to provide a User Interface , where the user can edit the properties through the screen.The normal properties file approach (key/Value) pairs was used earlier but needs to change to read these properties from the database.Any help on this will be greatly appreciated.
Yes, you can use a custom properties provider.
Its configuration would look like this:
<spring:bean class="org.mule.DatabasePropertiesProvider" id="DatabasePropertiesProvider"/>
<spring:bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<spring:property name="properties">
<spring:bean factory-bean="DatabasePropertiesProvider" factory-method="getProperties" />
</spring:property>
</spring:bean>
And the code for DatabasePropertiesProvider is as simple as this:
public class DatabasePropertiesProvider {
public Properties getProperties() throws Exception {
Properties properties = new Properties();
// get properties from the database
return properties;
}
}