package org.jibeframework.core.service.impl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.jibeframework.core.Context;
import org.jibeframework.core.JibeRuntimeException;
import org.jibeframework.core.app.Application;
import org.jibeframework.core.app.Reloadable;
import org.jibeframework.core.app.bootstrap.Bootstrapable;
import org.jibeframework.core.app.bootstrap.MessagesBootstrapDescriptor;
import org.jibeframework.core.app.messages.MessagesProvider;
import org.jibeframework.core.service.MessageService;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ResourceUtils;
/**
*
* @author dhalupa
*
*/
public class MessagesServiceImpl implements MessageService, Bootstrapable<MessagesBootstrapDescriptor>, Reloadable {
private Set<String> clientBundles = new LinkedHashSet<String>();
private Set<String> serverBundles = new LinkedHashSet<String>();
private Map<File, Long> resources = new HashMap<File, Long>();
private Map<Locale, Map<String, String>> serverMessagesCache = new HashMap<Locale, Map<String, String>>();
private Map<Locale, Map<String, String>> clientMessagesCache = new HashMap<Locale, Map<String, String>>();
private Object lock = new Object();
private List<MessagesProvider> proxies = new ArrayList<MessagesProvider>();
public Locale getLocale() {
Context currentContext = Context.getCurrentContext();
if (currentContext != null) {
return currentContext.getLocale();
}
return null;
}
public void bootstrap(MessagesBootstrapDescriptor data) {
clientBundles.addAll(data.getClientBundles());
serverBundles.addAll(data.getServerBundles());
proxies.addAll(data.getProvidersProxies());
}
public String getMessage(String key, Object... args) {
key = key.replace(':', '_');
Locale locale = Context.getCurrentContext().getLocale();
if (!serverMessagesCache.containsKey(locale)) {
synchronized (lock) {
if (!serverMessagesCache.containsKey(locale)) {
loadServerMessagesCache();
}
}
}
String message = serverMessagesCache.get(locale).get(key);
if (message == null) {
for (MessagesProvider proxy : proxies) {
message = proxy.getMessage(key, args);
if (message != null) {
break;
}
}
}
if (message == null) {
return String.format("#%1$s#", key);
}
return MessageFormat.format(message, args);
}
public Map<String, String> getMessages() {
Locale locale = Context.getCurrentContext().getLocale();
if (!serverMessagesCache.containsKey(locale)) {
synchronized (lock) {
if (!serverMessagesCache.containsKey(locale)) {
loadServerMessagesCache();
}
}
}
return serverMessagesCache.get(locale);
}
public String getMessage(String key) {
return getMessage(key, new Object[0]);
}
public Map<String, String> getClientMessages() {
Locale locale = Context.getCurrentContext().getLocale();
if (!clientMessagesCache.containsKey(locale)) {
Map<String, String> o = new HashMap<String, String>();
Properties p = new Properties();
for (String clientBundle : clientBundles) {
try {
p.putAll(getMessagesFromBundle(Application.getClasspathPrefix() + clientBundle));
} catch (IOException e) {
throw new JibeRuntimeException("Message bundles could not be loaded", e);
}
}
for (Object key : p.keySet()) {
o.put((String) key, p.getProperty((String) key));
}
clientMessagesCache.put(locale, o);
}
return clientMessagesCache.get(locale);
}
public void reloadIfRequired() {
for (File res : resources.keySet()) {
if (res != null && res.lastModified() != resources.get(res))
synchronized (lock) {
serverMessagesCache.clear();
clientMessagesCache.clear();
}
}
}
private void loadServerMessagesCache() {
Map<String, String> messages = new HashMap<String, String>();
for (String bundle : serverBundles) {
Properties p = null;
try {
p = getMessagesFromBundle(Application.getClasspathPrefix() + bundle);
} catch (IOException e) {
throw new JibeRuntimeException("Could not load message bundles", e);
}
for (String msg : p.stringPropertyNames()) {
messages.put(msg, p.getProperty(msg));
}
}
serverMessagesCache.put(Context.getCurrentContext().getLocale(), messages);
}
private Properties getMessagesFromBundle(String bundle) throws IOException {
Locale locale = Context.getCurrentContext().getLocale();
Properties p = new Properties();
load(bundle, p);
load(bundle + "_" + locale, p);
load(bundle + "_" + locale.getCountry(), p);
return p;
}
private void load(String bundle, Properties p) throws FileNotFoundException, IOException {
File file;
try {
file = ResourceUtils.getFile(bundle + ".properties");
} catch (FileNotFoundException e) {
return;
}
if (file.exists()) {
resources.put(file, file.lastModified());
p.load(new FileInputStream(file));
}
}
public String getPropertyTitle(String property) {
return getMessage(getKey(property, "title"));
}
public String getPropertyDescription(String property) {
return getMessage(getKey(property, "description"));
}
private String getKey(String property, String label) {
StringBuffer b = new StringBuffer();
b.append("property.").append(property).append(".").append(label);
return StringUtils.replace(b.toString(), ":", "_");
}
}