1 /* 2 * Copyright (c) 2015, 2016, 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.nashorn.tools.jjs; 27 28 import java.lang.reflect.Modifier; 29 import java.io.IOException; 30 import java.util.ArrayList; 31 import java.util.Collections; 32 import java.util.LinkedHashMap; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.Set; 36 import jdk.nashorn.internal.runtime.Context; 37 38 /** 39 * Abstract helper class to compute properties of a Java package object. Properties of 40 * package object are (simple) top level class names in that java package and 41 * immediate subpackages of that package. 42 */ 43 abstract class PackagesHelper { 44 private final Context context; 45 46 /** 47 * Construct a new PackagesHelper. 48 * 49 * @param context the current Nashorn Context 50 */ 51 PackagesHelper(final Context context) throws IOException { 52 this.context = context; 53 } 54 55 static PackagesHelper create(final Context context) throws IOException { 56 return isJavacHelperAvailable()? new JavacPackagesHelper(context) : new JrtPackagesHelper(context); 57 } 58 59 // LRU cache for java package properties lists 60 private final LinkedHashMap<String, List<String>> propsCache = 61 new LinkedHashMap<String, List<String>>(32, 0.75f, true) { 62 private static final int CACHE_SIZE = 100; 63 private static final long serialVersionUID = 1; 64 65 @Override 66 protected boolean removeEldestEntry(final Map.Entry<String, List<String>> eldest) { 67 return size() > CACHE_SIZE; 68 } 69 }; 70 71 /** 72 * Return the list of properties of the given Java package or package prefix 73 * 74 * @param pkg Java package name or package prefix name 75 * @return the list of properties of the given Java package or package prefix 76 */ 77 final List<String> getPackageProperties(final String pkg) { 78 // check the cache first 79 if (propsCache.containsKey(pkg)) { 80 return propsCache.get(pkg); 81 } 82 83 try { 84 // make sorted list of properties 85 final List<String> props = new ArrayList<>(listPackage(pkg)); 86 Collections.sort(props); 87 propsCache.put(pkg, props); 88 return props; 89 } catch (final IOException exp) { 90 if (Main.DEBUG) { 91 exp.printStackTrace(); 92 } 93 return Collections.<String>emptyList(); 94 } 95 } 96 97 /** 98 * Close resources (like file system) used, if any. 99 */ 100 abstract void close() throws IOException; 101 102 /** 103 * Return the set of properties of a given package object. 104 * 105 * @param pkg package start string 106 * @return set of properties of the given Java package 107 */ 108 abstract Set<String> listPackage(final String pkg) throws IOException; 109 110 final boolean isClassAccessible(final String className) { 111 try { 112 final Class<?> clz = context.findClass(className); 113 return Modifier.isPublic(clz.getModifiers()); 114 } catch (final ClassNotFoundException cnfe) { 115 } 116 return false; 117 } 118 119 final boolean isPackageAccessible(final String pkgName) { 120 try { 121 Context.checkPackageAccess(pkgName); 122 return true; 123 } catch (final SecurityException se) { 124 return false; 125 } 126 } 127 128 private static boolean isJavacHelperAvailable() { 129 try { 130 boolean result = JavacPackagesHelper.isAvailable(); 131 if (Main.DEBUG && !result) { 132 System.err.println("javac packages helper is not available"); 133 } 134 return result; 135 } catch (final LinkageError err) { 136 if (Main.DEBUG) { 137 System.err.println("javac packages helper is not available"); 138 err.printStackTrace(); 139 } 140 return false; 141 } 142 } 143 }