package fi.utu.ville.exercises.stub; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.io.IOUtils; import com.vaadin.server.VaadinServlet; /** * A class for loading a .trl files (if needed) and providing a global access to them. */ class UILanguageGiver { private static final Logger logger = Logger.getLogger(UILanguageGiver.class .getName()); private static final AtomicReference<Map<String, UILanguageStub>> uiLanguages = new AtomicReference<Map<String, UILanguageStub>>(null); /** * Initiates UI-languages if needed and returns a {@link UILanguageStub} loaded for given {@link Locale} * * @param locale * {@link Locale} to use for the loaded {@link UILanguageStub} * @return {@link UILanguageStub} using the given {@link Locale} */ public static UILanguageStub getUILanguage(Locale locale) { if (uiLanguages.get() == null) { reloadLanguages(); } UILanguageStub res = uiLanguages.get().get(locale.getLanguage()); if (res == null) { throw new IllegalStateException( "No translations were found in the selected language! " + "Add at least some translations in the given language (@" + locale.getLanguage() + ") or choose another language!"); } else { return res; } } /** * Prompts the translations to be reloaded from the .trl-files. */ public static void reloadLanguages() { Map<String, UILanguageStub> oldValue = uiLanguages.get(); UILanguageLoaderStub loader = new UILanguageLoaderStub(); try { loader.readFiles(); } catch (IOException e) { logger.log(Level.SEVERE, "Could not load language files", e); } Map<String, UILanguageStub> initiatedLangs = loader.getLoadedLangs(); // in the stub it is enough that some thread has reloaded the languages // after this // reloading was prompted, no need to override, if it was already // updated // should not happen in stub though, as stub is not meant to be used in // multi-user situations uiLanguages.compareAndSet(oldValue, initiatedLangs); } /** * A class wrapping the actual loading of .trl-files and containing as hard-coded path the knowledge of where those files stored. * * @author Riku Haavisto */ static class UILanguageLoaderStub { private static Logger logger = Logger .getLogger(UILanguageLoaderStub.class.getName()); private static final String translationFileSuffix = ".trl"; private final Map<String, Map<String, String>> dictsByLang = new HashMap<String, Map<String, String>>();; /** * @return map of language-key to {@link UILanguageStub} parsed from all the translations found from the loaded .trl-files */ public Map<String, UILanguageStub> getLoadedLangs() { Map<String, UILanguageStub> res = new HashMap<String, UILanguageStub>(); for (String langName : dictsByLang.keySet()) { res.put(langName, new UILanguageStub(dictsByLang.get(langName))); } return res; } /** * Finds all the translation files from predefined path using the servlet-context methods for loading the .trl files also from the exercise-type jars * (and other ville-jars containing .trl files) * * @throws IOException * if there is an i/o-error */ public void readFiles() throws IOException { dictsByLang.clear(); Set<String> matches = VaadinServlet.getCurrent() .getServletContext() .getResourcePaths("/VILLE/language/extensions/"); for (String aMatch : matches) { if (aMatch.endsWith(translationFileSuffix)) { // strip path String fname = aMatch; if (fname.contains("/")) { // known to end with 'translationFileSuffix' so should // not be out-of-index fname = fname.substring(fname.lastIndexOf("/") + 1); } String currPrefix = fname.substring(0, fname.length() - translationFileSuffix.length()) .toUpperCase(); Map<String, Map<String, String>> newTranslations = TranslationFileParser .parseTranslationFile(currPrefix, (readFile(VaadinServlet.getCurrent() .getServletContext() .getResourceAsStream(aMatch)))); for (Entry<String, Map<String, String>> addToLang : newTranslations .entrySet()) { Map<String, String> translationsInLang = dictsByLang .get(addToLang.getKey()); if (translationsInLang == null) { translationsInLang = new HashMap<String, String>(); dictsByLang.put(addToLang.getKey(), translationsInLang); } for (Entry<String, String> newTranslation : addToLang .getValue().entrySet()) { // this would require having two translation files // with same name if (translationsInLang.put(newTranslation.getKey(), newTranslation.getValue()) != null) { logger.warning("Overrid entry for key: " + newTranslation.getKey() + ". This probably means that you have " + "included two .trl files with same namespace (=file-name)"); } } } } else { logger.warning("Non-trl resource-file ( " + aMatch + " ) contained in translation file path!"); } } } /** * Reads all the lines from an utf-8 input-stream and returns the lines as a list. * * @param toRead * {@link InputStream} from which to read lines * @return list of all the lines contained in the given stream * @throws IOException * if there is an io-error */ private List<String> readFile(InputStream toRead) throws IOException { List<String> res = IOUtils.readLines(toRead, "UTF-8"); return res; } } }