47 import javax.tools.JavaFileManager.Location; |
48 import javax.tools.JavaFileManager.Location; |
48 import javax.tools.JavaFileObject; |
49 import javax.tools.JavaFileObject; |
49 import javax.tools.StandardJavaFileManager; |
50 import javax.tools.StandardJavaFileManager; |
50 import javax.tools.StandardLocation; |
51 import javax.tools.StandardLocation; |
51 import javax.tools.ToolProvider; |
52 import javax.tools.ToolProvider; |
|
53 import jdk.nashorn.internal.runtime.Context; |
52 |
54 |
53 /** |
55 /** |
54 * A helper class to compute properties of a Java package object. Properties of |
56 * A helper class to compute properties of a Java package object. Properties of |
55 * package object are (simple) top level class names in that java package and |
57 * package object are (simple) top level class names in that java package and |
56 * immediate subpackages of that package. |
58 * immediate subpackages of that package. |
70 */ |
72 */ |
71 private static boolean isJavacAvailable() { |
73 private static boolean isJavacAvailable() { |
72 return compiler != null; |
74 return compiler != null; |
73 } |
75 } |
74 |
76 |
|
77 private final Context context; |
75 private final StandardJavaFileManager fm; |
78 private final StandardJavaFileManager fm; |
76 private final Set<JavaFileObject.Kind> fileKinds; |
79 private final Set<JavaFileObject.Kind> fileKinds; |
77 private final FileSystem jrtfs; |
80 private final FileSystem jrtfs; |
78 |
81 |
79 /** |
82 /** |
80 * Construct a new PackagesHelper. |
83 * Construct a new PackagesHelper. |
81 * |
84 * |
82 * @param classPath Class path to compute properties of java package objects |
85 * @param context the current Nashorn Context |
83 */ |
86 */ |
84 PackagesHelper(final String classPath) throws IOException { |
87 PackagesHelper(final Context context) throws IOException { |
|
88 this.context = context; |
|
89 final String classPath = context.getEnv()._classpath; |
85 if (isJavacAvailable()) { |
90 if (isJavacAvailable()) { |
86 fm = compiler.getStandardFileManager(null, null, null); |
91 fm = compiler.getStandardFileManager(null, null, null); |
87 fileKinds = EnumSet.of(JavaFileObject.Kind.CLASS); |
92 fileKinds = EnumSet.of(JavaFileObject.Kind.CLASS); |
88 |
93 |
89 if (classPath != null && !classPath.isEmpty()) { |
94 if (classPath != null && !classPath.isEmpty()) { |
164 try (DirectoryStream<Path> ds2 = Files.newDirectoryStream(pkgUnderMod)) { |
169 try (DirectoryStream<Path> ds2 = Files.newDirectoryStream(pkgUnderMod)) { |
165 for (Path p : ds2) { |
170 for (Path p : ds2) { |
166 String str = p.getFileName().toString(); |
171 String str = p.getFileName().toString(); |
167 // get rid of ".class", if any |
172 // get rid of ".class", if any |
168 if (str.endsWith(".class")) { |
173 if (str.endsWith(".class")) { |
169 props.add(str.substring(0, str.length() - ".class".length())); |
174 final String clsName = str.substring(0, str.length() - ".class".length()); |
170 } else { |
175 if (clsName.indexOf('$') == -1 && isClassAccessible(pkg + "." + clsName)) { |
|
176 props.add(str); |
|
177 } |
|
178 } else if (isPackageAccessible(pkg + "." + str)) { |
171 props.add(str); |
179 props.add(str); |
172 } |
180 } |
173 } |
181 } |
174 } |
182 } |
175 } |
183 } |
191 final int nextDot = binaryName.indexOf('.', pkg.length() + 1); |
199 final int nextDot = binaryName.indexOf('.', pkg.length() + 1); |
192 final int start = pkg.length() + 1; |
200 final int start = pkg.length() + 1; |
193 |
201 |
194 if (nextDot != -1) { |
202 if (nextDot != -1) { |
195 // subpackage - eg. "regex" for "java.util" |
203 // subpackage - eg. "regex" for "java.util" |
196 props.add(binaryName.substring(start, nextDot)); |
204 final String pkgName = binaryName.substring(start, nextDot); |
|
205 if (isPackageAccessible(binaryName.substring(0, nextDot))) { |
|
206 props.add(binaryName.substring(start, nextDot)); |
|
207 } |
197 } else { |
208 } else { |
198 // class - filter out nested, inner, anonymous, local classes. |
209 // class - filter out nested, inner, anonymous, local classes. |
199 // Dynalink supported public nested classes as properties of |
210 // Dynalink supported public nested classes as properties of |
200 // StaticClass object anyway. We don't want to expose those |
211 // StaticClass object anyway. We don't want to expose those |
201 // "$" internal names as properties of package object. |
212 // "$" internal names as properties of package object. |
202 |
213 |
203 final String clsName = binaryName.substring(start); |
214 final String clsName = binaryName.substring(start); |
204 if (clsName.indexOf('$') == -1) { |
215 if (clsName.indexOf('$') == -1 && isClassAccessible(binaryName)) { |
205 props.add(clsName); |
216 props.add(clsName); |
206 } |
217 } |
207 } |
218 } |
208 } |
219 } |
209 } |
220 } |
212 private static List<File> getFiles(final String classPath) { |
223 private static List<File> getFiles(final String classPath) { |
213 return Stream.of(classPath.split(File.pathSeparator)) |
224 return Stream.of(classPath.split(File.pathSeparator)) |
214 .map(File::new) |
225 .map(File::new) |
215 .collect(Collectors.toList()); |
226 .collect(Collectors.toList()); |
216 } |
227 } |
|
228 |
|
229 private boolean isClassAccessible(final String className) { |
|
230 try { |
|
231 final Class<?> clz = context.findClass(className); |
|
232 return Modifier.isPublic(clz.getModifiers()); |
|
233 } catch (final ClassNotFoundException cnfe) { |
|
234 } |
|
235 return false; |
|
236 } |
|
237 |
|
238 private boolean isPackageAccessible(final String pkgName) { |
|
239 try { |
|
240 Context.checkPackageAccess(pkgName); |
|
241 return true; |
|
242 } catch (final SecurityException se) { |
|
243 return false; |
|
244 } |
|
245 } |
217 } |
246 } |