Announcement Announcement Module
Collapse
No announcement yet.
PropertyPlaceholderConfigurer Chicken-Egg Scenario Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • PropertyPlaceholderConfigurer Chicken-Egg Scenario

    Hi Folks,

    I have a chicken-egg scenario in a bean creation

    I am using a PropertyPlaceholderConfigurer which uses the CommonsConfigurationFactoryBean to combine a db property files from the file path and also the database. The problem arises when setting up the DatabaseConfiguration bean as it requires a datasource which uses placeholders from the db.properties, because the PPC is a bean post processor it gets kicked off first before place holders are resolved. This results in a exception of

    java.lang.ClassNotFoundException: ${datasource.driver}
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)

    So from the exception you can see thats it trying to load a class ${datasource.driver} which is the place holder

    Anyone ever had this type of problem.. A confused developer :-(

    E.g
    <!-- Decrypts the DB -->
    <bean id="propertyConfigurer" class="org.jasypt.spring.properties.EncryptablePro pertyPlaceholderConfigurer">
    <constructor-arg ref="configurationEncryptor" />
    <property name="properties" ref="CommonsConfigurationFactoryBean"/>
    <property name="ignoreUnresolvablePlaceholders" value="false"/>
    </bean>

    <bean name="CommonsConfigurationFactoryBean" class="org.springmodules.commons.configuration.Com monsConfigurationFactoryBean" >

    <property name="locations">
    <list>
    <value>db.properties</value>
    </list>
    </property>
    <property name="configurations">
    <list>
    <bean name="DatabaseConfiguration" class="org.apache.commons.configuration.DatabaseCo nfiguration">
    <constructor-arg index="0" ref="myDataSource"/>
    <constructor-arg index="1" value="CONFIG_TABLE"/>
    <constructor-arg index="2" value="CONFIG_KEY"/>
    <constructor-arg index="3" value="CONFIG_VALUE"/>
    </bean>
    </list>
    </property>
    </bean>


    <!-- Place holder referencing the db.properties -->
    <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${datasource.driver}"/>
    <property name="jdbcUrl" value="${datasource.url}"/>
    <property name="user" value="${datasource.usr}"/>
    <property name="password" value="${datasource.pwd}"/>
    </bean>


    Thanks
    Dan

  • #2
    Hi,

    Following are the reason why you are getting an error.

    Problem:

    1) First EncryptablePropertyPlaceholderConfigurer is called.It is not initialised until CommonsConfigurationFactoryBean is initialised.
    2)So now CommonsConfigurationFactoryBean is called.In that just loads the property files and simply loading the property file wont replace the dynamic properties used in the Datasource Configuration.Now when it is setting up DatabaseConfiguration as a property which has a reference to myDatasource it fails since the properties arent replaced dynamically.

    Note:PropertyPlaceHolder can only replace the properties dynamically in your spring context file.Here EncryptablePropertyPlaceholderConfigurer didnt get initialised because the it fails while injecting the dependencies(CommonsConfigurationFactoryBean).

    Solution
    1)Create a PropertPlaceHolder bean and place it propertyConfigurer bean i.e. before
    <bean id="propertyConfigurer" class="org.jasypt.spring.properties.EncryptablePro pertyPlaceholderConfigurer">
    In that PropertPlaceHolder pass your db.properties.

    By doing so this PropertPlaceHolder will be created before EncryptablePropertyPlaceholderConfigurer and will load the db.properties file.
    This will replace the dynamic properties in your datasource

    2)Remove the entry from CommonsConfigurationFactoryBean
    <property name="locations">
    <list>
    <value>db.properties</value>
    </list>
    </property>


    I Hope this solves your problem

    Kartik

    Comment


    • #3
      Hi Kartik,

      I tried what you described but to no avail, I have now created 2 EncryptablePropertyPlaceholderConfigurer one that loads the db properties and the second loads it from the database. but it appears that no matter what way I create the datasource beana via contructor or setter based injection the datasource properties have still yet to be replaced. Is there away to call the postProcessBeanFactory after the first EncryptablePropertyPlaceholderConfigurer was created, as it appears that the postProcessBeanFactory will only be called once all the PPC are created. I have tried to have a init-method on the EncryptablePropertyPlaceholderConfigurer bean calling the super.postProcessBeanFactory but I need to pass a ConfigurableListableBeanFactory instance which would hold all then beans. Is there away to get this working

      Any ideas as I am really stuck on this

      Thanks
      Danny

      Comment


      • #4
        Hi,

        I placed my beans in the way as shown below and was able to create an instance of "CommonsConfigurationFactoryBean" .Creating CommonsConfigurationFactoryBean was an issue for you.So once it has been created you can inject it into EncryptablePropertyPlaceholderConfigurer bean.Can you try this please.

        <bean id="propertyLoader" class="org.springframework.beans.factory.config.Pr opertyPlaceholderConfigurer">
        <property name="location">
        <value>db.properties</value>
        </property>
        </bean>

        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName">
        <value>${driverClassName}</value>
        </property>
        <property name="url">
        <value>${url}</value>
        </property>
        <property name="username">
        <value>${username}</value>
        </property>
        <property name="password">
        <value>${password}</value>
        </property>
        </bean>

        <bean name="CommonsConfigurationFactoryBean" class="org.springmodules.commons.configuration.Com monsConfigurationFactoryBean" >
        <property name="configurations">
        <list>
        <bean name="DatabaseConfiguration" class="org.apache.commons.configuration.DatabaseCo nfiguration">
        <constructor-arg index="0" ref="dataSource"/>
        <constructor-arg index="1" value="CONFIG_TABLE"/>
        <constructor-arg index="2" value="CONFIG_KEY"/>
        <constructor-arg index="3" value="CONFIG_VALUE"/>
        </bean>
        </list>
        </property>
        </bean>

        Hope this works for you.

        Kartik

        Comment


        • #5
          In addition to the above code,i am using two propertyplaceholder and i am injecting CommonsConfigurationFactoryBean to it

          <bean id="propertyLoader" class="org.springframework.beans.factory.config.Pr opertyPlaceholderConfigurer">
          <property name="location">
          <value>db.properties</value>
          </property>
          </bean>

          <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
          <property name="driverClassName">
          <value>${driverClassName}</value>
          </property>
          <property name="url">
          <value>${url}</value>
          </property>
          <property name="username">
          <value>${username}</value>
          </property>
          <property name="password">
          <value>${password}</value>
          </property>
          </bean>

          <bean name="CommonsConfigurationFactoryBean" class="org.springmodules.commons.configuration.Com monsConfigurationFactoryBean" >
          <property name="configurations">
          <list>
          <bean name="DatabaseConfiguration" class="org.apache.commons.configuration.DatabaseCo nfiguration">
          <constructor-arg index="0" ref="dataSource"/>
          <constructor-arg index="1" value="CONFIG_TABLE"/>
          <constructor-arg index="2" value="CONFIG_KEY"/>
          <constructor-arg index="3" value="CONFIG_VALUE"/>
          </bean>
          </list>
          </property>
          </bean>

          <bean id="propertyLoader1" class="org.springframework.beans.factory.config.Pr opertyPlaceholderConfigurer">
          <property name="properties" ref="CommonsConfigurationFactoryBean"/>
          </bean>


          -Kartik

          Comment


          • #6
            Hi Kartik,

            I am back to my original exception java.lang.ClassNotFoundException: ${datasource.driver}. Can you verifiy if the datasource has all its properties values replaced. Using a debugger I can see that Datasource pool hasnt had the datasource driver replaced. If you step through the debugger you will notice that the postProcessBeanFactory will only be called once all the PPC have been properly initialised.

            Here is my new config file

            <bean id="propertyLoader" class="org.springframework.beans.factory.config.Pr opertyPlaceholderConfigurer">
            <property name="location">
            <value>db.properties</value>
            </property>
            <property name="order" value="0"/>
            <property name="ignoreUnresolvablePlaceholders" value="true"/>

            </bean>

            <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" lazy-init="true">

            <property name="driverClass" value="${datasource.driver}"/>
            <property name="jdbcUrl" value="${datasource.url}"/>
            <property name="user" value="${datasource.username}"/>
            <property name="password" value="${datasource.password}"/>
            </bean>


            <bean id="propertyLoader1" class="org.springframework.beans.factory.config.Pr opertyPlaceholderConfigurer">
            <property name="properties" ref="CommonsConfigurationFactoryBean"/>
            </bean>

            <bean name="CommonsConfigurationFactoryBean" class="org.springmodules.commons.configuration.Com monsConfigurationFactoryBean" >
            <property name="configurations">
            <list>
            <bean name="DatabaseConfiguration" class="org.apache.commons.configuration.DatabaseCo nfiguration">
            <constructor-arg index="0" ref="myDataSource"/>
            <constructor-arg index="1" value="GBS_OFXM_CONFIG_DATA"/>
            <constructor-arg index="2" value="CONFIG_KEY"/>
            <constructor-arg index="3" value="CONFIG_VALUE"/>
            </bean>
            </list>
            </property>
            </bean>

            Regards
            Danny

            Comment


            • #7
              Failed to convert property value of type 'java.util.ArrayList' to required type 'java

              Hi Danny,
              With the above Approach I am getting the following exception. Can you please let me know what I need to do?

              Failed to convert property value of type 'java.util.ArrayList' to required type 'java.util.Properties[]' for property 'propertiesArray'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [org.springframework.beans.factory.config.PropertyP laceholderConfigurer] to required type [java.util.Properties] for property 'propertiesArray[0]': PropertyEditor [org.springframework.beans.propertyeditors.Properti esEditor] returned inappropriate value of type [org.springframework.beans.factory.config.PropertyP laceholderConfigurer]

              Regards,
              Narasimha

              Comment

              Working...
              X