CheckResourceKeys.java revision 3294:9adfb22ff08f
1135332Sglebius/* 2219182Sglebius * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. 3143923Sglebius * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4135332Sglebius * 5135332Sglebius * This code is free software; you can redistribute it and/or modify it 6135332Sglebius * under the terms of the GNU General Public License version 2 only, as 7135332Sglebius * published by the Free Software Foundation. 8135332Sglebius * 9135332Sglebius * This code is distributed in the hope that it will be useful, but WITHOUT 10135332Sglebius * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11135332Sglebius * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12135332Sglebius * version 2 for more details (a copy is included in the LICENSE file that 13135332Sglebius * accompanied this code). 14135332Sglebius * 15135332Sglebius * You should have received a copy of the GNU General Public License version 16135332Sglebius * 2 along with this work; if not, write to the Free Software Foundation, 17135332Sglebius * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18135332Sglebius * 19135332Sglebius * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20135332Sglebius * or visit www.oracle.com if you need additional information or have any 21135332Sglebius * questions. 22135332Sglebius */ 23135332Sglebius 24135332Sglebius/* 25135332Sglebius * @test 26135332Sglebius * @bug 8000612 27135332Sglebius * @summary need test program to validate javadoc resource bundles 28135332Sglebius * @modules jdk.jdeps/com.sun.tools.classfile 29135332Sglebius */ 30135332Sglebius 31135332Sglebiusimport java.io.*; 32135332Sglebiusimport java.lang.reflect.Layer; 33135332Sglebiusimport java.lang.reflect.Module; 34135332Sglebiusimport java.util.*; 35135332Sglebiusimport javax.tools.*; 36223787Sglebiusimport com.sun.tools.classfile.*; 37241446Smelifaro 38135332Sglebius/** 39167990Sglebius * Compare string constants in javadoc classes against keys in javadoc resource bundles. 40135332Sglebius */ 41135332Sglebiuspublic class CheckResourceKeys { 42135332Sglebius /** 43135332Sglebius * Main program. 44143988Sglebius * Options: 45135332Sglebius * -finddeadkeys 46219182Sglebius * look for keys in resource bundles that are no longer required 47135332Sglebius * -findmissingkeys 48219182Sglebius * look for keys in resource bundles that are missing 49219182Sglebius * 50219182Sglebius * @throws Exception if invoked by jtreg and errors occur 51135332Sglebius */ 52135332Sglebius public static void main(String... args) throws Exception { 53154267Sglebius CheckResourceKeys c = new CheckResourceKeys(); 54154267Sglebius if (c.run(args)) 55154267Sglebius return; 56154267Sglebius 57154267Sglebius if (is_jtreg()) 58154267Sglebius throw new Exception(c.errors + " errors occurred"); 59183693Smav else 60219182Sglebius System.exit(1); 61219182Sglebius } 62241446Smelifaro 63135332Sglebius static boolean is_jtreg() { 64135332Sglebius return (System.getProperty("test.src") != null); 65135332Sglebius } 66135332Sglebius 67219182Sglebius /** 68219182Sglebius * Main entry point. 69219182Sglebius */ 70219182Sglebius boolean run(String... args) throws Exception { 71219182Sglebius boolean findDeadKeys = false; 72219182Sglebius boolean findMissingKeys = false; 73219182Sglebius 74219182Sglebius if (args.length == 0) { 75146139Sglebius if (is_jtreg()) { 76219182Sglebius findDeadKeys = true; 77146139Sglebius findMissingKeys = true; 78146139Sglebius } else { 79219182Sglebius System.err.println("Usage: java CheckResourceKeys <options>"); 80219182Sglebius System.err.println("where options include"); 81219182Sglebius System.err.println(" -finddeadkeys find keys in resource bundles which are no longer required"); 82146139Sglebius System.err.println(" -findmissingkeys find keys in resource bundles that are required but missing"); 83146139Sglebius return true; 84146139Sglebius } 85146139Sglebius } else { 86135332Sglebius for (String arg: args) { 87135332Sglebius if (arg.equalsIgnoreCase("-finddeadkeys")) 88135332Sglebius findDeadKeys = true; 89135332Sglebius else if (arg.equalsIgnoreCase("-findmissingkeys")) 90135332Sglebius findMissingKeys = true; 91135332Sglebius else 92135332Sglebius error("bad option: " + arg); 93249400Sglebius } 94183693Smav } 95135332Sglebius 96135332Sglebius if (errors > 0) 97135332Sglebius return false; 98135332Sglebius 99135332Sglebius Set<String> codeKeys = getCodeKeys(); 100135332Sglebius Set<String> resourceKeys = getResourceKeys(); 101249400Sglebius 102135332Sglebius System.err.println("found " + codeKeys.size() + " keys in code"); 103135332Sglebius System.err.println("found " + resourceKeys.size() + " keys in resource bundles"); 104135332Sglebius 105135332Sglebius if (findDeadKeys) 106249400Sglebius findDeadKeys(codeKeys, resourceKeys); 107249400Sglebius 108135332Sglebius if (findMissingKeys) 109135332Sglebius findMissingKeys(codeKeys, resourceKeys); 110135332Sglebius 111135332Sglebius return (errors == 0); 112135332Sglebius } 113135332Sglebius 114135332Sglebius /** 115135332Sglebius * Find keys in resource bundles which are probably no longer required. 116237227Smelifaro * A key is required if there is a string in the code that is a resource key, 117237227Smelifaro * or if the key is well-known according to various pragmatic rules. 118237227Smelifaro */ 119237227Smelifaro void findDeadKeys(Set<String> codeKeys, Set<String> resourceKeys) { 120237227Smelifaro for (String rk: resourceKeys) { 121237227Smelifaro if (codeKeys.contains(rk)) 122183693Smav continue; 123237227Smelifaro 124237227Smelifaro error("Resource key not found in code: " + rk); 125237227Smelifaro } 126237227Smelifaro } 127183693Smav 128183693Smav /** 129249400Sglebius * For all strings in the code that look like they might be 130249400Sglebius * a resource key, verify that a key exists. 131183693Smav */ 132183693Smav void findMissingKeys(Set<String> codeKeys, Set<String> resourceKeys) { 133219182Sglebius for (String ck: codeKeys) { 134219182Sglebius if (resourceKeys.contains(ck)) 135219182Sglebius continue; 136219182Sglebius error("No resource for \"" + ck + "\""); 137219182Sglebius } 138219182Sglebius } 139219182Sglebius 140219182Sglebius /** 141219182Sglebius * Get the set of strings from (most of) the javadoc classfiles. 142219182Sglebius */ 143219182Sglebius Set<String> getCodeKeys() throws IOException { 144223787Sglebius Set<String> results = new TreeSet<String>(); 145223787Sglebius JavaCompiler c = ToolProvider.getSystemJavaCompiler(); 146223787Sglebius try (JavaFileManager fm = c.getStandardFileManager(null, null, null)) { 147223787Sglebius JavaFileManager.Location javadocLoc = findJavadocLocation(fm); 148249400Sglebius String[] pkgs = { 149223787Sglebius "com.sun.tools.doclets", 150223787Sglebius "com.sun.tools.javadoc" 151219182Sglebius }; 152241446Smelifaro for (String pkg: pkgs) { 153241446Smelifaro for (JavaFileObject fo: fm.list(javadocLoc, 154241446Smelifaro pkg, EnumSet.of(JavaFileObject.Kind.CLASS), true)) { 155241446Smelifaro String name = fo.getName(); 156241446Smelifaro // ignore resource files 157241446Smelifaro if (name.matches(".*resources.[A-Za-z_0-9]+\\.class.*")) 158241446Smelifaro continue; 159223787Sglebius scan(fo, results); 160223787Sglebius } 161223787Sglebius } 162223787Sglebius 163223787Sglebius // special handling for code strings synthesized in 164223787Sglebius // com.sun.tools.doclets.internal.toolkit.util.Util.getTypeName 165135332Sglebius String[] extras = { 166135332Sglebius "AnnotationType", "Class", "Enum", "Error", "Exception", "Interface" 167249400Sglebius }; 168219182Sglebius for (String s: extras) { 169135332Sglebius if (results.contains("doclet." + s)) 170135332Sglebius results.add("doclet." + s.toLowerCase()); 171135332Sglebius } 172135332Sglebius 173135332Sglebius // special handling for code strings synthesized in 174135332Sglebius // com.sun.tools.javadoc.Messager 175135332Sglebius results.add("javadoc.error.msg"); 176135332Sglebius results.add("javadoc.note.msg"); 177135332Sglebius results.add("javadoc.note.pos.msg"); 178135332Sglebius results.add("javadoc.warning.msg"); 179135332Sglebius 180135332Sglebius return results; 181135332Sglebius } 182135332Sglebius } 183135332Sglebius 184135332Sglebius // depending on how the test is run, javadoc may be on bootclasspath or classpath 185135332Sglebius JavaFileManager.Location findJavadocLocation(JavaFileManager fm) { 186135332Sglebius JavaFileManager.Location[] locns = 187135332Sglebius { StandardLocation.PLATFORM_CLASS_PATH, StandardLocation.CLASS_PATH }; 188219182Sglebius try { 189219182Sglebius for (JavaFileManager.Location l: locns) { 190249400Sglebius JavaFileObject fo = fm.getJavaFileForInput(l, 191219182Sglebius "com.sun.tools.javadoc.Main", JavaFileObject.Kind.CLASS); 192219182Sglebius if (fo != null) { 193219182Sglebius System.err.println("found javadoc in " + l); 194219182Sglebius return l; 195219182Sglebius } 196219182Sglebius } 197219182Sglebius } catch (IOException e) { 198219182Sglebius throw new Error(e); 199219182Sglebius } 200219182Sglebius throw new IllegalStateException("Cannot find javadoc"); 201219182Sglebius } 202219182Sglebius 203219182Sglebius /** 204219182Sglebius * Get the set of strings from a class file. 205219182Sglebius * Only strings that look like they might be a resource key are returned. 206219182Sglebius */ 207219182Sglebius void scan(JavaFileObject fo, Set<String> results) throws IOException { 208219182Sglebius //System.err.println("scan " + fo.getName()); 209219182Sglebius InputStream in = fo.openInputStream(); 210219182Sglebius try { 211219182Sglebius ClassFile cf = ClassFile.read(in); 212219182Sglebius for (ConstantPool.CPInfo cpinfo: cf.constant_pool.entries()) { 213219182Sglebius if (cpinfo.getTag() == ConstantPool.CONSTANT_Utf8) { 214219182Sglebius String v = ((ConstantPool.CONSTANT_Utf8_info) cpinfo).value; 215219182Sglebius if (v.matches("(doclet|main|javadoc|tag)\\.[A-Za-z0-9-_.]+")) 216219182Sglebius results.add(v); 217135332Sglebius } 218135332Sglebius } 219135332Sglebius } catch (ConstantPoolException ignore) { 220135332Sglebius } finally { 221135332Sglebius in.close(); 222135332Sglebius } 223135332Sglebius } 224135332Sglebius 225135332Sglebius /** 226135332Sglebius * Get the set of keys from the javadoc resource bundles. 227249400Sglebius */ 228249400Sglebius Set<String> getResourceKeys() { 229249400Sglebius Module jdk_javadoc = Layer.boot().findModule("jdk.javadoc").get(); 230249400Sglebius String[] names = { 231249400Sglebius "com.sun.tools.doclets.formats.html.resources.standard", 232135332Sglebius "com.sun.tools.doclets.internal.toolkit.resources.doclets", 233135332Sglebius "com.sun.tools.javadoc.resources.javadoc", 234249400Sglebius }; 235249400Sglebius Set<String> results = new TreeSet<String>(); 236249400Sglebius for (String name : names) { 237249400Sglebius ResourceBundle b = ResourceBundle.getBundle(name, jdk_javadoc); 238249400Sglebius results.addAll(b.keySet()); 239135332Sglebius } 240135332Sglebius return results; 241219182Sglebius } 242219182Sglebius 243219182Sglebius /** 244219182Sglebius * Report an error. 245249400Sglebius */ 246249400Sglebius void error(String msg) { 247219182Sglebius System.err.println("Error: " + msg); 248249400Sglebius errors++; 249249400Sglebius } 250219182Sglebius 251219182Sglebius int errors; 252249400Sglebius} 253249400Sglebius