Coverage Summary for Class: CustomResourceBundle (org.kitodo.production.helper.messages)

Class Class, % Method, % Line, %
CustomResourceBundle 100% (1/1) 50% (6/12) 63,6% (28/44)


 /*
  * (c) Kitodo. Key to digital objects e. V. <contact@kitodo.org>
  *
  * This file is part of the Kitodo project.
  *
  * It is licensed under GNU General Public License version 3 or later.
  *
  * For the full copyright and license information, please read the
  * GPL3-License.txt file that was distributed with this source code.
  */
 
 package org.kitodo.production.helper.messages;
 
 import java.io.File;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
 import java.util.MissingResourceException;
 import java.util.Objects;
 import java.util.ResourceBundle;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.kitodo.config.ConfigCore;
 import org.kitodo.config.enums.ParameterCore;
 import org.kitodo.production.helper.LocaleHelper;
 
 abstract class CustomResourceBundle extends ResourceBundle {
 
     private static final Logger logger = LogManager.getLogger(CustomResourceBundle.class);
     private static URLClassLoader urlClassLoader;
     private static Map<String, Boolean> propertiesFileExistsMap = new HashMap<String, Boolean>();
 
     @Override
     public Enumeration<String> getKeys() {
         throw new UnsupportedOperationException();
     }
 
     @Override
     protected Object handleGetObject(String key) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * Create a URLClassLoader that is allowed to load resource bundles from the external directory
      * containing translated messages and errors (e.g. /usr/local/kitodo/messages).
 
      * @return instance of URLClassLoader
      */
     private static URLClassLoader getURLClassLoader() {
         if (Objects.isNull(urlClassLoader)) {
             File file = new File(ConfigCore.getParameterOrDefaultValue(ParameterCore.DIR_LOCAL_MESSAGES));
             if (file.exists()) {
                 try {
                     final URL resourceURL = file.toURI().toURL();
                     urlClassLoader = AccessController.doPrivileged(
                         (PrivilegedAction<URLClassLoader>) () -> new URLClassLoader(new URL[] { resourceURL })
                     );
                 } catch (MalformedURLException e) {
                     logger.info(e.getMessage(), e);
                 }
             } else {
                 urlClassLoader = null;
             }
         }
         return urlClassLoader;
     }
 
     /**
      * Checks if properties file for a specfiic external resource bundle does exist.
      * Remembers existence in static map such that filesystem is not checked repeatedly.
      * 
      * <p>This check is required because resource bundles seem to always load if an URLClassLoader
      * could be initialized even if the corresponding properties file in that directory does not 
      * exist. The resulting resource bundle is simply empty then.</p>
      * 
      * <p>This check allows to only load from URLClassLoader, if the corresponding properties file
      * actually exists.</p>
      * 
      * @param bundleName the bundle name
      * @param locale the locale
      * @return true if properties file for resource bundle exists, else false
      */
     private static Boolean externalResourceBundleFileExists(String bundleName, Locale locale) {
         String key = bundleName + "_" + locale.getLanguage();
         if (!propertiesFileExistsMap.containsKey(key)) {
             String directory = ConfigCore.getParameterOrDefaultValue(ParameterCore.DIR_LOCAL_MESSAGES);
             Path path = Paths.get(directory, bundleName + "_" + locale.getLanguage() + ".properties");
             File file = path.toFile();
             
             propertiesFileExistsMap.put(key, file.exists());
 
             if (!file.exists()) {
                 logger.info("Could not find external resource bundle '" + bundleName + "' at " + file);
             }
         }
         return propertiesFileExistsMap.get(key);
     }
 
     /**
      * Loads an external resource bundle (outside jar files) if a corresponding properties file 
      * exists and an URLClassLoader could be build that has the permissions to load files from 
      * that directory.
      * 
      * @param bundleName the bundle name
      * @param locale the locale
      * @return the external resource bundle or null if it does not exist
      */
     private static ResourceBundle getExternalResourceBundle(String bundleName, Locale locale) {
         if (!externalResourceBundleFileExists(bundleName, locale)) {
             return null;
         }
         URLClassLoader urlLoader = getURLClassLoader();
         if (Objects.nonNull(urlLoader)) {
             try {
                 return ResourceBundle.getBundle(bundleName, locale, urlLoader);
             } catch (MissingResourceException e) {
                 logger.error("Could not load external resource bundle '" + bundleName + "': " + e.getMessage());
             }
         }
         return null;
     }
 
     private static ResourceBundle getExternalResourceBundle(String bundleName) {
         Locale locale = LocaleHelper.getCurrentLocale();
         return getExternalResourceBundle(bundleName, locale);
     }
 
     /**
      * Get resource bundle. In case there is a custom version of translation
      * files load them, if not load the default ones.
      * 
      * @param defaultBundleName
      *            name of the default translation bundle
      * @param customBundleName
      *            name of the custom translation bundle
      * @param locale
      *            for which translation bundle should be created
      * @return available translation bundle
      */
     public static ResourceBundle getResourceBundle(String defaultBundleName, String customBundleName, Locale locale) {
         ResourceBundle bundle = getExternalResourceBundle(customBundleName, locale);
         if (Objects.nonNull(bundle)) {
             return bundle;
         }
         return ResourceBundle.getBundle(defaultBundleName, locale);
     }
 
     /**
      * Loads default resource bundle (from inside jar files).
      * @param bundleName the bundle name
      * @return the resource bundle
      */
     protected ResourceBundle getBaseResources(String bundleName) {
         return ResourceBundle.getBundle(bundleName, LocaleHelper.getCurrentLocale());
     }
 
     /**
      * Loads value from external resource bundles (outside jar files).
      * @param key the key of the resource
      * @param bundleName the bundle name
      * @return the value or null if not exists
      */
     protected Object getValueFromExternalResourceBundle(String key, String bundleName) {
         ResourceBundle bundle = getExternalResourceBundle(bundleName);
         if (Objects.nonNull(bundle)) {
             return bundle.getObject(key);
         }
         return null;
     }
 
 }