8055463: Need public API allowing full access to font collections in Font.createFont()
Reviewed-by: serb, vadim
--- a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java Tue Mar 22 13:10:07 2016 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java Tue Mar 22 14:46:48 2016 -0700
@@ -142,94 +142,6 @@
}
}
- @Override
- public Font2D createFont2D(File fontFile, int fontFormat, boolean isCopy, CreatedFontTracker tracker) throws FontFormatException {
-
- String fontFilePath = fontFile.getPath();
- Font2D font2D = null;
- final File fFile = fontFile;
- final CreatedFontTracker _tracker = tracker;
- try {
- switch (fontFormat) {
- case Font.TRUETYPE_FONT:
- font2D = new TrueTypeFont(fontFilePath, null, 0, true);
- break;
- case Font.TYPE1_FONT:
- font2D = new Type1Font(fontFilePath, null, isCopy);
- break;
- default:
- throw new FontFormatException("Unrecognised Font Format");
- }
- } catch (FontFormatException e) {
- if (isCopy) {
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<Object>() {
- public Object run() {
- if (_tracker != null) {
- _tracker.subBytes((int)fFile.length());
- }
- fFile.delete();
- return null;
- }
- });
- }
- throw(e);
- }
- if (isCopy) {
- FileFont.setFileToRemove(font2D, fontFile, tracker);
- synchronized (FontManager.class) {
-
- if (tmpFontFiles == null) {
- tmpFontFiles = new Vector<File>();
- }
- tmpFontFiles.add(fontFile);
-
- if (fileCloser == null) {
- final Runnable fileCloserRunnable = new Runnable() {
- public void run() {
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<Object>() {
- public Object run() {
-
- for (int i=0;i<CHANNELPOOLSIZE;i++) {
- if (fontFileCache[i] != null) {
- try {
- fontFileCache[i].close();
- } catch (Exception e) {}
- }
- }
- if (tmpFontFiles != null) {
- File[] files = new File[tmpFontFiles.size()];
- files = tmpFontFiles.toArray(files);
- for (int f=0; f<files.length;f++) {
- try {
- files[f].delete();
- } catch (Exception e) {}
- }
- }
- return null;
- }
- });
- }
- };
- AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
- /* The thread must be a member of a thread group
- * which will not get GCed before VM exit.
- * Make its parent the top-level thread group.
- */
- ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup();
- fileCloser = new ManagedLocalsThread(rootTG, fileCloserRunnable);
- fileCloser.setContextClassLoader(null);
- Runtime.getRuntime().addShutdownHook(fileCloser);
- return null;
- }
- );
- }
- }
- }
- return font2D;
- }
-
protected void registerFontsInDir(String dirName, boolean useJavaRasterizer, int fontRank, boolean defer, boolean resolveSymLinks) {
loadNativeDirFonts(dirName);
super.registerFontsInDir(dirName, useJavaRasterizer, fontRank, defer, resolveSymLinks);
--- a/jdk/src/java.desktop/share/classes/java/awt/Font.java Tue Mar 22 13:10:07 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/java/awt/Font.java Tue Mar 22 14:46:48 2016 -0700
@@ -611,8 +611,9 @@
* so that when the Font2D is GC'd it can also remove the file.
*/
FontManager fm = FontManagerFactory.getInstance();
- this.font2DHandle = fm.createFont2D(fontFile, fontFormat, isCopy,
- tracker).handle;
+ Font2D[] fonts =
+ fm.createFont2D(fontFile, fontFormat, false, isCopy, tracker);
+ this.font2DHandle = fonts[0].handle;
this.name = this.font2DHandle.font2D.getFontName(Locale.getDefault());
this.style = Font.PLAIN;
this.size = 1;
@@ -841,6 +842,132 @@
return hasPerm;
}
+
+ /**
+ * Returns a new array of {@code Font} decoded from the specified stream.
+ * The returned {@code Font[]} will have at least one element.
+ * <p>
+ * The explicit purpose of this variation on the
+ * {@code createFont(int, InputStream)} method is to support font
+ * sources which represent a TrueType/OpenType font collection and
+ * be able to return all individual fonts in that collection.
+ * Consequently this method will throw {@code FontFormatException}
+ * if the data source does not contain at least one TrueType/OpenType
+ * font. The same exception will also be thrown if any of the fonts in
+ * the collection does not contain the required font tables.
+ * <p>
+ * The condition "at least one", allows for the stream to represent
+ * a single OpenType/TrueType font. That is, it does not have to be
+ * a collection.
+ * Each {@code Font} element of the returned array is
+ * created with a point size of 1 and style {@link #PLAIN PLAIN}.
+ * This base font can then be used with the {@code deriveFont}
+ * methods in this class to derive new {@code Font} objects with
+ * varying sizes, styles, transforms and font features.
+ * <p>This method does not close the {@link InputStream}.
+ * <p>
+ * To make each {@code Font} available to Font constructors it
+ * must be registered in the {@code GraphicsEnvironment} by calling
+ * {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}.
+ * @param fontStream an {@code InputStream} object representing the
+ * input data for the font or font collection.
+ * @return a new {@code Font[]}.
+ * @throws FontFormatException if the {@code fontStream} data does
+ * not contain the required font tables for any of the elements of
+ * the collection, or if it contains no fonts at all.
+ * @throws IOException if the {@code fontStream} cannot be completely read.
+ * @see GraphicsEnvironment#registerFont(Font)
+ * @since 9
+ */
+ public static Font[] createFonts(InputStream fontStream)
+ throws FontFormatException, IOException {
+
+ final int fontFormat = Font.TRUETYPE_FONT;
+ if (hasTempPermission()) {
+ return createFont0(fontFormat, fontStream, true, null);
+ }
+
+ // Otherwise, be extra conscious of pending temp file creation and
+ // resourcefully handle the temp file resources, among other things.
+ CreatedFontTracker tracker = CreatedFontTracker.getTracker();
+ boolean acquired = false;
+ try {
+ acquired = tracker.acquirePermit();
+ if (!acquired) {
+ throw new IOException("Timed out waiting for resources.");
+ }
+ return createFont0(fontFormat, fontStream, true, tracker);
+ } catch (InterruptedException e) {
+ throw new IOException("Problem reading font data.");
+ } finally {
+ if (acquired) {
+ tracker.releasePermit();
+ }
+ }
+ }
+
+ /* used to implement Font.createFont */
+ private Font(Font2D font2D) {
+
+ this.createdFont = true;
+ this.font2DHandle = font2D.handle;
+ this.name = font2D.getFontName(Locale.getDefault());
+ this.style = Font.PLAIN;
+ this.size = 1;
+ this.pointSize = 1f;
+ }
+
+ /**
+ * Returns a new array of {@code Font} decoded from the specified file.
+ * The returned {@code Font[]} will have at least one element.
+ * <p>
+ * The explicit purpose of this variation on the
+ * {@code createFont(int, File)} method is to support font
+ * sources which represent a TrueType/OpenType font collection and
+ * be able to return all individual fonts in that collection.
+ * Consequently this method will throw {@code FontFormatException}
+ * if the data source does not contain at least one TrueType/OpenType
+ * font. The same exception will also be thrown if any of the fonts in
+ * the collection does not contain the required font tables.
+ * <p>
+ * The condition "at least one", allows for the stream to represent
+ * a single OpenType/TrueType font. That is, it does not have to be
+ * a collection.
+ * Each {@code Font} element of the returned array is
+ * created with a point size of 1 and style {@link #PLAIN PLAIN}.
+ * This base font can then be used with the {@code deriveFont}
+ * methods in this class to derive new {@code Font} objects with
+ * varying sizes, styles, transforms and font features.
+ * <p>
+ * To make each {@code Font} available to Font constructors it
+ * must be registered in the {@code GraphicsEnvironment} by calling
+ * {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}.
+ * @param fontFile a {@code File} object containing the
+ * input data for the font or font collection.
+ * @return a new {@code Font[]}.
+ * @throws FontFormatException if the {@code File} does
+ * not contain the required font tables for any of the elements of
+ * the collection, or if it contains no fonts at all.
+ * @throws IOException if the {@code fontFile} cannot be read.
+ * @see GraphicsEnvironment#registerFont(Font)
+ * @since 9
+ */
+ public static Font[] createFonts(File fontFile)
+ throws FontFormatException, IOException
+ {
+ int fontFormat = Font.TRUETYPE_FONT;
+ fontFile = checkFontFile(fontFormat, fontFile);
+ FontManager fm = FontManagerFactory.getInstance();
+ Font2D[] font2DArr =
+ fm.createFont2D(fontFile, fontFormat, true, false, null);
+ int num = font2DArr.length;
+ Font[] fonts = new Font[num];
+ for (int i = 0; i < num; i++) {
+ fonts[i] = new Font(font2DArr[i]);
+ }
+ return fonts;
+ }
+
/**
* Returns a new {@code Font} using the specified font type
* and input data. The new {@code Font} is
@@ -873,7 +1000,7 @@
throws java.awt.FontFormatException, java.io.IOException {
if (hasTempPermission()) {
- return createFont0(fontFormat, fontStream, null);
+ return createFont0(fontFormat, fontStream, false, null)[0];
}
// Otherwise, be extra conscious of pending temp file creation and
@@ -885,7 +1012,7 @@
if (!acquired) {
throw new IOException("Timed out waiting for resources.");
}
- return createFont0(fontFormat, fontStream, tracker);
+ return createFont0(fontFormat, fontStream, false, tracker)[0];
} catch (InterruptedException e) {
throw new IOException("Problem reading font data.");
} finally {
@@ -895,8 +1022,9 @@
}
}
- private static Font createFont0(int fontFormat, InputStream fontStream,
- CreatedFontTracker tracker)
+ private static Font[] createFont0(int fontFormat, InputStream fontStream,
+ boolean allFonts,
+ CreatedFontTracker tracker)
throws java.awt.FontFormatException, java.io.IOException {
if (fontFormat != Font.TRUETYPE_FONT &&
@@ -965,8 +1093,15 @@
* without waiting for the results of that constructor.
*/
copiedFontData = true;
- Font font = new Font(tFile, fontFormat, true, tracker);
- return font;
+ FontManager fm = FontManagerFactory.getInstance();
+ Font2D[] font2DArr =
+ fm.createFont2D(tFile, fontFormat, allFonts, true, tracker);
+ int num = font2DArr.length;
+ Font[] fonts = new Font[num];
+ for (int i = 0; i < num; i++) {
+ fonts[i] = new Font(font2DArr[i]);
+ }
+ return fonts;
} finally {
if (tracker != null) {
tracker.remove(tFile);
@@ -1037,6 +1172,13 @@
public static Font createFont(int fontFormat, File fontFile)
throws java.awt.FontFormatException, java.io.IOException {
+ fontFile = checkFontFile(fontFormat, fontFile);
+ return new Font(fontFile, fontFormat, false, null);
+ }
+
+ private static File checkFontFile(int fontFormat, File fontFile)
+ throws FontFormatException, IOException {
+
fontFile = new File(fontFile.getPath());
if (fontFormat != Font.TRUETYPE_FONT &&
@@ -1052,7 +1194,7 @@
if (!fontFile.canRead()) {
throw new IOException("Can't read " + fontFile);
}
- return new Font(fontFile, fontFormat, false, null);
+ return fontFile;
}
/**
--- a/jdk/src/java.desktop/share/classes/sun/font/FileFont.java Tue Mar 22 13:10:07 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/font/FileFont.java Tue Mar 22 14:46:48 2016 -0700
@@ -36,6 +36,7 @@
import sun.java2d.DisposerRecord;
import java.io.IOException;
+import java.util.List;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
@@ -116,17 +117,17 @@
return true;
}
- void setFileToRemove(File file, CreatedFontTracker tracker) {
- Disposer.addObjectRecord(this,
- new CreatedFontFileDisposerRecord(file, tracker));
- }
+ static void setFileToRemove(List<Font2D> fonts,
+ File file, int cnt,
+ CreatedFontTracker tracker)
+ {
+ CreatedFontFileDisposerRecord dr =
+ new CreatedFontFileDisposerRecord(file, cnt, tracker);
- // MACOSX begin -- Make this static so that we can pass in CFont
- static void setFileToRemove(Object font, File file, CreatedFontTracker tracker) {
- Disposer.addObjectRecord(font,
- new CreatedFontFileDisposerRecord(file, tracker));
+ for (Font2D f : fonts) {
+ Disposer.addObjectRecord(f, dr);
+ }
}
- // MACOSX - end
/* This is called when a font scaler is determined to
* be unusable (ie bad).
@@ -251,11 +252,13 @@
implements DisposerRecord {
File fontFile = null;
+ int count = 0; // number of fonts referencing this file object.
CreatedFontTracker tracker;
- private CreatedFontFileDisposerRecord(File file,
+ private CreatedFontFileDisposerRecord(File file, int cnt,
CreatedFontTracker tracker) {
fontFile = file;
+ count = (cnt > 0) ? cnt : 1;
this.tracker = tracker;
}
@@ -263,6 +266,12 @@
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Object>() {
public Object run() {
+ synchronized (fontFile) {
+ count--;
+ if (count > 0) {
+ return null;
+ }
+ }
if (fontFile != null) {
try {
if (tracker != null) {
--- a/jdk/src/java.desktop/share/classes/sun/font/FontManager.java Tue Mar 22 13:10:07 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/font/FontManager.java Tue Mar 22 14:46:48 2016 -0700
@@ -81,13 +81,15 @@
*
* @param fontFile the file holding the font data
* @param fontFormat the expected font format
+ * @param all whether to retrieve all fonts in the resource or
+ * just the first one.
* @param isCopy {@code true} if the file is a copy and needs to be
* deleted, {@code false} otherwise
*
* @return the created Font2D instance
*/
- public Font2D createFont2D(File fontFile, int fontFormat,
- boolean isCopy, CreatedFontTracker tracker)
+ public Font2D[] createFont2D(File fontFile, int fontFormat, boolean all,
+ boolean isCopy, CreatedFontTracker tracker)
throws FontFormatException;
/**
--- a/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java Tue Mar 22 13:10:07 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java Tue Mar 22 14:46:48 2016 -0700
@@ -40,6 +40,7 @@
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
@@ -2420,15 +2421,15 @@
protected abstract String getFontPath(boolean noType1Fonts);
- // MACOSX begin -- need to access this in subclass
- protected Thread fileCloser = null;
- // MACOSX end
+ Thread fileCloser = null;
Vector<File> tmpFontFiles = null;
- public Font2D createFont2D(File fontFile, int fontFormat,
- boolean isCopy, CreatedFontTracker tracker)
+ public Font2D[] createFont2D(File fontFile, int fontFormat, boolean all,
+ boolean isCopy, CreatedFontTracker tracker)
throws FontFormatException {
+ List<Font2D> fList = new ArrayList<Font2D>();
+ int cnt = 1;
String fontFilePath = fontFile.getPath();
FileFont font2D = null;
final File fFile = fontFile;
@@ -2437,9 +2438,19 @@
switch (fontFormat) {
case Font.TRUETYPE_FONT:
font2D = new TrueTypeFont(fontFilePath, null, 0, true);
+ fList.add(font2D);
+ if (!all) {
+ break;
+ }
+ cnt = ((TrueTypeFont)font2D).getFontCount();
+ int index = 1;
+ while (index < cnt) {
+ fList.add(new TrueTypeFont(fontFilePath, null, index++, true));
+ }
break;
case Font.TYPE1_FONT:
font2D = new Type1Font(fontFilePath, null, isCopy);
+ fList.add(font2D);
break;
default:
throw new FontFormatException("Unrecognised Font Format");
@@ -2460,7 +2471,7 @@
throw(e);
}
if (isCopy) {
- font2D.setFileToRemove(fontFile, tracker);
+ FileFont.setFileToRemove(fList, fontFile, cnt, tracker);
synchronized (FontManager.class) {
if (tmpFontFiles == null) {
@@ -2511,7 +2522,7 @@
}
}
}
- return font2D;
+ return fList.toArray(new Font2D[0]);
}
/* remind: used in X11GraphicsEnvironment and called often enough
--- a/jdk/test/java/awt/FontClass/CreateFont/BigFont.java Tue Mar 22 13:10:07 2016 -0700
+++ b/jdk/test/java/awt/FontClass/CreateFont/BigFont.java Tue Mar 22 14:46:48 2016 -0700
@@ -60,12 +60,16 @@
System.out.println("Applet " + id + " "+
Thread.currentThread().getThreadGroup());
+ if (System.getSecurityManager() == null) {
+ System.setSecurityManager(new SecurityManager());
+ }
// Larger than size for a single font.
int fontSize = 64 * 1000 * 1000;
SizedInputStream sis = new SizedInputStream(fontSize);
try {
Font font = Font.createFont(Font.TRUETYPE_FONT, sis);
} catch (Throwable t) {
+ t.printStackTrace();
if (t instanceof FontFormatException ||
fontSize <= sis.getCurrentSize())
{
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/FontClass/CreateFont/CreateFontArrayTest.java Tue Mar 22 14:46:48 2016 -0700
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8055463
+ * @summary Test createFont APIs
+ * @run CreateFontArrayTest
+ */
+
+import java.awt.Font;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+
+/*
+ * This test pokes around in platform folders/directories to try
+ * to find some fonts with which to test. It will do different things
+ * on different platforms and may not do anything at all if the platform
+ * directories aren't where it expects. For example if /usr/share/fonts
+ * is not used on a particular Linux distro or on Windows the fonts are
+ * not in c:\windows\fonts (which would be the right place on 99.99% of
+ * systems you will find today.
+ * It ought to be very reliable but it is not 100% guaranteed.
+ * Failure to find fonts to test is 'not a product bug'.
+ * Fonts on a system having different content than we expect based on
+ * file extension is also 'not a product bug'.
+ * The former will cause silent success, the latter may cause 'noisy' failure
+ * and the test would then need to be dialled back to be more cautious.
+ */
+
+public class CreateFontArrayTest {
+
+ public static void main(String[] args) throws Exception {
+ test(".ttc", 2, -1, true);
+ test(".ttf", 1, 1, true);
+ test(".otf", 1, 1, true);
+ test(".pfa", 0, 0, false);
+ test(".pfb", 0, 0, false);
+ }
+
+ static File getPlatformFontFolder(String ext) throws Exception {
+ boolean recurse = false;
+ String folder = null;
+ String os = System.getProperty("os.name");
+ if (os.startsWith("Win")) {
+ folder = "c:\\windows\\fonts";
+ } else if (os.startsWith("Linux")) {
+ folder = "/usr/share/fonts";
+ recurse = true; // need to dig to find fonts.
+ } else if (os.startsWith("Mac")) {
+ // Disabled until createFont can handle mac font names.
+ //folder = "/Library/Fonts";
+ }
+ if (folder == null) {
+ return null;
+ }
+ File dir = new File(folder);
+ if (!dir.exists() || !dir.isDirectory()) {
+ return null;
+ }
+ // Have a root.
+ if (!recurse) {
+ return dir;
+ }
+
+ // If "recurse" is set, try to find a sub-folder which contains
+ // fonts with the specified extension
+ return findSubFolder(dir, ext);
+ }
+
+ static File findSubFolder(File folder, String ext) {
+ File[] files =
+ folder.listFiles(f -> f.getName().toLowerCase().endsWith(ext));
+ if (files != null && files.length > 0) {
+ return folder;
+ }
+ File[] subdirs = folder.listFiles(f -> f.isDirectory());
+ for (File f : subdirs) {
+ File subfolder = findSubFolder(f, ext);
+ if (subfolder != null) {
+ return subfolder;
+ }
+ }
+ return null;
+ }
+
+ static void test(String ext, int min, int max,
+ boolean expectSuccess ) throws Exception {
+
+ File dir = getPlatformFontFolder(ext);
+ if (dir == null) {
+ System.out.println("No folder to test for " + ext);
+ return;
+ }
+ File[] files =
+ dir.listFiles(f -> f.getName().toLowerCase().endsWith(ext));
+ if (files == null || files.length == 0) {
+ System.out.println("No files to test for " + ext);
+ return;
+ }
+ System.out.println("Create from file " + files[0]);
+ Font[] fonts = null;
+ try {
+ fonts = Font.createFonts(files[0]);
+ System.out.println("createFont from file returned " + fonts);
+ } catch (Exception e) {
+ if (expectSuccess) {
+ throw new RuntimeException("Unexpected exception", e);
+ } else {
+ System.out.println("Got expected exception " + e);
+ return;
+ }
+ }
+ for (Font f : fonts) {
+ System.out.println(ext + " component : " + f);
+ }
+ if (fonts.length < min) {
+ throw new RuntimeException("Expected at least " + min +
+ " but got " + fonts.length);
+ }
+ if (max > 0 && fonts.length > max) {
+ throw new RuntimeException("Expected no more than " + max +
+ " but got " + fonts.length);
+ }
+ FileInputStream fis = null;
+ try {
+ System.out.println("Create from stream " + files[0]);
+ fis = new FileInputStream(files[0]);
+ InputStream s = new BufferedInputStream(fis);
+ fonts = null;
+ try {
+ fonts = Font.createFonts(s);
+ System.out.println("createFont from stream returned " + fonts);
+ } catch (Exception e) {
+ if (expectSuccess) {
+ throw new RuntimeException("Unexpected exception", e);
+ } else {
+ System.out.println("Got expected exception " + e);
+ return;
+ }
+ }
+ for (Font f : fonts) {
+ System.out.println(ext + " component : " + f);
+ }
+ if (fonts.length < min) {
+ throw new RuntimeException("Expected at least " + min +
+ " but got " + fonts.length);
+ }
+ if (max > 0 && fonts.length > max) {
+ throw new RuntimeException("Expected no more than " + max +
+ " but got " + fonts.length);
+ }
+ } finally {
+ if (fis != null) {
+ fis.close();
+ }
+ }
+ }
+}
--- a/jdk/test/java/awt/font/FontNames/GetLCIDFromLocale.java Tue Mar 22 13:10:07 2016 -0700
+++ b/jdk/test/java/awt/font/FontNames/GetLCIDFromLocale.java Tue Mar 22 14:46:48 2016 -0700
@@ -4,9 +4,7 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
+ * published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or