com.cleverpine.cptranslationsutil.config.DynamicResourceBundleMessageSource Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cp-translations-util Show documentation
Show all versions of cp-translations-util Show documentation
Simple util library for Spring Framework projects
package com.cleverpine.cptranslationsutil.config;
import com.cleverpine.cptranslationsutil.dto.ModuleProperties;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.io.FileSystemResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.lang.Nullable;
import static com.cleverpine.cptranslationsutil.util.ErrorMessages.INVALID_LOCALE_CODE_ERROR_MESSAGE;
import static com.cleverpine.cptranslationsutil.util.ErrorMessages.PROPERTY_FILE_CREATION_ERROR_MESSAGE;
import static com.cleverpine.cptranslationsutil.util.ErrorMessages.TRANSLATION_MAP_FOR_LANGUAGE_NULL_ERROR_MESSAGE_FORMAT;
/**
* Custom implementation of hot reload of internationalization properties.
* Caching of properties defaults to 3600 seconds (1 hour).
* Properties are loaded from relative to the current VM working directory.
* Additional configuration might be needed if application is run in a web server like Tomcat.
*/
@Log4j2
public class DynamicResourceBundleMessageSource extends ReloadableResourceBundleMessageSource {
private final String PROPERTIES_SUFFIX = ".properties";
private final String PROPERTY_FORMAT = "%s.%s=%s%s";
private String resourcePath = "/i18n/";
private ResourceLoader resourceLoader;
public DynamicResourceBundleMessageSource(
String basename,
String messagesPath,
String defaultEncoding
) {
this(basename, messagesPath, defaultEncoding, 3600);
}
public DynamicResourceBundleMessageSource(
String basename,
String messagesPath,
String defaultEncoding,
int cacheIntervalSeconds
) {
log.debug("Configuring ReloadableResourceBundleMessageSource");
this.resourcePath = messagesPath;
log.info("Loading i18n properties from: " + this.resourcePath + basename);
this.setBasename(this.resourcePath + basename);
this.resourceLoader = new FileSystemResourceLoader();
this.setResourceLoader(this.resourceLoader); //for parent ReloadableResourceBundleMessageSource
this.setDefaultEncoding(defaultEncoding);
if(cacheIntervalSeconds == -1){
log.debug("Cache interval set to -1. Caching properties forever.");
} else if(cacheIntervalSeconds > 0){
log.debug("Caching is set to {} seconds", cacheIntervalSeconds);
} else if(cacheIntervalSeconds == 0){
log.warn("Caching is disabled and reload checks are run on every request! "
+ "Do not use this option in production.");
}
this.setCacheSeconds(cacheIntervalSeconds);
}
/**
* By documentation, the resourceLoader of ReloadableResourceBundleMessageSource
* is overriden by the ApplicationContext. Only enable overriding it if is of type FileSystemResourceLoader.
* @param resourceLoader the ResourceLoader object to be used by this object
*/
@Override
public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
if(resourceLoader instanceof FileSystemResourceLoader){
super.setResourceLoader(resourceLoader);
}
}
public static Locale getValidLocaleOrThrowException(String language) {
if (language == null) {
throw new IllegalArgumentException(INVALID_LOCALE_CODE_ERROR_MESSAGE);
}
return new Locale(language);
}
protected String getResourceFileName(String basename, Locale locale) {
return basename + "_" + locale.toString();
}
protected String getFullResourceFileName(String baseFileName){
return baseFileName + PROPERTIES_SUFFIX;
}
public void refreshMessages(String language, Map> moduleMap) {
if (moduleMap == null) {
throw new IllegalArgumentException(String.format(TRANSLATION_MAP_FOR_LANGUAGE_NULL_ERROR_MESSAGE_FORMAT, language));
}
Locale locale = getValidLocaleOrThrowException(language);
String fileName = getResourceFileName(getBasenameSet().iterator().next(), locale);
createOrOverwriteResourceForLanguage(getFullResourceFileName(fileName), moduleMap);
PropertiesHolder propertiesHolder = createPropertiesBundle(moduleMap);
this.refreshProperties(fileName, propertiesHolder);
}
private PropertiesHolder createPropertiesBundle(Map> moduleMap) {
Map modulePropertiesMap = new HashMap<>();
for(String module : moduleMap.keySet()){
ModuleProperties moduleProperties = new ModuleProperties();
moduleProperties.setTranslations(moduleMap.get(module));
modulePropertiesMap.put(module, moduleProperties);
}
Properties properties = new Properties();
properties.putAll(modulePropertiesMap);
return new PropertiesHolder(properties, System.currentTimeMillis());
}
protected void createOrOverwriteResourceForLanguage(String fileName, Map> messages) {
try {
Resource resource = this.resourceLoader.getResource(fileName);
File propertiesFile;
if (!resource.exists()) {
log.debug("Messages for new language available. Creating {}", fileName);
propertiesFile = resource.getFile();
propertiesFile.createNewFile();
} else {
propertiesFile = resource.getFile();
}
writeMessagesToNewPropertiesFile(messages, propertiesFile);
} catch (IOException e) {
throw new RuntimeException(PROPERTY_FILE_CREATION_ERROR_MESSAGE + fileName, e);
}
}
private void writeMessagesToNewPropertiesFile(Map> messages, File propertiesFile) throws IOException {
try (FileOutputStream outputStream = new FileOutputStream(propertiesFile, false)) {
for (String module : messages.keySet()) {
Set> moduleEntrySet = messages.get(module).entrySet();
for (Map.Entry entry : moduleEntrySet) {
String line = String.format(PROPERTY_FORMAT, module, entry.getKey(), entry.getValue(), System.lineSeparator());
outputStream.write(line.getBytes(StandardCharsets.UTF_8));
}
}
}
}
public String resolveCodeForMapping(String property, Locale locale){
return this.resolveCodeWithoutArguments(property, locale);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy