jdk/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java
changeset 42401 925e4d87ebac
parent 42400 bd7790c39ad8
parent 42395 c80058e8983e
child 42418 4330273ee80c
equal deleted inserted replaced
42400:bd7790c39ad8 42401:925e4d87ebac
     1 /*
       
     2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.util.locale.provider;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.io.InputStream;
       
    30 import java.io.UncheckedIOException;
       
    31 import java.lang.reflect.Constructor;
       
    32 import java.lang.reflect.InvocationTargetException;
       
    33 import java.lang.reflect.Modifier;
       
    34 import java.lang.reflect.Module;
       
    35 import java.security.AccessController;
       
    36 import java.security.PrivilegedAction;
       
    37 import java.util.PropertyResourceBundle;
       
    38 import java.util.ResourceBundle;
       
    39 
       
    40 /**
       
    41  * ResourceBundleProviderSupport provides convenience methods for loading
       
    42  * resource bundles.
       
    43  */
       
    44 public class ResourceBundleProviderSupport {
       
    45     /**
       
    46      * Loads a {@code ResourceBundle} of the given {@code bundleName} local to
       
    47      * the given {@code module}.
       
    48      *
       
    49      * @apiNote
       
    50      * {@link Class#forName(Module, String)} does a stack-based permission check.
       
    51      * Caller of this method is responsible for doing an appropriate permission
       
    52      * on behalf of the caller before calling this method.
       
    53      *
       
    54      * @param module     the module from which the {@code ResourceBundle} is loaded
       
    55      * @param bundleName the bundle name for the {@code ResourceBundle} class,
       
    56      *                   such as "com.example.app.MyResources_fr"
       
    57      * @return the {@code ResourceBundle}, or null if no {@code ResourceBundle} is found
       
    58      * @throws SecurityException
       
    59      *         if a security manager exists, it denies loading the class given by
       
    60      *         {@code bundleName} from the given {@code module}.
       
    61      *         If the given module is "java.base", this method will not do security check.
       
    62      * @throws NullPointerException
       
    63      *         if {@code module} or {@code bundleName) is null
       
    64      * @see Class#forName(Module, String)
       
    65      */
       
    66     public static ResourceBundle loadResourceBundle(Module module, String bundleName)
       
    67     {
       
    68         Class<?> c = Class.forName(module, bundleName);
       
    69         if (c != null && ResourceBundle.class.isAssignableFrom(c)) {
       
    70             try {
       
    71                 @SuppressWarnings("unchecked")
       
    72                 Class<ResourceBundle> bundleClass = (Class<ResourceBundle>) c;
       
    73                 Constructor<ResourceBundle> ctor = bundleClass.getConstructor();
       
    74                 if (!Modifier.isPublic(ctor.getModifiers())) {
       
    75                     return null;
       
    76                 }
       
    77                 // java.base may not be able to read the bundleClass's module.
       
    78                 PrivilegedAction<Void> pa1 = () -> { ctor.setAccessible(true); return null; };
       
    79                 AccessController.doPrivileged(pa1);
       
    80                 try {
       
    81                     return ctor.newInstance((Object[]) null);
       
    82                 } catch (InvocationTargetException e) {
       
    83                     uncheckedThrow(e);
       
    84                 } catch (InstantiationException | IllegalAccessException e) {
       
    85                     throw new InternalError(e);
       
    86                 }
       
    87             } catch (NoSuchMethodException e) {
       
    88             }
       
    89         }
       
    90         return null;
       
    91     }
       
    92 
       
    93     @SuppressWarnings("unchecked")
       
    94     private static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
       
    95        if (t != null)
       
    96             throw (T)t;
       
    97        else
       
    98             throw new Error("Unknown Exception");
       
    99     }
       
   100 
       
   101     /**
       
   102      * Loads properties of the given {@code bundleName} local to the given
       
   103      * {@code module} and returns a {@code ResourceBundle} produced from the
       
   104      * loaded properties.
       
   105      *
       
   106      * @apiNote This method is intended for internal use.  Need to refactor.
       
   107      *
       
   108      * @param module     the module from which the properties are loaded
       
   109      * @param bundleName the bundle name of the properties,
       
   110      *                   such as "com.example.app.MyResources_de"
       
   111      * @return the {@code ResourceBundle} produced from the loaded properties,
       
   112      *         or null if no properties are found
       
   113      * @see PropertyResourceBundle
       
   114      */
       
   115     public static ResourceBundle loadPropertyResourceBundle(Module module, String bundleName)
       
   116             throws IOException
       
   117     {
       
   118         String resourceName = toResourceName(bundleName, "properties");
       
   119         if (resourceName == null) {
       
   120             return null;
       
   121         }
       
   122 
       
   123         PrivilegedAction<InputStream> pa = () -> {
       
   124             try {
       
   125                 return module.getResourceAsStream(resourceName);
       
   126             } catch (IOException e) {
       
   127                 throw new UncheckedIOException(e);
       
   128             }
       
   129         };
       
   130         try (InputStream stream = AccessController.doPrivileged(pa)) {
       
   131             if (stream != null) {
       
   132                 return new PropertyResourceBundle(stream);
       
   133             } else {
       
   134                 return null;
       
   135             }
       
   136         } catch (UncheckedIOException e) {
       
   137             throw e.getCause();
       
   138         }
       
   139     }
       
   140 
       
   141     private static String toResourceName(String bundleName, String suffix) {
       
   142         if (bundleName.contains("://")) {
       
   143             return null;
       
   144         }
       
   145         StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
       
   146         sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
       
   147         return sb.toString();
       
   148     }
       
   149 }