21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 |
23 |
24 /* |
24 /* |
25 * @test |
25 * @test |
26 * @bug 4777124 6920545 6911753 |
26 * @bug 4777124 6920545 6911753 8073924 |
27 * @summary Verify that all Charset subclasses are available through the API |
27 * @summary Verify that all Charset subclasses are available through the API |
28 */ |
28 */ |
29 |
29 |
30 import java.io.File; |
30 import java.net.URI; |
31 import java.io.FileInputStream; |
|
32 import java.io.FileNotFoundException; |
|
33 import java.io.IOException; |
|
34 import java.nio.charset.Charset; |
31 import java.nio.charset.Charset; |
35 import java.security.AccessController; |
32 import java.nio.file.FileSystem; |
36 import java.security.PrivilegedAction; |
33 import java.nio.file.FileSystems; |
37 import java.util.Collection; |
34 import java.nio.file.Files; |
|
35 import java.nio.file.Path; |
38 import java.util.HashSet; |
36 import java.util.HashSet; |
39 import java.util.Iterator; |
|
40 import java.util.Set; |
37 import java.util.Set; |
41 import java.util.Vector; |
38 import java.util.stream.Collectors; |
42 import java.util.zip.ZipEntry; |
39 import java.util.stream.Stream; |
43 import java.util.zip.ZipInputStream; |
|
44 |
|
45 |
40 |
46 public class NIOCharsetAvailabilityTest { |
41 public class NIOCharsetAvailabilityTest { |
47 |
42 |
48 public static void main(String[] args) throws Exception { |
43 public static void main(String[] args) throws Exception { |
|
44 |
49 // build the set of all Charset subclasses in the |
45 // build the set of all Charset subclasses in the |
50 // two known charset implementation packages |
46 // two known charset implementation packages |
51 Set charsets = new HashSet(); |
47 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); |
52 addCharsets(charsets, "sun.nio.cs"); |
48 Set<Class> charsets = |
53 addCharsets(charsets, "sun.nio.cs.ext"); |
49 Stream.concat(Files.walk(fs.getPath("/java.base/sun/nio/cs/")), |
54 |
50 Files.walk(fs.getPath("/jdk.charsets/sun/nio/cs/ext/"))) |
|
51 .map( p -> p.subpath(1, p.getNameCount()).toString()) |
|
52 .filter( s -> s.indexOf("$") == -1 && s.endsWith(".class")) |
|
53 .map( s -> { |
|
54 try { |
|
55 return Class.forName(s.substring(0, s.length() - 6) |
|
56 .replace('/', '.')); |
|
57 } catch (Exception x) { |
|
58 throw new RuntimeException(x); |
|
59 } |
|
60 }) |
|
61 .filter( clz -> { |
|
62 Class superclazz = clz.getSuperclass(); |
|
63 while (superclazz != null && !superclazz.equals(Object.class)) { |
|
64 if (superclazz.equals(Charset.class)) { |
|
65 return true; |
|
66 } else { |
|
67 superclazz = superclazz.getSuperclass(); |
|
68 } |
|
69 } |
|
70 return false; |
|
71 }) |
|
72 .collect(Collectors.toCollection(HashSet::new)); |
55 // remove the charsets that the API says are available |
73 // remove the charsets that the API says are available |
56 Collection availableCharsets = Charset.availableCharsets().values(); |
74 Charset.availableCharsets() |
57 Iterator iter = availableCharsets.iterator(); |
75 .values() |
58 while (iter.hasNext()) { |
76 .stream() |
59 charsets.remove(((Charset) iter.next()).getClass()); |
77 .forEach(cs -> { |
60 } |
78 if (!charsets.contains(cs.getClass())) { |
|
79 System.out.println(" missing -> " + cs.getClass()); |
|
80 } |
|
81 charsets.remove(cs.getClass()); |
|
82 }); |
61 |
83 |
62 // remove the known pseudo-charsets that serve only to implement |
84 // remove the known pseudo-charsets that serve only to implement |
63 // other charsets, but shouldn't be known to the public |
85 // other charsets, but shouldn't be known to the public |
64 charsets.remove(Class.forName("sun.nio.cs.Unicode")); |
86 charsets.remove(Class.forName("sun.nio.cs.Unicode")); |
65 charsets.remove(Class.forName("sun.nio.cs.ext.ISO2022")); |
87 charsets.remove(Class.forName("sun.nio.cs.ext.ISO2022")); |
74 } catch (ClassNotFoundException x) { |
96 } catch (ClassNotFoundException x) { |
75 // these two might be moved into stdcs |
97 // these two might be moved into stdcs |
76 charsets.remove(Class.forName("sun.nio.cs.JIS_X_0208_Solaris")); |
98 charsets.remove(Class.forName("sun.nio.cs.JIS_X_0208_Solaris")); |
77 charsets.remove(Class.forName("sun.nio.cs.JIS_X_0212_Solaris")); |
99 charsets.remove(Class.forName("sun.nio.cs.JIS_X_0212_Solaris")); |
78 } |
100 } |
79 |
|
80 // report the charsets that are implemented but not available |
101 // report the charsets that are implemented but not available |
81 iter = charsets.iterator(); |
|
82 while (iter.hasNext()) { |
|
83 System.out.println("Unused Charset subclass: " + ((Class) iter.next()).getName()); |
|
84 } |
|
85 if (charsets.size() > 0) { |
102 if (charsets.size() > 0) { |
|
103 charsets.stream() |
|
104 .forEach( clz -> |
|
105 System.out.println("Unused Charset subclass: " + clz)); |
86 throw new RuntimeException(); |
106 throw new RuntimeException(); |
87 } |
107 } |
88 } |
108 } |
89 |
|
90 private static Vector classPathSegments = new Vector(); |
|
91 |
|
92 private static void addCharsets(Set charsets, final String packageName) |
|
93 throws Exception { |
|
94 |
|
95 String classPath = AccessController.doPrivileged( |
|
96 (PrivilegedAction<String>)() -> System.getProperty("sun.boot.class.path")); |
|
97 String s = AccessController.doPrivileged( |
|
98 (PrivilegedAction<String>)() -> System.getProperty("java.class.path")); |
|
99 |
|
100 // Search combined system and application class path |
|
101 if (s != null && s.length() != 0) { |
|
102 classPath += File.pathSeparator + s; |
|
103 } |
|
104 while (classPath != null && classPath.length() != 0) { |
|
105 int i = classPath.lastIndexOf(java.io.File.pathSeparatorChar); |
|
106 String dir = classPath.substring(i + 1); |
|
107 if (i == -1) { |
|
108 classPath = null; |
|
109 } else { |
|
110 classPath = classPath.substring(0, i); |
|
111 } |
|
112 classPathSegments.insertElementAt(dir, 0); |
|
113 } |
|
114 |
|
115 String[] classList = (String[]) |
|
116 java.security.AccessController.doPrivileged( |
|
117 new java.security.PrivilegedAction() { |
|
118 public Object run() { |
|
119 return getClassList(packageName, ""); |
|
120 } |
|
121 }); |
|
122 |
|
123 for (int i = 0; i < classList.length; i++) { |
|
124 try { |
|
125 Class clazz = Class.forName(packageName + "." + classList[i]); |
|
126 Class superclazz = clazz.getSuperclass(); |
|
127 while (superclazz != null && !superclazz.equals(Object.class)) { |
|
128 if (superclazz.equals(Charset.class)) { |
|
129 charsets.add(clazz); |
|
130 break; |
|
131 } else { |
|
132 superclazz = superclazz.getSuperclass(); |
|
133 } |
|
134 } |
|
135 } catch (ClassNotFoundException e) { |
|
136 } |
|
137 } |
|
138 } |
|
139 |
|
140 private static final char ZIPSEPARATOR = '/'; |
|
141 |
|
142 /** |
|
143 * Walk through CLASSPATH and find class list from a package. |
|
144 * The class names start with prefix string |
|
145 * @param package name, class name prefix |
|
146 * @return class list in an array of String |
|
147 */ |
|
148 private static String[] getClassList(String pkgName, String prefix) { |
|
149 Vector listBuffer = new Vector(); |
|
150 String packagePath = pkgName.replace('.', File.separatorChar) |
|
151 + File.separatorChar; |
|
152 String zipPackagePath = pkgName.replace('.', ZIPSEPARATOR) |
|
153 + ZIPSEPARATOR; |
|
154 for (int i = 0; i < classPathSegments.size(); i++){ |
|
155 String onePath = (String) classPathSegments.elementAt(i); |
|
156 File f = new File(onePath); |
|
157 if (!f.exists()) |
|
158 continue; |
|
159 if (f.isFile()) |
|
160 scanFile(f, zipPackagePath, listBuffer, prefix); |
|
161 else if (f.isDirectory()) { |
|
162 String fullPath; |
|
163 if (onePath.endsWith(File.separator)) |
|
164 fullPath = onePath + packagePath; |
|
165 else |
|
166 fullPath = onePath + File.separatorChar + packagePath; |
|
167 File dir = new File(fullPath); |
|
168 if (dir.exists() && dir.isDirectory()) |
|
169 scanDir(dir, listBuffer, prefix); |
|
170 } |
|
171 } |
|
172 String[] classNames = new String[listBuffer.size()]; |
|
173 listBuffer.copyInto(classNames); |
|
174 return classNames; |
|
175 } |
|
176 |
|
177 private static void addClass (String className, Vector listBuffer, String prefix) { |
|
178 if (className != null && className.startsWith(prefix) |
|
179 && !listBuffer.contains(className)) |
|
180 listBuffer.addElement(className); |
|
181 } |
|
182 |
|
183 private static String midString(String str, String pre, String suf) { |
|
184 String midStr; |
|
185 if (str.startsWith(pre) && str.endsWith(suf)) |
|
186 midStr = str.substring(pre.length(), str.length() - suf.length()); |
|
187 else |
|
188 midStr = null; |
|
189 return midStr; |
|
190 } |
|
191 |
|
192 private static void scanDir(File dir, Vector listBuffer, String prefix) { |
|
193 String[] fileList = dir.list(); |
|
194 for (int i = 0; i < fileList.length; i++) { |
|
195 addClass(midString(fileList[i], "", ".class"), listBuffer, prefix); |
|
196 } |
|
197 } |
|
198 |
|
199 private static void scanFile(File f, String packagePath, Vector listBuffer, |
|
200 String prefix) { |
|
201 try { |
|
202 ZipInputStream zipFile = new ZipInputStream(new FileInputStream(f)); |
|
203 ZipEntry entry; |
|
204 while ((entry = zipFile.getNextEntry()) != null) { |
|
205 String eName = entry.getName(); |
|
206 if (eName.startsWith(packagePath)) { |
|
207 if (eName.endsWith(".class")) { |
|
208 addClass(midString(eName, packagePath, ".class"), |
|
209 listBuffer, prefix); |
|
210 } |
|
211 } |
|
212 } |
|
213 } catch (FileNotFoundException e) { |
|
214 System.out.println("file not found:" + e); |
|
215 } catch (IOException e) { |
|
216 System.out.println("file IO Exception:" + e); |
|
217 } catch (Exception e) { |
|
218 System.out.println("Exception:" + e); |
|
219 } |
|
220 } |
|
221 } |
109 } |