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;
}
}