1

I created a database driven message bean which loads messages from database and if a message key cannot be found then it falls back to properties files. It works fine except one thing. All other message properties from spring are missing. (Eg. error messages from spring security AbstractSecurityInterceptor.authenticationNotFound.)

Spring 4.1.6

<bean class="org.springframework.context.support.ReloadableResourceBundleMessageSource" id="propertiesMessageSource">              
    <property name="basenames">
        <list>                
            <value>classpath:events</value>                
            <value>classpath:messages.prod</value>                
            <value>classpath:messages</value>                                
        </list>
    </property>        
</bean>
<bean id="messageSource" class="hu.bluesystem.hrportal.services.DatabaseDrivenMessageSource">        
    <constructor-arg ref="messageResourceService"/>
    <property name="parentMessageSource" ref="propertiesMessageSource"/>    
</bean>


    package x.x.services;

    import java.text.MessageFormat;
    import java.util.HashMap;
    import java.util.Locale;
    import java.util.Map;
    import javax.annotation.PostConstruct;
    import org.apache.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ResourceLoaderAware;
    import org.springframework.context.support.AbstractMessageSource;
    import org.springframework.core.io.DefaultResourceLoader;
    import org.springframework.core.io.ResourceLoader;

    public final class DatabaseDrivenMessageSource extends AbstractMessageSource implements ResourceLoaderAware {

        final private Logger log = Logger.getLogger(getClass());
        private ResourceLoader resourceLoader;

        private final Map<String, Map<String, String>> properties = new HashMap();

        @Autowired
        private MessageResourceServiceImpl messageResourceService;

        public DatabaseDrivenMessageSource(MessageResourceServiceImpl messageResourceService) {
            this.messageResourceService = messageResourceService;

        }

        @PostConstruct
        public void init() {
            reload();
        }

        @Override
        protected MessageFormat resolveCode(String code, Locale locale) {
            String msg = getText(code, locale);
            MessageFormat result = createMessageFormat(msg, locale);
            return result;
        }

        @Override
        protected String resolveCodeWithoutArguments(String code, Locale locale) {
            String result = getText(code, locale);
            return result;
        }

        private String getText(String code, Locale locale) {
            Map<String, String> localized = properties.get(code);
            String textForCurrentLanguage = null;
            if (localized != null) {
                textForCurrentLanguage = localized.get(locale.getLanguage());
                if (textForCurrentLanguage == null) {
                    textForCurrentLanguage = localized.get(new Locale("en_US"));
                }
            }
            if (textForCurrentLanguage == null) {
                //Check parent message
                try {
                    textForCurrentLanguage = getParentMessageSource().getMessage(code, null, locale);
                } catch (Exception e) {
                    logger.error("Cannot find message with code: " + code);
                }
            }
            return textForCurrentLanguage != null ? textForCurrentLanguage : code;
        }

        public void reload() {
            properties.clear();
            properties.putAll(loadTexts());
        }

        protected Map<String, Map<String, String>> loadTexts() {
            return messageResourceService.reloadMessages();

        }

        @Override
        public void setResourceLoader(ResourceLoader resourceLoader) {
            this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader());
        }
    }

    package x.x.services;


   import java.util.HashMap;
   import java.util.List;
   import java.util.Map;
   import java.util.Properties;
   import java.util.logging.Level;
   import java.util.logging.Logger;
   import org.springframework.jdbc.core.JdbcTemplate;
   import org.springframework.jdbc.datasource.DriverManagerDataSource;

   public class MessageResourceServiceImpl implements MessageResourceService {

    private static final Logger LOG = Logger.getLogger(MessageResourceServiceImpl.class.getName());

    String dataSourceName;

    Properties dbProperties;

    DriverManagerDataSource dataSource;
    private  Map<String, Map<String, String>> msg = new HashMap();

    public Map<String, Map<String, String>> reloadMessages() {
        try {

            dataSource = new DriverManagerDataSource();

            dataSource.setDriverClassName(dbProperties.getProperty("jdbc.driverClassName"));
            dataSource.setPassword(dbProperties.getProperty("jdbc.password"));
            dataSource.setUsername(dbProperties.getProperty("jdbc.username"));
            dataSource.setUrl(dbProperties.getProperty("jdbc.url"));
            load();

            dataSource.getConnection().close();

        } catch (Exception ex) {
            Logger.getLogger(SpringPropertiesUtilImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
       return msg;
    }

    private void load() {
        Map<String, String> m;
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        List<Map<String,  Object>> messages = jdbcTemplate
                .queryForList("select msg_key, msg_value,msg_locale from hrp_app_messages where msg_status='true'");

        LOG.info("Loading messages from Database");

        for(Map<String, Object> message : messages) {
            m=new HashMap();
            if(msg.get(message.get("MSG_KEY").toString())!=null) {
               m=msg.get(message.get("MSG_KEY").toString());
            }           
            m.put(message.get("MSG_LOCALE").toString(),message.get("MSG_VALUE").toString());            
            msg.put(message.get("MSG_KEY").toString(),m);
        }

    }

    public String getDataSourceName() {
        return dataSourceName;
    }

    public void setDataSourceName(String dataSourceName) {
        this.dataSourceName = dataSourceName;
    }

    public Properties getDbProperties() {
        return dbProperties;
    }

    public void setDbProperties(Properties dbProperties) {
        this.dbProperties = dbProperties;
    }

}
sfeher
  • 51
  • 4
  • Please have a look at [this](https://stackoverflow.com/questions/10623388/override-springmessage-tag-with-database-values) – m4gic Aug 31 '18 at 13:32

1 Answers1

0

Using ReloadableResourceBundleMessageSource class instead of AbstractMessageSource it works fine. Thank you for the support.

sfeher
  • 51
  • 4