Page 1 of 2 12 LastLast
Results 1 to 10 of 12

Thread: Dynamic configuration from Java classes to Java Config

  1. #1
    Join Date
    Aug 2008
    Location
    Billings, Montana
    Posts
    47

    Default Dynamic configuration from Java classes to Java Config

    I have some configuration which are set by the users using java class. I would like to pass on these configuration to Spring Java Config classes. How do I achieve this in SJC?

    For instance, the database configuration is set in the Configuration java class (custom code). I would like to pull the database configuration from this custom class and dynamically pass these parameters to DataSourceConfiguration (SJC).

    Appreciate any insight into this.

  2. #2
    Join Date
    Apr 2007
    Posts
    307

    Default

    I believe you've gotten this question answered via other channels - is that right?
    Chris Beams
    Spring Framework committer, VMware
    http://github.com/cbeams

  3. #3
    Join Date
    Aug 2008
    Location
    Billings, Montana
    Posts
    47

    Default

    Chris,

    SystemPropertiesValueSource does not really solve my problem as my application could run within a J2SE/J2EE container, as I do not have control over other libraries within the same JVM could possibly override the system properties.

    So, I am looking for some kind of setters on these configuration objects which could be invoked just after context initialization.

    Basically, I should be able to set some of the database configuration properties at runtime without using any of the existing properties resolvers (System, Environment).

    Code:
            JavaConfigApplicationContext context = new JavaConfigApplicationContext(ApplicationConfiguration.class);
            Configuration configuration = new Configuration();//my application config class
            configuration.setDatabaseType("MYSQL");
            configuration.setDriver("com.mysql.jdbc.Driver");
            configuration.setUrl("jdbc:mysql://localhost:3306/sjc");
            configuration.setUsername("root");
            configuration.setPassword("mysql");
            overrideConfiguration(configuration);//this should somehow override the configuration originally initialized by the application context
            DataSource ds = context.getBean(BasicDataSource.class);
            Connection conn = ds.getConnection();
    Is it possible to achieve something like this in SJC?

    Appreciate your clarification.

    Thanks!
    Arul

  4. #4
    Join Date
    Aug 2008
    Location
    Billings, Montana
    Posts
    47

    Default

    Chris,

    I was able to resolve this issue after going through some of the system tests.

    Btw, did you had a chance to look in to the code which I submitted for http://jira.springframework.org/browse/SJC-150?

    -Arul

  5. #5
    Join Date
    Apr 2007
    Posts
    307

    Default

    Re: SJC-150 - not yet, but I haven't forgotten about it. Thanks again for submitting.
    Chris Beams
    Spring Framework committer, VMware
    http://github.com/cbeams

  6. #6
    Join Date
    Aug 2008
    Location
    Billings, Montana
    Posts
    47

    Default Overriding configuration after context creation

    Hi Chris,

    I have the following test case which fails to override the bean configuration after context creation. Could you please correct me if I am missing something in my configuration?

    Code:
    import static junit.framework.Assert.assertEquals;
    import org.junit.Test;
    import org.springframework.config.java.annotation.Bean;
    import org.springframework.config.java.annotation.Configuration;
    import org.springframework.config.java.context.JavaConfigApplicationContext;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    
    import javax.sql.DataSource;
    import java.sql.Connection;
    
    public class TestConfiguration {
    
      @Test
      public void testOverrideConfig() throws Exception {
        JavaConfigApplicationContext context = new JavaConfigApplicationContext(DataSourceConfiguration.class);
        //override default configuration
        DefaultConfig customConfig = context.getBean(DefaultConfig.class);
        customConfig.setDriverClass("com.mysql.jdbc.Driver");
        customConfig.setJdbcUrl("jdbc:mysql://localhost/test");
        customConfig.setUser("root");
        customConfig.setPassword("mysql");
        DataSource dataSource = context.getBean(DataSource.class);
        Connection connection = dataSource.getConnection();
        assertEquals("MySQL", connection.getMetaData().getDatabaseProductName());
      }
    
      @Configuration
      static class DataSourceConfiguration {
        //default driver configuration    
        private String driverClass = "org.hsqldb.jdbcDriver";
        private String jdbcUrl = "jdbc:hsqldb:mem:test";
        private String user = "sa";
        private String password = "";
    
        @Bean
        public DefaultConfig defaultConfig() {
          DefaultConfig defaultConfig = new DefaultConfig(driverClass, jdbcUrl, user, password);
          return defaultConfig;
        }
    
        @Bean
        public DataSource dataSource() {
          DriverManagerDataSource dataSource = new DriverManagerDataSource();
          DefaultConfig config = defaultConfig();
    
          dataSource.setDriverClassName(config.getDriverClass());
          dataSource.setUrl(config.getJdbcUrl());
          dataSource.setUsername(config.getUser());
          dataSource.setPassword(config.getPassword());
          return dataSource;
        }
    
      }
    
      static class DefaultConfig {
        private String driverClass;
        private String jdbcUrl;
        private String user;
        private String password;
    
        DefaultConfig(String driverClass, String jdbcUrl, String user, String password) {
          this.driverClass = driverClass;
          this.jdbcUrl = jdbcUrl;
          this.user = user;
          this.password = password;
        }
    
        public String getDriverClass() {
          return driverClass;
        }
    
        public void setDriverClass(String driverClass) {
          this.driverClass = driverClass;
        }
    
        public String getJdbcUrl() {
          return jdbcUrl;
        }
    
        public void setJdbcUrl(String jdbcUrl) {
          this.jdbcUrl = jdbcUrl;
        }
    
        public String getUser() {
          return user;
        }
    
        public void setUser(String user) {
          this.user = user;
        }
    
        public String getPassword() {
          return password;
        }
    
        public void setPassword(String password) {
          this.password = password;
        }
    
      }
    }
    Thanks!
    Arul
    Last edited by aruld; Oct 14th, 2008 at 01:44 PM. Reason: updated sub-title

  7. #7
    Join Date
    Apr 2007
    Posts
    307

    Default

    The DataSource bean (like all beans) is eagerly instantiated during the construction of JavaConfigApplicationContext. So, by the time you reset the values in DefaultConfig, it's too late.

    You have at least a couple of options.

    1) make the DataSource bean @Bean(lazy=Lazy.TRUE).
    2) make the DataSource bean @Bean(scope=DefaultScopes.PROTOTYPE)

    The second option isn't likely to be viable though - if you have multiple objects depending on DataSource, you'll want them all talking to the same instance, I'm sure.

    - C
    Chris Beams
    Spring Framework committer, VMware
    http://github.com/cbeams

  8. #8
    Join Date
    Aug 2008
    Location
    Billings, Montana
    Posts
    47

    Default

    Thanks Chris.

    It worked like a charm as always with SJC

    -Arul

  9. #9
    Join Date
    Apr 2007
    Posts
    307

    Default

    great news!
    Chris Beams
    Spring Framework committer, VMware
    http://github.com/cbeams

  10. #10
    Join Date
    Aug 2008
    Location
    Billings, Montana
    Posts
    47

    Default Adding JpaConfiguration to context fails to override default DataSourceConfiguration

    Hi Chris,

    This works only if I include DataSourceConfiguration to the JavaConfigApplicationContext. If I include both DataSourceConfiguration and JpaConfiguration, the override does not work. It always falls back to the default datasource.

    Here is my configuration classes for your reference.

    JpaConfiguration

    Code:
    @Configuration
    @AnnotationDrivenTx
    @AnnotationDrivenConfig
    @Import({DataSourceConfiguration.class})
    public abstract class JpaConfiguration extends ConfigurationSupport {
    
      @ExternalBean
      abstract DataSource dataSource();
    
      @Bean
      public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        adapter.setShowSql(true);
        adapter.setGenerateDdl(false);
        adapter.setDatabasePlatform("org.hibernate.dialect.MySQLInnoDBDialect");
        return adapter;
      }
    
      @Bean(lazy = Lazy.TRUE)
      public EntityManagerFactory entityManagerFactory() {
        Properties jpaProperties = new Properties();
        jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect");
        jpaProperties.put("hibernate.show_sql", true);
    
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setPersistenceUnitName("myPU");
        em.setJpaDialect(jpaDialect());
        em.setJpaProperties(jpaProperties);
        em.setDataSource(dataSource());
        em.setJpaVendorAdapter(jpaVendorAdapter());
        em.setLoadTimeWeaver(loadTimeWeaver());
        return this.getObject(em, EntityManagerFactory.class);
      }
    
      @Bean
      public JpaDialect jpaDialect() {
        return new HibernateJpaDialect();
      }
    
      @Bean
      public InstrumentationLoadTimeWeaver loadTimeWeaver() {
        return new InstrumentationLoadTimeWeaver();
      }
    
      @Bean(lazy = Lazy.TRUE)
      public PlatformTransactionManager transactionManager() {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory());
        txManager.setJpaDialect(jpaDialect());
        txManager.setDataSource(dataSource());
        return txManager;
      }
    }
    DataSourceConfiguration
    Code:
    @Configuration
    public abstract class DataSourceConfiguration extends ConfigurationSupport {
      @Bean(lazy = Lazy.TRUE)
      public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        CustomConfiguration config = customConfiguration();
        dataSource.setDriverClassName(config.getDriverClass());
        dataSource.setUrl(config.getJdbcUrl());
        dataSource.setUsername(config.getJdbcUsername());
        dataSource.setPassword(config.getJdbcPassword());
        return dataSource;
    
      }
    
      @Bean
      public CustomConfiguration customConfiguration() {
        String driverClass = "org.h2.Driver";
        String jdbcUrl = "jdbc:h2:mem:test";
        String user = "sa";
        String password = "";
    
        CustomConfiguration config = new CustomConfiguration();
        config.setDriverClass(driverClass);
        config.setJdbcUrl(jdbcUrl);
        config.setJdbcUsername(user);
        config.setJdbcPassword(password);
        return config;
      }
    }
    CustomConfiguration

    Code:
    public class CustomConfiguration {
      private String driverClass;
      private String jdbcUrl;
      private String jdbcUsername;
      private String jdbcPassword;
      //getters/setters omitted
    }
    Test
    Code:
      @Test
      public void testOverrideConfig() throws Exception {
        JavaConfigApplicationContext context = new JavaConfigApplicationContext(DataSourceConfiguration.class, JpaConfiguration.class);
        //override default configuration
        CustomConfiguration customConfig = context.getBean(CustomConfiguration.class);
        customConfig.setDriverClass("com.mysql.jdbc.Driver");
        customConfig.setJdbcUrl("jdbc:mysql://localhost/test");
        customConfig.setJdbcUsername("root");
        customConfig.setJdbcPassword("secret");
        DataSource dataSource = context.getBean(DataSource.class);
        Connection connection = dataSource.getConnection();
        assertEquals("MySQL", connection.getMetaData().getDatabaseProductName());
    
      }
    Please clarify this issue.

    Thanks!
    Arul

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •