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 java.nio.charset;
27
28 import java.nio.ByteBuffer;
29 import java.nio.CharBuffer;
30 import java.nio.charset.spi.CharsetProvider;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import java.util.Collections;
34 import java.util.HashSet;
35 import java.util.Iterator;
36 import java.util.Locale;
37 import java.util.Map;
38 import java.util.NoSuchElementException;
39 import java.util.Set;
40 import java.util.ServiceLoader;
41 import java.util.ServiceConfigurationError;
42 import java.util.SortedMap;
43 import java.util.TreeMap;
44 import sun.misc.ASCIICaseInsensitiveComparator;
45 import sun.nio.cs.StandardCharsets;
46 import sun.nio.cs.ThreadLocalCoders;
47 import sun.security.action.GetPropertyAction;
48
49
50 /**
51 * A named mapping between sequences of sixteen-bit Unicode <a
52 * href="../../lang/Character.html#unicode">code units</a> and sequences of
319 /* The standard set of charsets */
320 private static CharsetProvider standardProvider = new StandardCharsets();
321
322 // Cache of the most-recently-returned charsets,
323 // along with the names that were used to find them
324 //
325 private static volatile Object[] cache1 = null; // "Level 1" cache
326 private static volatile Object[] cache2 = null; // "Level 2" cache
327
328 private static void cache(String charsetName, Charset cs) {
329 cache2 = cache1;
330 cache1 = new Object[] { charsetName, cs };
331 }
332
333 // Creates an iterator that walks over the available providers, ignoring
334 // those whose lookup or instantiation causes a security exception to be
335 // thrown. Should be invoked with full privileges.
336 //
337 private static Iterator<CharsetProvider> providers() {
338 return new Iterator<>() {
339
340 ClassLoader cl = ClassLoader.getSystemClassLoader();
341 ServiceLoader<CharsetProvider> sl =
342 ServiceLoader.load(CharsetProvider.class, cl);
343 Iterator<CharsetProvider> i = sl.iterator();
344
345 CharsetProvider next = null;
346
347 private boolean getNext() {
348 while (next == null) {
349 try {
350 if (!i.hasNext())
351 return false;
352 next = i.next();
353 } catch (ServiceConfigurationError sce) {
354 if (sce.getCause() instanceof SecurityException) {
355 // Ignore security exceptions
356 continue;
357 }
358 throw sce;
359 }
360 }
361 return true;
362 }
363
364 public boolean hasNext() {
407 new PrivilegedAction<>() {
408 public Charset run() {
409 for (Iterator<CharsetProvider> i = providers();
410 i.hasNext();) {
411 CharsetProvider cp = i.next();
412 Charset cs = cp.charsetForName(charsetName);
413 if (cs != null)
414 return cs;
415 }
416 return null;
417 }
418 });
419
420 } finally {
421 gate.set(null);
422 }
423 }
424
425 /* The extended set of charsets */
426 private static class ExtendedProviderHolder {
427 static final CharsetProvider extendedProvider = extendedProvider();
428 // returns ExtendedProvider, if installed
429 private static CharsetProvider extendedProvider() {
430 return AccessController.doPrivileged(
431 new PrivilegedAction<>() {
432 public CharsetProvider run() {
433 try {
434 Class<?> epc
435 = Class.forName("sun.nio.cs.ext.ExtendedCharsets");
436 return (CharsetProvider)epc.newInstance();
437 } catch (ClassNotFoundException x) {
438 // Extended charsets not available
439 // (charsets.jar not present)
440 } catch (InstantiationException |
441 IllegalAccessException x) {
442 throw new Error(x);
443 }
444 return null;
445 }
446 });
447 }
448 }
449
450 private static Charset lookupExtendedCharset(String charsetName) {
451 CharsetProvider ecp = ExtendedProviderHolder.extendedProvider;
452 return (ecp != null) ? ecp.charsetForName(charsetName) : null;
453 }
454
455 private static Charset lookup(String charsetName) {
456 if (charsetName == null)
457 throw new IllegalArgumentException("Null charset name");
458 Object[] a;
459 if ((a = cache1) != null && charsetName.equals(a[0]))
460 return (Charset)a[1];
461 // We expect most programs to use one Charset repeatedly.
462 // We convey a hint to this effect to the VM by putting the
463 // level 1 cache miss code in a separate method.
464 return lookup2(charsetName);
465 }
466
467 private static Charset lookup2(String charsetName) {
468 Object[] a;
469 if ((a = cache2) != null && charsetName.equals(a[0])) {
470 cache2 = cache1;
471 cache1 = a;
472 return (Charset)a[1];
559 * forName} method, which instead employs an efficient incremental lookup
560 * algorithm.
561 *
562 * <p> This method may return different results at different times if new
563 * charset providers are dynamically made available to the current Java
564 * virtual machine. In the absence of such changes, the charsets returned
565 * by this method are exactly those that can be retrieved via the {@link
566 * #forName forName} method. </p>
567 *
568 * @return An immutable, case-insensitive map from canonical charset names
569 * to charset objects
570 */
571 public static SortedMap<String,Charset> availableCharsets() {
572 return AccessController.doPrivileged(
573 new PrivilegedAction<>() {
574 public SortedMap<String,Charset> run() {
575 TreeMap<String,Charset> m =
576 new TreeMap<>(
577 ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
578 put(standardProvider.charsets(), m);
579 CharsetProvider ecp = ExtendedProviderHolder.extendedProvider;
580 if (ecp != null)
581 put(ecp.charsets(), m);
582 for (Iterator<CharsetProvider> i = providers(); i.hasNext();) {
583 CharsetProvider cp = i.next();
584 put(cp.charsets(), m);
585 }
586 return Collections.unmodifiableSortedMap(m);
587 }
588 });
589 }
590
591 private static volatile Charset defaultCharset;
592
593 /**
594 * Returns the default charset of this Java virtual machine.
595 *
596 * <p> The default charset is determined during virtual-machine startup and
597 * typically depends upon the locale and charset of the underlying
598 * operating system.
599 *
600 * @return A charset object for the default charset
601 *
|
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 java.nio.charset;
27
28 import java.nio.ByteBuffer;
29 import java.nio.CharBuffer;
30 import java.nio.charset.spi.CharsetProvider;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import java.util.Arrays;
34 import java.util.Collections;
35 import java.util.HashSet;
36 import java.util.Iterator;
37 import java.util.Locale;
38 import java.util.Map;
39 import java.util.NoSuchElementException;
40 import java.util.Set;
41 import java.util.ServiceLoader;
42 import java.util.ServiceConfigurationError;
43 import java.util.SortedMap;
44 import java.util.TreeMap;
45 import sun.misc.ASCIICaseInsensitiveComparator;
46 import sun.nio.cs.StandardCharsets;
47 import sun.nio.cs.ThreadLocalCoders;
48 import sun.security.action.GetPropertyAction;
49
50
51 /**
52 * A named mapping between sequences of sixteen-bit Unicode <a
53 * href="../../lang/Character.html#unicode">code units</a> and sequences of
320 /* The standard set of charsets */
321 private static CharsetProvider standardProvider = new StandardCharsets();
322
323 // Cache of the most-recently-returned charsets,
324 // along with the names that were used to find them
325 //
326 private static volatile Object[] cache1 = null; // "Level 1" cache
327 private static volatile Object[] cache2 = null; // "Level 2" cache
328
329 private static void cache(String charsetName, Charset cs) {
330 cache2 = cache1;
331 cache1 = new Object[] { charsetName, cs };
332 }
333
334 // Creates an iterator that walks over the available providers, ignoring
335 // those whose lookup or instantiation causes a security exception to be
336 // thrown. Should be invoked with full privileges.
337 //
338 private static Iterator<CharsetProvider> providers() {
339 return new Iterator<>() {
340 ClassLoader cl = ClassLoader.getSystemClassLoader();
341 ServiceLoader<CharsetProvider> sl =
342 ServiceLoader.load(CharsetProvider.class, cl);
343 Iterator<CharsetProvider> i = sl.iterator();
344 CharsetProvider next = null;
345
346 private boolean getNext() {
347 while (next == null) {
348 try {
349 if (!i.hasNext())
350 return false;
351 next = i.next();
352 } catch (ServiceConfigurationError sce) {
353 if (sce.getCause() instanceof SecurityException) {
354 // Ignore security exceptions
355 continue;
356 }
357 throw sce;
358 }
359 }
360 return true;
361 }
362
363 public boolean hasNext() {
406 new PrivilegedAction<>() {
407 public Charset run() {
408 for (Iterator<CharsetProvider> i = providers();
409 i.hasNext();) {
410 CharsetProvider cp = i.next();
411 Charset cs = cp.charsetForName(charsetName);
412 if (cs != null)
413 return cs;
414 }
415 return null;
416 }
417 });
418
419 } finally {
420 gate.set(null);
421 }
422 }
423
424 /* The extended set of charsets */
425 private static class ExtendedProviderHolder {
426 static final CharsetProvider[] extendedProviders = extendedProviders();
427 // returns ExtendedProvider, if installed
428 private static CharsetProvider[] extendedProviders() {
429 return AccessController.doPrivileged(new PrivilegedAction<>() {
430 public CharsetProvider[] run() {
431 CharsetProvider[] cps = new CharsetProvider[1];
432 int n = 0;
433 ServiceLoader<CharsetProvider> sl =
434 ServiceLoader.loadInstalled(CharsetProvider.class);
435 for (CharsetProvider cp : sl) {
436 if (n + 1 > cps.length) {
437 cps = Arrays.copyOf(cps, cps.length << 1);
438 }
439 cps[n++] = cp;
440 }
441 return n == cps.length ? cps : Arrays.copyOf(cps, n);
442 }});
443 }
444 }
445
446 private static Charset lookupExtendedCharset(String charsetName) {
447 if (!sun.misc.VM.isBooted()) // see lookupViaProviders()
448 return null;
449 CharsetProvider[] ecps = ExtendedProviderHolder.extendedProviders;
450 for (CharsetProvider cp : ecps) {
451 Charset cs = cp.charsetForName(charsetName);
452 if (cs != null)
453 return cs;
454 }
455 return null;
456 }
457
458 private static Charset lookup(String charsetName) {
459 if (charsetName == null)
460 throw new IllegalArgumentException("Null charset name");
461 Object[] a;
462 if ((a = cache1) != null && charsetName.equals(a[0]))
463 return (Charset)a[1];
464 // We expect most programs to use one Charset repeatedly.
465 // We convey a hint to this effect to the VM by putting the
466 // level 1 cache miss code in a separate method.
467 return lookup2(charsetName);
468 }
469
470 private static Charset lookup2(String charsetName) {
471 Object[] a;
472 if ((a = cache2) != null && charsetName.equals(a[0])) {
473 cache2 = cache1;
474 cache1 = a;
475 return (Charset)a[1];
562 * forName} method, which instead employs an efficient incremental lookup
563 * algorithm.
564 *
565 * <p> This method may return different results at different times if new
566 * charset providers are dynamically made available to the current Java
567 * virtual machine. In the absence of such changes, the charsets returned
568 * by this method are exactly those that can be retrieved via the {@link
569 * #forName forName} method. </p>
570 *
571 * @return An immutable, case-insensitive map from canonical charset names
572 * to charset objects
573 */
574 public static SortedMap<String,Charset> availableCharsets() {
575 return AccessController.doPrivileged(
576 new PrivilegedAction<>() {
577 public SortedMap<String,Charset> run() {
578 TreeMap<String,Charset> m =
579 new TreeMap<>(
580 ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
581 put(standardProvider.charsets(), m);
582 CharsetProvider[] ecps = ExtendedProviderHolder.extendedProviders;
583 for (CharsetProvider ecp :ecps) {
584 put(ecp.charsets(), m);
585 }
586 for (Iterator<CharsetProvider> i = providers(); i.hasNext();) {
587 CharsetProvider cp = i.next();
588 put(cp.charsets(), m);
589 }
590 return Collections.unmodifiableSortedMap(m);
591 }
592 });
593 }
594
595 private static volatile Charset defaultCharset;
596
597 /**
598 * Returns the default charset of this Java virtual machine.
599 *
600 * <p> The default charset is determined during virtual-machine startup and
601 * typically depends upon the locale and charset of the underlying
602 * operating system.
603 *
604 * @return A charset object for the default charset
605 *
|