package husacct.common.locale;
import husacct.common.Resource;
import husacct.common.services.ObservableService;
import husacct.control.task.configuration.ConfigurationManager;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.apache.log4j.Logger;
public class LocaleServiceImpl extends ObservableService implements ILocaleService{
private Logger logger = Logger.getLogger(LocaleServiceImpl.class);
public static Locale english = Locale.ENGLISH;
public static Locale dutch = new Locale("nl", "NL");
private String bundleLocation = Resource.LOCALE_PATH;
private String bundlePrefix = "husacct";
private String bundleSuffix = ".properties";
private Locale defaultLocale;
private ResourceBundle resourceBundle;
private Locale currentLocale;
private List<Locale> availableLocales = new ArrayList<Locale>();
public LocaleServiceImpl(){
detectLocales();
String locale = ConfigurationManager.getProperty("Language");
defaultLocale = new Locale(locale, locale);
setLocale(defaultLocale);
}
private void detectLocales(){
String[] fileNames = null;
try {
fileNames = getResourceListing(bundleLocation);
for(String fileName : fileNames){
if(fileName.startsWith(bundlePrefix + "_") && fileName.endsWith(bundleSuffix)){
String locale = fileName.substring(bundlePrefix.length()+1, fileName.indexOf("."));
Locale detectedLocale = new Locale(locale, locale);
availableLocales.add(detectedLocale);
}
}
} catch (Exception e) {
logger.debug("Unable to find locales dynamically.");
availableLocales.add(defaultLocale);
}
}
@Override
public void setLocale(Locale locale){
if(isAvailableLocale(locale)){
currentLocale = locale;
loadBundle();
notifyServiceListeners();
} else {
logger.warn("Trying to set non-existing locale " + locale.getLanguage());
}
}
private void loadBundle(){
try {
String path = bundleLocation.replace('/', '.').substring(1) + bundlePrefix;
resourceBundle = ResourceBundle.getBundle(path, getLocale());
} catch (Exception e){
logger.debug("Unable to reload resource bundle: " + e.getMessage());
}
}
@Override
public List<Locale> getAvailableLocales(){
return availableLocales;
}
private boolean isAvailableLocale(Locale locale){
String language = locale.getLanguage();
for(Locale availableLocale : getAvailableLocales()){
String availableLanguage = availableLocale.getLanguage();
if(language.equals(availableLanguage)){
return true;
}
}
return false;
}
@Override
public Locale getLocale(){
return currentLocale;
}
@Override
public String getTranslatedString(String key){
String transKey = "";
if((key == null) || (key == ""))
return "";
try {
transKey = resourceBundle.getString(key);
} catch (MissingResourceException missingResourceException){
return key + " (Missing resource in Locale service)";
//logger.debug(String.format("Unable to find translation for key %s in %s_%s.properties" + key + resourceBundle.getLocale().getLanguage()));
//missingResourceException.printStackTrace();
}
return transKey;
}
/**
* List directory contents for a resource folder. Not recursive.
* This is basically a brute-force implementation.
* Works for regular files and also JARs.
*
* @author Greg Briggs, http://www.uofr.net/~greg/java/get-resource-listing.html
* @param clazz Any java class that lives in the same place as the resources you want.
* @param strippedPath Should end with "/", but not start with one.
* @return Just the name of each member item, not the full paths.
* @throws URISyntaxException
* @throws IOException
*/
private String[] getResourceListing(String path) throws URISyntaxException, IOException {
String strippedPath = path.substring(1);
URL dirURL = getClass().getClassLoader().getResource(strippedPath);
if (dirURL != null && dirURL.getProtocol().equals("file")) {
/* A file path: easy enough */
return new File(dirURL.toURI()).list();
}
if (dirURL == null) {
/*
* In case of a jar file, we can't actually find a directory.
* Have to assume the same jar as clazz.
*/
String me = getClass().getName().replace(".", "/")+".class";
dirURL = getClass().getClassLoader().getResource(me);
}
if (dirURL.getProtocol().equals("jar")) {
/* A JAR path */
String jarPath = dirURL.getPath().substring(5, dirURL.getPath().indexOf("!")); //strip out only the JAR file
JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
Set<String> result = new HashSet<String>(); //avoid duplicates in case it is a subdirectory
while(entries.hasMoreElements()) {
String name = entries.nextElement().getName();
if (name.startsWith(strippedPath)) { //filter according to the path
String entry = name.substring(strippedPath.length());
int checkSubdir = entry.indexOf("/");
if (checkSubdir >= 0) {
// if it is a subdirectory, we just return the directory name
entry = entry.substring(0, checkSubdir);
}
result.add(entry);
}
}
jar.close();
return result.toArray(new String[result.size()]);
}
throw new UnsupportedOperationException("Cannot list files for URL "+dirURL);
}
}