1 /* 2 * Copyright (c) 2009, 2017, 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 jdk.internal.module; 27 28 import java.util.Set; 29 30 /** 31 * Utility class for checking module, package, and class names. 32 */ 33 34 public final class Checks { 35 36 private Checks() { } 37 38 /** 39 * Checks a name to ensure that it's a legal module name. 40 * 41 * @throws IllegalArgumentException if name is null or not a legal 42 * module name 43 */ 44 public static String requireModuleName(String name) { 45 if (name == null) 46 throw new IllegalArgumentException("Null module name"); 47 int next; 48 int off = 0; 49 while ((next = name.indexOf('.', off)) != -1) { 50 String id = name.substring(off, next); 51 if (!isJavaIdentifier(id)) { 52 throw new IllegalArgumentException(name + ": Invalid module name" 53 + ": '" + id + "' is not a Java identifier"); 54 } 55 off = next+1; 56 } 57 String last = name.substring(off); 58 if (!isJavaIdentifier(last)) { 59 throw new IllegalArgumentException(name + ": Invalid module name" 60 + ": '" + last + "' is not a Java identifier"); 61 } 62 return name; 63 } 64 65 /** 66 * Checks a name to ensure that it's a legal package name. 67 * 68 * @throws IllegalArgumentException if name is null or not a legal 69 * package name 70 */ 71 public static String requirePackageName(String name) { 72 return requireTypeName("package name", name); 73 } 74 75 /** 76 * Returns {@code true} if the given name is a legal package name. 77 */ 78 public static boolean isPackageName(String name) { 79 return isTypeName(name); 80 } 81 82 /** 83 * Checks a name to ensure that it's a legal qualified class name 84 * 85 * @throws IllegalArgumentException if name is null or not a legal 86 * qualified class name 87 */ 88 public static String requireServiceTypeName(String name) { 89 return requireQualifiedClassName("service type name", name); 90 } 91 92 /** 93 * Checks a name to ensure that it's a legal qualified class name. 94 * 95 * @throws IllegalArgumentException if name is null or not a legal 96 * qualified class name 97 */ 98 public static String requireServiceProviderName(String name) { 99 return requireQualifiedClassName("service provider name", name); 100 } 101 102 /** 103 * Checks a name to ensure that it's a legal qualified class name in 104 * a named package. 105 * 106 * @throws IllegalArgumentException if name is null or not a legal 107 * qualified class name in a named package 108 */ 109 public static String requireQualifiedClassName(String what, String name) { 110 requireTypeName(what, name); 111 if (name.indexOf('.') == -1) 112 throw new IllegalArgumentException(name + ": is not a qualified name of" 113 + " a Java class in a named package"); 114 return name; 115 } 116 117 /** 118 * Returns {@code true} if the given name is a legal class name. 119 */ 120 public static boolean isClassName(String name) { 121 return isTypeName(name); 122 } 123 124 /** 125 * Returns {@code true} if the given name is a legal type name. 126 */ 127 private static boolean isTypeName(String name) { 128 int next; 129 int off = 0; 130 while ((next = name.indexOf('.', off)) != -1) { 131 String id = name.substring(off, next); 132 if (!isJavaIdentifier(id)) 133 return false; 134 off = next+1; 135 } 136 String last = name.substring(off); 137 return isJavaIdentifier(last); 138 } 139 140 /** 141 * Checks if the given name is a legal type name. 142 * 143 * @throws IllegalArgumentException if name is null or not a legal 144 * type name 145 */ 146 private static String requireTypeName(String what, String name) { 147 if (name == null) 148 throw new IllegalArgumentException("Null " + what); 149 int next; 150 int off = 0; 151 while ((next = name.indexOf('.', off)) != -1) { 152 String id = name.substring(off, next); 153 if (!isJavaIdentifier(id)) { 154 throw new IllegalArgumentException(name + ": Invalid " + what 155 + ": '" + id + "' is not a Java identifier"); 156 } 157 off = next + 1; 158 } 159 String last = name.substring(off); 160 if (!isJavaIdentifier(last)) { 161 throw new IllegalArgumentException(name + ": Invalid " + what 162 + ": '" + last + "' is not a Java identifier"); 163 } 164 return name; 165 } 166 167 /** 168 * Returns true if the given string is a legal Java identifier, 169 * otherwise false. 170 */ 171 private static boolean isJavaIdentifier(String str) { 172 if (str.isEmpty() || RESERVED.contains(str)) 173 return false; 174 175 int first = Character.codePointAt(str, 0); 176 if (!Character.isJavaIdentifierStart(first)) 177 return false; 178 179 int i = Character.charCount(first); 180 while (i < str.length()) { 181 int cp = Character.codePointAt(str, i); 182 if (!Character.isJavaIdentifierPart(cp)) 183 return false; 184 i += Character.charCount(cp); 185 } 186 187 return true; 188 } 189 190 // keywords, boolean and null literals, not allowed in identifiers 191 private static final Set<String> RESERVED = Set.of( 192 "abstract", 193 "assert", 194 "boolean", 195 "break", 196 "byte", 197 "case", 198 "catch", 199 "char", 200 "class", 201 "const", 202 "continue", 203 "default", 204 "do", 205 "double", 206 "else", 207 "enum", 208 "extends", 209 "final", 210 "finally", 211 "float", 212 "for", 213 "goto", 214 "if", 215 "implements", 216 "import", 217 "instanceof", 218 "int", 219 "interface", 220 "long", 221 "native", 222 "new", 223 "package", 224 "private", 225 "protected", 226 "public", 227 "return", 228 "short", 229 "static", 230 "strictfp", 231 "super", 232 "switch", 233 "synchronized", 234 "this", 235 "throw", 236 "throws", 237 "transient", 238 "try", 239 "void", 240 "volatile", 241 "while", 242 "true", 243 "false", 244 "null", 245 "_" 246 ); 247 }