Added by erik.drolshammer, last edited by erik.drolshammer on Mar 31, 2008  (view change)

Labels:

Enter labels to add to this page:
Wait Image 
Looking for a label? Just start typing.

Run-time approach

The goal is to avoid building artifacts for different environments. This problem can be divided into the following sub-problems:

  • Make the application environment-independent. I.e., by default is should not have any dependencies to external systems.
  • Use property files from classpath to override default configuration. It should for example be possible to use an external database instead of the default embedded one by defining properties in a property file.

Suggested implementation

We assume that the application use Dependency Injection. The default configuration should depend on embedded products only.

The Proof-of-Concept code uses Spring's IoC container. To override this defaults we use PropertyOverrideConfigurer instead of the more common PropertyPlaceholderConfigurer. The following example use HSQLDB by default, but can be configured to use another database by adding a deploy.properties file to classpath.

<bean id="propertyConfigurer"
      class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
    <property name="location">
          <value>classpath:deploy.properties</value>
    </property>
</bean>

<bean id="dataSource"
      class="org.apache.commons.dbcp.BasicDataSource"
      destroy-method="close">
    <property name="driverClassName">
        <value>org.hsqldb.jdbcDriver</value>
    </property>
    <property name="url">
        <value>jdbc:hsqldb:mem:naut</value>
    </property>
    <property name="username">
        <value>sa</value>
    </property>
    <property name="password">
        <value></value>
    </property>

    <property name="removeAbandoned">
        <value>true</value>
    </property>
    <property name="removeAbandonedTimeout">
        <value>60</value>
    </property>
    <property name="logAbandoned">
        <value>true</value>
    </property>
</bean>

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
  <property name="dataSource" ref="dataSource"/>

  <property name="mappingDirectoryLocations">
      <list>
          <value>classpath:/no/abakus/naut/entity</value>
      </list>
  </property>

  <property name="hibernateProperties">
      <props>
          <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
          <prop key="hibernate.query.substitutions">true 'T', false 'F'</prop>
          <!--<prop key="hibernate.hbm2ddl.auto">create-drop</prop>-->
          <prop key="hibernate.show_sql">false</prop>

          <prop key="hibernate.c3p0.acquire_increment">3</prop>
          <prop key="hibernate.c3p0.idle_test_period">30</prop>
          <prop key="hibernate.c3p0.timeout">600</prop>
          <prop key="hibernate.c3p0.max_size">50</prop>
          <prop key="hibernate.c3p0.min_size">5</prop>
          <prop key="hibernate.c3p0.max_statements">50</prop>
      </props>
  </property>
</bean>

Note that we have explicitly specified deploy.properties in the PropertyOverrideConfigurer, because there should only be one such deployment descriptor. To use PostgreSQL instead of HSQLDB, put the following into deploy.properties:

dataSource.driverClassName=org.postgresql.Driver
dataSource.url=jdbc:postgresql://db.abakus.no/naut
dataSource.username=naut
dataSource.password=prodDataSourcePasswordHere

sessionFactory.hibernateProperties[java:hibernate.dialect]=org.hibernate.dialect.PostgreSQLDialect

If you need to change many properties, it might be better to choose beans using a configurer and just use deploy.properties to set which combination of beans to use. See Alef Arendsen's blog for details on how to set this up. (NOTE! Erik tried this approach, but could not get it to work.)

How to enforce that all relevant properties are changed when deploying to a different environment?

(If one or two settings are off, the result might be very hard to debug.)
This problem can be reduced by minimizing the number of properties that needs to be set.

  • We could distribute the application as a zip archive that contains template-files and readmes in addition to the artifact. This solution is far from ideal, but it is currently my best suggestion.

We got Alef's approach working recently, but I'm still not 100% happy with the solution.. Using Spring there's no way to get a type-safe injection like you would with @Autowired and @Qualified. What I would've liked would've been if we could make some sort of annotation which was a mix of @Qualified and @IfProfileValue to use a combination of annotations and system properties to decide on which bean to inject..

Posted by thomas.nicolaisen at Feb 22, 2008 08:07 Updated by erik.drolshammer

In more complex settings, you do need to consider a centralized config-repository approach, from which the inject-parameters are fetched after an initial identification phase. This is neccessary when you try to do ad-hoc vertical and horizontal scaling in a heterogenous environment.

It also simplifies auditing and security perspectives for those interested in those topics

Posted by Thor Henning Hetland at Feb 22, 2008 08:39 Updated by Erik Drolshammer
All content on this wiki is licensed under a Creative Commons Attribution 3.0 Unported License.