0
votes

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

2
Can you show how you are trying to access these propertiesSatheesh Kumar
The properties should be loaded at init. And then accessible using ${} placeholder. Can you show how you are trying to access them?Ryan Carter
Thanks @Satheesh and @Ryan!! I have updated the question. Please help!!Zulfiqar Ali

2 Answers

1
votes

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.

0
votes

Let your db contains following properties values with key/value pair as below :-
enter image description here

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