1 /* 2 * Copyright (c) 2015, 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 import jdk.internal.misc.BootLoader; 41 import sun.misc.Unsafe; 42 43 44 /** 45 * ResourceBundleProviderSupport provides convenience methods for loading 46 * resource bundles. 47 */ 48 public class ResourceBundleProviderSupport { 49 /** 50 * Loads a {@code ResourceBundle} of the given {@code bundleName} local to 51 * the given {@code module}. 52 * 53 * @param module the module from which the {@code ResourceBundle} is loaded 54 * @param bundleName the bundle name for the {@code ResourceBundle} class, 55 * such as "com.example.app.MyResources_fr" 56 * @return the {@code ResourceBundle}, or null if no {@code ResourceBundle} is found 57 */ 58 public static ResourceBundle loadResourceBundle(Module module, String bundleName) 59 { 60 // TODO: security permission check to access a bundle in another module? 61 PrivilegedAction<Class<?>> pa = () -> Class.forName(module, bundleName); 62 Class<?> c = AccessController.doPrivileged(pa); 63 if (c != null && ResourceBundle.class.isAssignableFrom(c)) { 64 try { 65 @SuppressWarnings("unchecked") 66 Class<ResourceBundle> bundleClass = (Class<ResourceBundle>) c; 67 Constructor<ResourceBundle> ctor = bundleClass.getConstructor(); 68 if (!Modifier.isPublic(ctor.getModifiers())) { 69 return null; 70 } 71 72 // java.base may not be able to read the bundleClass's module. 73 PrivilegedAction<Void> pa1 = () -> { ctor.setAccessible(true); return null; }; 74 AccessController.doPrivileged(pa1); 75 try { 76 return ctor.newInstance((Object[]) null); 77 } catch (InvocationTargetException e) { 78 Unsafe.getUnsafe().throwException(e.getTargetException()); 79 } catch (InstantiationException | IllegalAccessException e) { 80 throw new InternalError(e); 81 } 82 } catch (NoSuchMethodException e) { 83 } 84 } 85 return null; 86 } 87 88 /** 89 * Loads properties of the given {@code bundleName} local to the given 90 * {@code module} and returns a {@code ResourceBundle} produced from the 91 * loaded properties. 92 * 93 * @apiNote This method is intended for internal use. Need to refactor. 94 * 95 * @param module the module from which the properties are loaded 96 * @param bundleName the bundle name of the properties, 97 * such as "com.example.app.MyResources_de" 98 * @return the {@code ResourceBundle} produced from the loaded properties, 99 * or null if no properties are found 100 * @see PropertiesResourceBundle 101 */ 102 public static ResourceBundle loadPropertyResourceBundle(Module module, String bundleName) 103 throws IOException 104 { 105 String resourceName = toResourceName(bundleName, "properties"); 106 if (resourceName == null) { 107 return null; 108 } 109 110 PrivilegedAction<InputStream> pa = () -> { 111 try { 112 return module.getResourceAsStream(resourceName); 113 } catch (IOException e) { 114 throw new UncheckedIOException(e); 115 } 116 }; 117 try (InputStream stream = AccessController.doPrivileged(pa)) { 118 if (stream != null) { 119 return new PropertyResourceBundle(stream); 120 } else { 121 return null; 122 } 123 } catch (UncheckedIOException e) { 124 throw e.getCause(); 125 } 126 } 127 128 private static String toResourceName(String bundleName, String suffix) { 129 if (bundleName.contains("://")) { 130 return null; 131 } 132 StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length()); 133 sb.append(bundleName.replace('.', '/')).append('.').append(suffix); 134 return sb.toString(); 135 } 136 }