| /* |
| * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| package shared; |
| |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| |
| public abstract class Checker { |
| protected Class staticTargetClass; |
| protected Class dynamicTargetClass; |
| protected String methodName; |
| |
| public abstract String check (Class callSite); |
| |
| public Checker(Class staticTargetClass, Class dynamicTargetClass) { |
| if (!staticTargetClass.isAssignableFrom(dynamicTargetClass)) { |
| throw new RuntimeException("Dynamic target class should be a subclass of the static target class."); |
| } |
| |
| // ********************************************** |
| // NB!!! All classes are assumed to be PUBLIC !!! |
| // ********************************************** |
| Class klass = dynamicTargetClass; |
| while (klass != Object.class) { |
| if (!Modifier.isPublic(klass.getModifiers())) { |
| throw new AssertionError("Class "+klass.getName()+" isn't public."); |
| } |
| |
| klass = klass.getSuperclass(); |
| } |
| |
| this.methodName = Utils.TARGET_METHOD_NAME; |
| this.staticTargetClass = staticTargetClass; |
| this.dynamicTargetClass = dynamicTargetClass; |
| } |
| |
| protected Method getMethodInHierarchy (Class klass) { |
| return getMethodInHierarchy(klass, methodName); |
| } |
| |
| protected Method getMethodInHierarchy (Class klass, String name) { |
| while (klass != null) { |
| Method method = getDeclaredMethod (klass, name); |
| |
| if ( method != null) { |
| // TODO: why doesn't this check work in VM? |
| // int modifiers = method.getModifiers(); |
| // |
| // if (Modifier.isPrivate(modifiers)) { |
| // if (klass == initialClass) { |
| // return method; |
| // } |
| // } else { |
| // return method; |
| // } |
| return method; |
| } |
| klass = klass.getSuperclass(); |
| } |
| |
| return null; |
| } |
| |
| protected Method getMethod (Class klass) { |
| return getMethod (klass, methodName); |
| } |
| |
| protected Method getDeclaredMethod (Class klass) { |
| return getDeclaredMethod (klass, methodName); |
| } |
| |
| static protected Method getMethod (Class klass, String name) { |
| return findMethod (klass.getMethods(), name); |
| } |
| |
| static protected Method getDeclaredMethod (Class klass, String name) { |
| return findMethod (klass.getDeclaredMethods(), name); |
| } |
| |
| static protected Method findMethod (Method[] methods, String name) { |
| for (Method method : methods) { |
| if (name.equals(method.getName())) { |
| return method; |
| } |
| } |
| |
| return null; |
| } |
| |
| static public String getClassPackageName(Class klass) { |
| String name = klass.getName(); |
| return getClassPackageName(name); |
| } |
| |
| static public String getClassPackageName(String name) { |
| int lastDotIndex = name.lastIndexOf('.'); |
| if (lastDotIndex > -1) { |
| return name.substring(0, lastDotIndex); |
| } else { |
| return ""; |
| } |
| } |
| |
| public static String abbreviateResult(String result) { |
| // Abbreviate exception names |
| result = result.replaceAll("java.lang.NullPointerException", "NPE"); |
| result = result.replaceAll("java.lang.IllegalAccessError", "IAE"); |
| result = result.replaceAll("java.lang.IllegalAccessException", "IAExc"); |
| result = result.replaceAll("java.lang.NoSuchMethodError", "NSME"); |
| result = result.replaceAll("java.lang.AbstractMethodError", "AME"); |
| result = result.replaceAll("java.lang.IncompatibleClassChangeError", "ICCE"); |
| result = result.replaceAll("java.lang.VerifyError", "VE"); |
| result = result.replaceAll("java.lang.ClassFormatError", "CFE"); |
| |
| return result; |
| } |
| |
| // Check access possibility from particular call site |
| protected boolean checkAccess(Class klass, Class callerClass) { |
| int modifiers = klass.getModifiers(); |
| |
| return checkAccess(modifiers, klass, callerClass); |
| } |
| |
| protected boolean checkAccess(Method m, Class callerClass) { |
| int modifiers = m.getModifiers(); |
| Class declaringClass = m.getDeclaringClass(); |
| |
| return checkAccess(modifiers, declaringClass, callerClass); |
| } |
| |
| protected boolean checkAccess(int modifiers, Class klass, Class callerClass) { |
| if ( Modifier.isPublic(modifiers) ) { |
| return true; |
| } else if ( Modifier.isProtected(modifiers) ) { |
| if (klass.isAssignableFrom(callerClass)) { |
| return true; |
| } else if (getClassPackageName(klass).equals(getClassPackageName(callerClass))) { |
| return true; |
| } |
| } else if ( Modifier.isPrivate(modifiers)) { |
| if (klass == callerClass) { |
| return true; |
| } |
| } else if (getClassPackageName(klass).equals(getClassPackageName(callerClass))) { |
| return true; |
| } else { |
| // if method isn't accessible, IllegalAccessException is thrown |
| return false; |
| } |
| |
| return false; |
| } |
| } |