< prev index next >

test/jdk/java/lang/invoke/AccessControlTest.java

Print this page


   1 /*
   2  * Copyright (c) 2012, 2018, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test
  25  * @summary test access checking by java.lang.invoke.MethodHandles.Lookup
  26  * @compile AccessControlTest.java AccessControlTest_subpkg/Acquaintance_remote.java
  27  * @run testng/othervm test.java.lang.invoke.AccessControlTest
  28  */
  29 
  30 package test.java.lang.invoke;
  31 
  32 import java.lang.invoke.*;
  33 import java.lang.reflect.*;
  34 import java.lang.reflect.Modifier;
  35 import java.util.*;
  36 import org.testng.*;
  37 import org.testng.annotations.*;
  38 
  39 import static java.lang.invoke.MethodHandles.*;
  40 import static java.lang.invoke.MethodHandles.Lookup.*;
  41 import static java.lang.invoke.MethodType.*;
  42 import static org.testng.Assert.*;
  43 
  44 import test.java.lang.invoke.AccessControlTest_subpkg.Acquaintance_remote;
  45 
  46 
  47 /**
  48  * Test many combinations of Lookup access and cross-class lookupStatic.
  49  * @author jrose
  50  */
  51 public class AccessControlTest {
  52     static final Class<?> THIS_CLASS = AccessControlTest.class;
  53     // How much output?
  54     static int verbosity = 0;
  55     static {
  56         String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbosity");
  57         if (vstr == null)
  58             vstr = System.getProperty(THIS_CLASS.getName()+".verbosity");
  59         if (vstr != null)  verbosity = Integer.parseInt(vstr);
  60     }
  61 
  62     private class LookupCase implements Comparable<LookupCase> {
  63         final Lookup   lookup;
  64         final Class<?> lookupClass;

  65         final int      lookupModes;
  66         public LookupCase(Lookup lookup) {
  67             this.lookup = lookup;
  68             this.lookupClass = lookup.lookupClass();

  69             this.lookupModes = lookup.lookupModes();

  70             assert(lookupString().equals(lookup.toString()));
  71             numberOf(lookupClass().getClassLoader()); // assign CL#
  72         }
  73         public LookupCase(Class<?> lookupClass, int lookupModes) {
  74             this.lookup = null;
  75             this.lookupClass = lookupClass;

  76             this.lookupModes = lookupModes;
  77             numberOf(lookupClass().getClassLoader()); // assign CL#
  78         }
  79 
  80         public final Class<?> lookupClass() { return lookupClass; }

  81         public final int      lookupModes() { return lookupModes; }
  82 
  83         public Lookup lookup() { lookup.getClass(); return lookup; }
  84 
  85         @Override
  86         public int compareTo(LookupCase that) {
  87             Class<?> c1 = this.lookupClass();
  88             Class<?> c2 = that.lookupClass();


  89             if (c1 != c2) {
  90                 int cmp = c1.getName().compareTo(c2.getName());
  91                 if (cmp != 0)  return cmp;
  92                 cmp = numberOf(c1.getClassLoader()) - numberOf(c2.getClassLoader());
  93                 assert(cmp != 0);
  94                 return cmp;










  95             }
  96             return -(this.lookupModes() - that.lookupModes());
  97         }
  98 
  99         @Override
 100         public boolean equals(Object that) {
 101             return (that instanceof LookupCase && equals((LookupCase)that));
 102         }
 103         public boolean equals(LookupCase that) {
 104             return (this.lookupClass() == that.lookupClass() &&

 105                     this.lookupModes() == that.lookupModes());
 106         }
 107 
 108         @Override
 109         public int hashCode() {
 110             return lookupClass().hashCode() + (lookupModes() * 31);
 111         }
 112 
 113         /** Simulate all assertions in the spec. for Lookup.toString. */
 114         private String lookupString() {
 115             String name = lookupClass.getName();


 116             String suffix = "";
 117             if (lookupModes == 0)
 118                 suffix = "/noaccess";
 119             else if (lookupModes == PUBLIC)
 120                 suffix = "/public";
 121              else if (lookupModes == (PUBLIC|UNCONDITIONAL))
 122                 suffix = "/publicLookup";
 123             else if (lookupModes == (PUBLIC|MODULE))
 124                 suffix = "/module";
 125             else if (lookupModes == (PUBLIC|MODULE|PACKAGE))

 126                 suffix = "/package";
 127             else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))

 128                 suffix = "/private";
 129             else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED))

 130                 suffix = "";
 131             else
 132                 suffix = "/#"+Integer.toHexString(lookupModes);
 133             return name+suffix;
 134         }
 135 
 136         /** Simulate all assertions from the spec. for Lookup.in:
 137          * <hr>
 138          * Creates a lookup on the specified new lookup class.
 139          * [A1] The resulting object will report the specified
 140          * class as its own {@link #lookupClass lookupClass}.
 141          * <p>
 142          * [A2] However, the resulting {@code Lookup} object is guaranteed
 143          * to have no more access capabilities than the original.
 144          * In particular, access capabilities can be lost as follows:<ul>
 145          * <li> [A3] If the old lookup class is in a named module, and the new
 146          * lookup class is in a different module {@code M}, then no members, not
 147          * even public members in {@code M}'s exported packages, will be accessible.
 148          * The exception to this is when this lookup is publicLookup, in which case
 149          * public access is not lost.
 150          * <li> [A4] If the old lookup class is in an unnamed module, and the new
 151          * lookup class is a different module then module access is lost.
 152          * <li> [A5] If the new lookup class differs from the old one then UNCONDITIONAL
 153          * is lost. If the new lookup class is not within the same package member as the
 154          * old one, protected members will not be accessible by virtue of inheritance.
 155          * (Protected members may continue to be accessible because of package sharing.)
 156          * <li> [A6] If the new lookup class is in a different package than the old one,
 157          * protected and default (package) members will not be accessible.
 158          * <li> [A7] If the new lookup class is not within the same package member
 159          * as the old one, private members will not be accessible.
 160          * <li> [A8] If the new lookup class is not accessible to the old lookup class,
 161          * then no members, not even public members, will be accessible.
 162          * <li> [A9] (In all other cases, public members will continue to be accessible.)
 163          * </ul>








 164          * Other than the above cases, the new lookup will have the same
 165          * access capabilities as the original. [A10]
 166          * <hr>
 167          */
 168         public LookupCase in(Class<?> c2) {
 169             Class<?> c1 = lookupClass();
 170             int m1 = lookupModes();



 171             int changed = 0;
 172             // for the purposes of access control then treat classes in different unnamed
 173             // modules as being in the same module.
 174             boolean sameModule = (c1.getModule() == c2.getModule()) ||
 175                                  (!c1.getModule().isNamed() && !c2.getModule().isNamed());
 176             boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() &&
 177                                    c1.getPackageName().equals(c2.getPackageName()));
 178             boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2));
 179             boolean sameClass = (c1 == c2);
 180             assert(samePackage  || !sameTopLevel);
 181             assert(sameTopLevel || !sameClass);
 182             boolean accessible = sameClass;
 183             if ((m1 & PACKAGE) != 0)  accessible |= samePackage;
 184             if ((m1 & PUBLIC ) != 0)  accessible |= (c2.getModifiers() & PUBLIC) != 0;
 185             if (!sameModule) {
 186                 if (c1.getModule().isNamed() && (m1 & UNCONDITIONAL) == 0) {
 187                     accessible = false;  // [A3]
 188                 } else {
 189                     changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED);    // [A3] [A4]
 190                 }





 191             }
 192             if (!accessible) {
 193                 // Different package and no access to c2; lose all access.
 194                 changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED);  // [A8]







 195             }
 196             if (!samePackage) {
 197                 // Different package; loose PACKAGE and lower access.
 198                 changed |= (PACKAGE|PRIVATE|PROTECTED);  // [A6]
 199             }
 200             if (!sameTopLevel) {
 201                 // Different top-level class.  Lose PRIVATE and PROTECTED access.
 202                 changed |= (PRIVATE|PROTECTED);  // [A5] [A7]
 203             }
 204             if (!sameClass) {
 205                 changed |= (UNCONDITIONAL);     // [A5]
 206             } else {
 207                 assert(changed == 0);       // [A10] (no deprivation if same class)
 208             }
 209             if (accessible)  assert((changed & PUBLIC) == 0);  // [A9]
 210             int m2 = m1 & ~changed;
 211             LookupCase l2 = new LookupCase(c2, m2);



 212             assert(l2.lookupClass() == c2); // [A1]
 213             assert((m1 | m2) == m1);        // [A2] (no elevation of access)

 214             return l2;
 215         }
 216 































 217         @Override
 218         public String toString() {
 219             String s = lookupClass().getSimpleName();
 220             String lstr = lookupString();
 221             int sl = lstr.indexOf('/');
 222             if (sl >= 0)  s += lstr.substring(sl);
 223             ClassLoader cld = lookupClass().getClassLoader();
 224             if (cld != THIS_LOADER)  s += "/loader#"+numberOf(cld);
 225             return s;
 226         }
 227 
 228         /** Predict the success or failure of accessing this method. */
 229         public boolean willAccess(Method m) {
 230             Class<?> c1 = lookupClass();
 231             Class<?> c2 = m.getDeclaringClass();










 232 
 233             // publicLookup has access to all public types/members of types in unnamed modules
 234             if ((lookupModes & UNCONDITIONAL) != 0
 235                 && (lookupModes & PUBLIC) != 0
 236                 && !c2.getModule().isNamed()
 237                 && Modifier.isPublic(c2.getModifiers())
 238                 && Modifier.isPublic(m.getModifiers()))
 239                 return true;





 240 
 241             LookupCase lc = this.in(c2);
 242             int m1 = lc.lookupModes();
 243             int m2 = fixMods(m.getModifiers());
 244             // allow private lookup on nestmates. Otherwise, privacy is strictly enforced
 245             if (c1 != c2 && ((m2 & PRIVATE) == 0 || !c1.isNestmateOf(c2))) {
 246                 m1 &= ~PRIVATE;
 247             }
 248             // protected access is sometimes allowed
 249             if ((m2 & PROTECTED) != 0) {
 250                 int prev = m2;
 251                 m2 |= PACKAGE;  // it acts like a package method also
 252                 if ((lookupModes() & PROTECTED) != 0 &&
 253                     c2.isAssignableFrom(c1))
 254                     m2 |= PUBLIC;  // from a subclass, it acts like a public method also
 255             }
 256             if (verbosity >= 2)
 257                 System.out.format("%s willAccess %s m1=0x%h m2=0x%h => %s%n", this, lc, m1, m2, ((m2 & m1) != 0));
 258             return (m2 & m1) != 0;
 259         }
 260 
 261         /** Predict the success or failure of accessing this class. */
 262         public boolean willAccessClass(Class<?> c2, boolean load) {
 263             Class<?> c1 = lookupClass();
 264             if (load && c2.getClassLoader() != null) {
 265                 if (c1.getClassLoader() == null) {
 266                     // not visible
 267                     return false;
 268                 }
 269             }
 270 
 271             // publicLookup has access to all public types/members of types in unnamed modules
 272             if ((lookupModes & UNCONDITIONAL) != 0
 273                 && (lookupModes & PUBLIC) != 0
 274                 && (!c2.getModule().isNamed())
 275                 && Modifier.isPublic(c2.getModifiers()))
 276                 return true;









 277 
 278             LookupCase lc = this.in(c2);
 279             int m1 = lc.lookupModes();
 280             boolean r = false;
 281             if (m1 == 0) {
 282                 r = false;
 283             } else {
 284                 int m2 = fixMods(c2.getModifiers());
 285                 if ((m2 & PUBLIC) != 0) {
 286                     r = true;
 287                 } else if ((m1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage()) {



 288                     r = true;
 289                 }
 290             }
 291             if (verbosity >= 2) {
 292                 System.out.println(this+" willAccessClass "+lc+" c1="+c1+" c2="+c2+" => "+r);
 293             }
 294             return r;
 295         }
 296     }
 297 
 298     private static Class<?> topLevelClass(Class<?> cls) {
 299         Class<?> c = cls;
 300         for (Class<?> ec; (ec = c.getEnclosingClass()) != null; )
 301             c = ec;
 302         assert(c.getEnclosingClass() == null);
 303         assert(c == cls || cls.getEnclosingClass() != null);
 304         return c;
 305     }
 306 
 307     private final TreeSet<LookupCase> CASES = new TreeSet<>();


 311     { if (THIS_LOADER != null)  LOADERS.add(THIS_LOADER); }  // #1
 312 
 313     private LookupCase lookupCase(String name) {
 314         for (LookupCase lc : CASES) {
 315             if (lc.toString().equals(name))
 316                 return lc;
 317         }
 318         throw new AssertionError(name);
 319     }
 320 
 321     private int numberOf(ClassLoader cl) {
 322         if (cl == null)  return 0;
 323         int i = LOADERS.indexOf(cl);
 324         if (i < 0) {
 325             i = LOADERS.size();
 326             LOADERS.add(cl);
 327         }
 328         return i+1;
 329     }
 330 
 331     private void addLookupEdge(LookupCase l1, Class<?> c2, LookupCase l2) {
 332         TreeSet<LookupCase> edges = CASE_EDGES.get(l2);
 333         if (edges == null)  CASE_EDGES.put(l2, edges = new TreeSet<>());
 334         if (edges.add(l1)) {
 335             Class<?> c1 = l1.lookupClass();
 336             assert(l2.lookupClass() == c2); // [A1]
 337             int m1 = l1.lookupModes();
 338             int m2 = l2.lookupModes();
 339             assert((m1 | m2) == m1);        // [A2] (no elevation of access)
 340             LookupCase expect = l1.in(c2);
 341             if (!expect.equals(l2))
 342                 System.out.println("*** expect "+l1+" => "+expect+" but got "+l2);
 343             assertEquals(l2, expect);
 344         }
 345     }
 346 
 347     private void makeCases(Lookup[] originalLookups) {
 348         // make initial set of lookup test cases
 349         CASES.clear(); LOADERS.clear(); CASE_EDGES.clear();
 350         ArrayList<Class<?>> classes = new ArrayList<>();
 351         for (Lookup l : originalLookups) {
 352             CASES.add(new LookupCase(l));
 353             classes.remove(l.lookupClass());  // no dups please
 354             classes.add(l.lookupClass());
 355         }
 356         System.out.println("loaders = "+LOADERS);
 357         int rounds = 0;
 358         for (int lastCount = -1; lastCount != CASES.size(); ) {
 359             lastCount = CASES.size();  // if CASES grow in the loop we go round again
 360             for (LookupCase lc1 : CASES.toArray(new LookupCase[0])) {





 361                 for (Class<?> c2 : classes) {
 362                     LookupCase lc2 = new LookupCase(lc1.lookup().in(c2));
 363                     addLookupEdge(lc1, c2, lc2);
 364                     CASES.add(lc2);
 365                 }
 366             }
 367             rounds++;
 368         }
 369         System.out.println("filled in "+CASES.size()+" cases from "+originalLookups.length+" original cases in "+rounds+" rounds");
 370         if (false) {
 371             System.out.println("CASES: {");
 372             for (LookupCase lc : CASES) {
 373                 System.out.println(lc);
 374                 Set<LookupCase> edges = CASE_EDGES.get(lc);
 375                 if (edges != null)
 376                     for (LookupCase prev : edges) {
 377                         System.out.println("\t"+prev);
 378                     }
 379             }
 380             System.out.println("}");
 381         }
 382     }
 383 
 384     @Test public void test() {
 385         makeCases(lookups());
 386         if (verbosity > 0) {
 387             verbosity += 9;
 388             Method pro_in_self = targetMethod(THIS_CLASS, PROTECTED, methodType(void.class));
 389             testOneAccess(lookupCase("AccessControlTest/public"),  pro_in_self, "find");
 390             testOneAccess(lookupCase("Remote_subclass/public"),    pro_in_self, "find");
 391             testOneAccess(lookupCase("Remote_subclass"),           pro_in_self, "find");
 392             verbosity -= 9;
 393         }
 394         Set<Class<?>> targetClassesDone = new HashSet<>();
 395         for (LookupCase targetCase : CASES) {
 396             Class<?> targetClass = targetCase.lookupClass();
 397             if (!targetClassesDone.add(targetClass))  continue;  // already saw this one
 398             String targetPlace = placeName(targetClass);
 399             if (targetPlace == null)  continue;  // Object, String, not a target
 400             for (int targetAccess : ACCESS_CASES) {


 401                 MethodType methodType = methodType(void.class);
 402                 Method method = targetMethod(targetClass, targetAccess, methodType);
 403                 // Try to access target method from various contexts.
 404                 for (LookupCase sourceCase : CASES) {
 405                     testOneAccess(sourceCase, method, "findClass");
 406                     testOneAccess(sourceCase, method, "accessClass");
 407                     testOneAccess(sourceCase, method, "find");
 408                     testOneAccess(sourceCase, method, "unreflect");
 409                 }
 410             }
 411         }
 412         System.out.println("tested "+testCount+" access scenarios; "+testCountFails+" accesses were denied");
 413     }
 414 
 415     private int testCount, testCountFails;
 416 
 417     private void testOneAccess(LookupCase sourceCase, Method method, String kind) {
 418         Class<?> targetClass = method.getDeclaringClass();
 419         String methodName = method.getName();
 420         MethodType methodType = methodType(method.getReturnType(), method.getParameterTypes());


 440             case "unreflect":
 441                 sourceCase.lookup().unreflect(method);
 442                 break;
 443             default:
 444                 throw new AssertionError(kind);
 445             }
 446             didAccess = true;
 447         } catch (ReflectiveOperationException ex) {
 448             accessError = ex;
 449         }
 450         if (willAccess != didAccess) {
 451             System.out.println(sourceCase+" => "+targetClass.getSimpleName()+(isFindOrAccessClass?"":"."+methodName+methodType));
 452             System.out.println("fail "+(isFindOrAccessClass?kind:"on "+method)+" ex="+accessError);
 453             assertEquals(willAccess, didAccess);
 454         }
 455         testCount++;
 456         if (!didAccess)  testCountFails++;
 457     }
 458 
 459     static Method targetMethod(Class<?> targetClass, int targetAccess, MethodType methodType) {
 460         assert targetAccess != MODULE;
 461         String methodName = accessName(targetAccess)+placeName(targetClass);
 462         if (verbosity >= 2)
 463             System.out.println(targetClass.getSimpleName()+"."+methodName+methodType);
 464         try {
 465             Method method = targetClass.getDeclaredMethod(methodName, methodType.parameterArray());
 466             assertEquals(method.getReturnType(), methodType.returnType());
 467             int haveMods = method.getModifiers();
 468             assert(Modifier.isStatic(haveMods));
 469             assert(targetAccess == fixMods(haveMods));
 470             return method;
 471         } catch (NoSuchMethodException ex) {
 472             throw new AssertionError(methodName, ex);
 473         }
 474     }
 475 
 476     static String placeName(Class<?> cls) {
 477         // return "self", "sibling", "nestmate", etc.
 478         if (cls == AccessControlTest.class)  return "self";
 479         String cln = cls.getSimpleName();
 480         int under = cln.lastIndexOf('_');
 481         if (under < 0)  return null;
 482         return cln.substring(under+1);
 483     }
 484     static String accessName(int acc) {
 485         switch (acc) {
 486         case PUBLIC:     return "pub_in_";
 487         case PROTECTED:  return "pro_in_";
 488         case PACKAGE:    return "pkg_in_";
 489         case PRIVATE:    return "pri_in_";
 490         }
 491         assert(false);
 492         return "?";
 493     }
 494     // MODULE not a test case at this time
 495     private static final int[] ACCESS_CASES = {
 496         PUBLIC, PACKAGE, PRIVATE, PROTECTED
 497     };




 498     /** Return one of the ACCESS_CASES. */
 499     static int fixMods(int mods) {
 500         mods &= (PUBLIC|PRIVATE|PROTECTED);
 501         switch (mods) {
 502         case PUBLIC: case PRIVATE: case PROTECTED: return mods;
 503         case 0:  return PACKAGE;
 504         }
 505         throw new AssertionError(mods);
 506     }
 507 
 508     static Lookup[] lookups() {
 509         ArrayList<Lookup> tem = new ArrayList<>();
 510         Collections.addAll(tem,
 511                            AccessControlTest.lookup_in_self(),
 512                            Inner_nestmate.lookup_in_nestmate(),
 513                            AccessControlTest_sibling.lookup_in_sibling());
 514         if (true) {
 515             Collections.addAll(tem,Acquaintance_remote.lookups());
 516         } else {
 517             try {


   1 /*
   2  * Copyright (c) 2012, 2019, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test
  25  * @summary test access checking by java.lang.invoke.MethodHandles.Lookup
  26  * @compile AccessControlTest.java AccessControlTest_subpkg/Acquaintance_remote.java
  27  * @run testng/othervm test.java.lang.invoke.AccessControlTest
  28  */
  29 
  30 package test.java.lang.invoke;
  31 
  32 import java.lang.invoke.*;
  33 import java.lang.reflect.*;
  34 import java.lang.reflect.Modifier;
  35 import java.util.*;

  36 import org.testng.annotations.*;
  37 
  38 import static java.lang.invoke.MethodHandles.*;
  39 import static java.lang.invoke.MethodHandles.Lookup.*;
  40 import static java.lang.invoke.MethodType.*;
  41 import static org.testng.Assert.*;
  42 
  43 import test.java.lang.invoke.AccessControlTest_subpkg.Acquaintance_remote;
  44 
  45 
  46 /**
  47  * Test many combinations of Lookup access and cross-class lookupStatic.
  48  * @author jrose
  49  */
  50 public class AccessControlTest {
  51     static final Class<?> THIS_CLASS = AccessControlTest.class;
  52     // How much output?
  53     static int verbosity = 0;
  54     static {
  55         String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbosity");
  56         if (vstr == null)
  57             vstr = System.getProperty(THIS_CLASS.getName()+".verbosity");
  58         if (vstr != null)  verbosity = Integer.parseInt(vstr);
  59     }
  60 
  61     private class LookupCase implements Comparable<LookupCase> {
  62         final Lookup   lookup;
  63         final Class<?> lookupClass;
  64         final Class<?> prevLookupClass;
  65         final int      lookupModes;
  66         public LookupCase(Lookup lookup) {
  67             this.lookup = lookup;
  68             this.lookupClass = lookup.lookupClass();
  69             this.prevLookupClass = lookup.previousLookupClass();
  70             this.lookupModes = lookup.lookupModes();
  71 
  72             assert(lookupString().equals(lookup.toString()));
  73             numberOf(lookupClass().getClassLoader()); // assign CL#
  74         }
  75         public LookupCase(Class<?> lookupClass, Class<?> prevLookupClass, int lookupModes) {
  76             this.lookup = null;
  77             this.lookupClass = lookupClass;
  78             this.prevLookupClass = prevLookupClass;
  79             this.lookupModes = lookupModes;
  80             numberOf(lookupClass().getClassLoader()); // assign CL#
  81         }
  82 
  83         public final Class<?> lookupClass()     { return lookupClass; }
  84         public final Class<?> prevLookupClass() { return prevLookupClass; }
  85         public final int      lookupModes()     { return lookupModes; }
  86 
  87         public Lookup lookup() { lookup.getClass(); return lookup; }
  88 
  89         @Override
  90         public int compareTo(LookupCase that) {
  91             Class<?> c1 = this.lookupClass();
  92             Class<?> c2 = that.lookupClass();
  93             Class<?> p1 = this.prevLookupClass();
  94             Class<?> p2 = that.prevLookupClass();
  95             if (c1 != c2) {
  96                 int cmp = c1.getName().compareTo(c2.getName());
  97                 if (cmp != 0)  return cmp;
  98                 cmp = numberOf(c1.getClassLoader()) - numberOf(c2.getClassLoader());
  99                 assert(cmp != 0);
 100                 return cmp;
 101             } else if (p1 != p2){
 102                 if (p1 == null)
 103                     return 1;
 104                 else if (p2 == null)
 105                     return -1;
 106                 int cmp = p1.getName().compareTo(p2.getName());
 107                 if (cmp != 0)  return cmp;
 108                 cmp = numberOf(p1.getClassLoader()) - numberOf(p2.getClassLoader());
 109                 assert(cmp != 0);
 110                 return cmp;
 111             }
 112             return -(this.lookupModes() - that.lookupModes());
 113         }
 114 
 115         @Override
 116         public boolean equals(Object that) {
 117             return (that instanceof LookupCase && equals((LookupCase)that));
 118         }
 119         public boolean equals(LookupCase that) {
 120             return (this.lookupClass() == that.lookupClass() &&
 121                     this.prevLookupClass() == that.prevLookupClass() &&
 122                     this.lookupModes() == that.lookupModes());
 123         }
 124 
 125         @Override
 126         public int hashCode() {
 127             return lookupClass().hashCode() + (lookupModes() * 31);
 128         }
 129 
 130         /** Simulate all assertions in the spec. for Lookup.toString. */
 131         private String lookupString() {
 132             String name = lookupClass.getName();
 133             if (prevLookupClass != null)
 134                 name += "/" + prevLookupClass.getName();
 135             String suffix = "";
 136             if (lookupModes == 0)
 137                 suffix = "/noaccess";
 138             else if (lookupModes == PUBLIC)
 139                 suffix = "/public";
 140              else if (lookupModes == UNCONDITIONAL)
 141                 suffix = "/publicLookup";
 142             else if (lookupModes == (PUBLIC|MODULE))
 143                 suffix = "/module";
 144             else if (lookupModes == (PUBLIC|PACKAGE)
 145                      || lookupModes == (PUBLIC|MODULE|PACKAGE))
 146                 suffix = "/package";
 147             else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE)
 148                     || lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))
 149                 suffix = "/private";
 150             else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE|PROTECTED)
 151                      || lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED))
 152                 suffix = "";
 153             else
 154                 suffix = "/#"+Integer.toHexString(lookupModes);
 155             return name+suffix;
 156         }
 157 
 158         /** Simulate all assertions from the spec. for Lookup.in:
 159          * <hr>
 160          * Creates a lookup on the specified new lookup class.
 161          * [A1] The resulting object will report the specified
 162          * class as its own {@link #lookupClass lookupClass}.

 163          * [A2] However, the resulting {@code Lookup} object is guaranteed
 164          * to have no more access capabilities than the original.
 165          * In particular, access capabilities can be lost as follows:<ul>
 166          * [A3] If the new lookup class is in a different module from the old one,
 167          * i.e. {@link #MODULE MODULE} access is lost.
 168          * [A4] If the new lookup class is in a different package
 169          * than the old one, protected and default (package) members will not be accessible,
 170          * i.e. {@link #PROTECTED PROTECTED} and {@link #PACKAGE PACKAGE} access are lost.
 171          * [A5] If the new lookup class is not within the same package member
 172          * as the old one, private members will not be accessible, and protected members
 173          * will not be accessible by virtue of inheritance,
 174          * i.e. {@link #PRIVATE PRIVATE} access is lost.

 175          * (Protected members may continue to be accessible because of package sharing.)
 176          * [A6] If the new lookup class is not
 177          * {@linkplain #accessClass(Class) accessible} to this lookup,
 178          * then no members, not even public members, will be accessible
 179          * i.e. all access modes are lost.
 180          * [A7] If the new lookup class, the old lookup class and the previous lookup class
 181          * are all in different modules i.e. teleporting to a third module,
 182          * all access modes are lost.
 183          * <p>
 184          * The new previous lookup class is chosen as follows:
 185          * [A8] If the new lookup object has {@link #UNCONDITIONAL UNCONDITIONAL} bit,
 186          * the new previous lookup class is {@code null}.
 187          * [A9] If the new lookup class is in the same module as the old lookup class,
 188          * the new previous lookup class is the old previous lookup class.
 189          * [A10] If the new lookup class is in a different module from the old lookup class,
 190          * the new previous lookup class is the the old lookup class.
 191          *
 192          * Other than the above cases, the new lookup will have the same
 193          * access capabilities as the original. [A11]
 194          * <hr>
 195          */
 196         public LookupCase in(Class<?> c2) {
 197             Class<?> c1 = lookupClass();
 198             Module m1 = c1.getModule();
 199             Module m2 = c2.getModule();
 200             Module m0 = prevLookupClass() != null ? prevLookupClass.getModule() : c1.getModule();
 201             int modes1 = lookupModes();
 202             int changed = 0;
 203             // for the purposes of access control then treat classes in different unnamed
 204             // modules as being in the same module.
 205             boolean sameModule = (m1 == m2) ||
 206                                  (!m1.isNamed() && !m2.isNamed());
 207             boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() &&
 208                                    c1.getPackageName().equals(c2.getPackageName()));
 209             boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2));
 210             boolean sameClass = (c1 == c2);
 211             assert(samePackage  || !sameTopLevel);
 212             assert(sameTopLevel || !sameClass);
 213             boolean accessible = sameClass;
 214 
 215             if ((modes1 & PACKAGE) != 0)  accessible |= samePackage;
 216             if ((modes1 & PUBLIC ) != 0)  {
 217                 if (isModuleAccessible(c2))
 218                     accessible |= (c2.getModifiers() & PUBLIC) != 0;
 219                 else
 220                     accessible = false;
 221             }
 222             if ((modes1 & UNCONDITIONAL) != 0) {
 223                 if (m2.isExported(c2.getPackageName()))
 224                     accessible |= (c2.getModifiers() & PUBLIC) != 0;
 225                 else
 226                     accessible = false;
 227             }
 228             if (!accessible) {
 229                 // no access to c2; lose all access.
 230                 changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED|UNCONDITIONAL);  // [A6]
 231             }
 232             if (m2 != m1 && m0 != m1) {
 233                 // hop to a third module; lose all access
 234                 changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED);  // [A7]
 235             }
 236             if (!sameModule) {
 237                 changed |= MODULE;  // [A3]
 238             }
 239             if (!samePackage) {
 240                 // Different package; loose PACKAGE and lower access.
 241                 changed |= (PACKAGE|PRIVATE|PROTECTED);  // [A4]
 242             }
 243             if (!sameTopLevel) {
 244                 // Different top-level class.  Lose PRIVATE and PROTECTED access.
 245                 changed |= (PRIVATE|PROTECTED);  // [A5]
 246             }
 247             if (sameClass) {
 248                 assert(changed == 0);       // [A11] (no deprivation if same class)


 249             }
 250 
 251             if (accessible)  assert((changed & PUBLIC) == 0);
 252             int modes2 = modes1 & ~changed;
 253             Class<?> plc = (m1 == m2) ? prevLookupClass() : c1; // [A9] [A10]
 254             if ((modes1 & UNCONDITIONAL) != 0) plc = null;      // [A8]
 255             LookupCase l2 = new LookupCase(c2, plc, modes2);
 256             assert(l2.lookupClass() == c2);         // [A1]
 257             assert((modes1 | modes2) == modes1);    // [A2] (no elevation of access)
 258             assert(l2.prevLookupClass() == null || (modes2 & MODULE) == 0);
 259             return l2;
 260         }
 261 
 262         LookupCase dropLookupMode(int modeToDrop) {
 263             int oldModes = lookupModes();
 264             int newModes = oldModes & ~(modeToDrop | PROTECTED);
 265             switch (modeToDrop) {
 266                 case PUBLIC: newModes &= ~(MODULE|PACKAGE|PROTECTED|PRIVATE); break;
 267                 case MODULE: newModes &= ~(PACKAGE|PRIVATE); break;
 268                 case PACKAGE: newModes &= ~(PRIVATE); break;
 269                 case PROTECTED:
 270                 case PRIVATE:
 271                 case UNCONDITIONAL: break;
 272                 default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop");
 273             }
 274             if (newModes == oldModes) return this;  // return self if no change
 275             LookupCase l2 = new LookupCase(lookupClass(), prevLookupClass(), newModes);
 276             assert((oldModes | newModes) == oldModes);    // [A2] (no elevation of access)
 277             assert(l2.prevLookupClass() == null || (newModes & MODULE) == 0);
 278             return l2;
 279         }
 280 
 281         boolean isModuleAccessible(Class<?> c) {
 282             Module m1 = lookupClass().getModule();
 283             Module m2 = c.getModule();
 284             Module m0 = prevLookupClass() != null ? prevLookupClass.getModule() : m1;
 285             String pn = c.getPackageName();
 286             boolean accessible = m1.canRead(m2) && m2.isExported(pn, m1);
 287             if (m1 != m0) {
 288                 accessible = accessible && m0.canRead(m2) && m2.isExported(pn, m0);
 289             }
 290             return accessible;
 291         }
 292 
 293         @Override
 294         public String toString() {
 295             String s = lookupClass().getSimpleName();
 296             String lstr = lookupString();
 297             int sl = lstr.indexOf('/');
 298             if (sl >= 0)  s += lstr.substring(sl);
 299             ClassLoader cld = lookupClass().getClassLoader();
 300             if (cld != THIS_LOADER)  s += "/loader#"+numberOf(cld);
 301             return s;
 302         }
 303 
 304         /** Predict the success or failure of accessing this method. */
 305         public boolean willAccess(Method m) {
 306             Class<?> c1 = lookupClass();
 307             Class<?> c2 = m.getDeclaringClass();
 308             Module m1 = c1.getModule();
 309             Module m2 = c2.getModule();
 310             Module m0 = prevLookupClass != null ? prevLookupClass.getModule() : m1;
 311             // unconditional has access to all public types/members of types that is in a package
 312             // are unconditionally exported
 313             if ((lookupModes & UNCONDITIONAL) != 0) {
 314                 return m2.isExported(c2.getPackageName())
 315                        && Modifier.isPublic(c2.getModifiers())
 316                        && Modifier.isPublic(m.getModifiers());
 317             }
 318 
 319             // c1 and c2 are in different module
 320             if (m1 != m2 || m0 != m2) {
 321                 return (lookupModes & PUBLIC) != 0
 322                        && isModuleAccessible(c2)
 323                        && Modifier.isPublic(c2.getModifiers())
 324                        && Modifier.isPublic(m.getModifiers());
 325             }
 326 
 327             assert(m1 == m2 && prevLookupClass == null);
 328 
 329             if (!willAccessClass(c2, false))
 330                 return false;
 331 
 332             LookupCase lc = this.in(c2);
 333             int modes1 = lc.lookupModes();
 334             int modes2 = fixMods(m.getModifiers());
 335             // allow private lookup on nestmates. Otherwise, privacy is strictly enforced
 336             if (c1 != c2 && ((modes2 & PRIVATE) == 0 || !c1.isNestmateOf(c2))) {
 337                 modes1 &= ~PRIVATE;
 338             }
 339             // protected access is sometimes allowed
 340             if ((modes2 & PROTECTED) != 0) {
 341                 int prev = modes2;
 342                 modes2 |= PACKAGE;  // it acts like a package method also
 343                 if ((lookupModes() & PROTECTED) != 0 &&
 344                     c2.isAssignableFrom(c1))
 345                     modes2 |= PUBLIC;  // from a subclass, it acts like a public method also
 346             }
 347             if (verbosity >= 2)
 348                 System.out.format("%s willAccess %s modes1=0x%h modes2=0x%h => %s%n", lookupString(), lc.lookupString(), modes1, modes2, (modes2 & modes1) != 0);
 349             return (modes2 & modes1) != 0;
 350         }
 351 
 352         /** Predict the success or failure of accessing this class. */
 353         public boolean willAccessClass(Class<?> c2, boolean load) {
 354             Class<?> c1 = lookupClass();
 355             if (load && c2.getClassLoader() != null) {
 356                 if (c1.getClassLoader() == null) {
 357                     // not visible
 358                     return false;
 359                 }
 360             }
 361 
 362             Module m1 = c1.getModule();
 363             Module m2 = c2.getModule();
 364             Module m0 = prevLookupClass != null ? prevLookupClass.getModule() : m1;
 365             // unconditional has access to all public types that is in an unconditionally exported package
 366             if ((lookupModes & UNCONDITIONAL) != 0) {
 367                 return m2.isExported(c2.getPackageName()) && Modifier.isPublic(c2.getModifiers());
 368             }
 369             // c1 and c2 are in different module
 370             if (m1 != m2 || m0 != m2) {
 371                 return (lookupModes & PUBLIC) != 0
 372                     && isModuleAccessible(c2)
 373                     && Modifier.isPublic(c2.getModifiers());
 374             }
 375 
 376             assert(m1 == m2 && prevLookupClass == null);
 377 
 378             LookupCase lc = this.in(c2);
 379             int modes1 = lc.lookupModes();
 380             boolean r = false;
 381             if (modes1 == 0) {
 382                 r = false;
 383             } else {
 384                 if (Modifier.isPublic(c2.getModifiers())) {
 385                     if ((modes1 & MODULE) != 0)
 386                         r = true;
 387                     else if ((modes1 & PUBLIC) != 0)
 388                         r = m1.isExported(c2.getPackageName());
 389                 } else {
 390                     if ((modes1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage())
 391                         r = true;
 392                 }
 393             }
 394             if (verbosity >= 2) {
 395                 System.out.println(this+" willAccessClass "+lc+" c1="+c1+" c2="+c2+" => "+r);
 396             }
 397             return r;
 398         }
 399     }
 400 
 401     private static Class<?> topLevelClass(Class<?> cls) {
 402         Class<?> c = cls;
 403         for (Class<?> ec; (ec = c.getEnclosingClass()) != null; )
 404             c = ec;
 405         assert(c.getEnclosingClass() == null);
 406         assert(c == cls || cls.getEnclosingClass() != null);
 407         return c;
 408     }
 409 
 410     private final TreeSet<LookupCase> CASES = new TreeSet<>();


 414     { if (THIS_LOADER != null)  LOADERS.add(THIS_LOADER); }  // #1
 415 
 416     private LookupCase lookupCase(String name) {
 417         for (LookupCase lc : CASES) {
 418             if (lc.toString().equals(name))
 419                 return lc;
 420         }
 421         throw new AssertionError(name);
 422     }
 423 
 424     private int numberOf(ClassLoader cl) {
 425         if (cl == null)  return 0;
 426         int i = LOADERS.indexOf(cl);
 427         if (i < 0) {
 428             i = LOADERS.size();
 429             LOADERS.add(cl);
 430         }
 431         return i+1;
 432     }
 433 
 434     private void addLookupEdge(LookupCase l1, Class<?> c2, LookupCase l2, int dropAccess) {
 435         TreeSet<LookupCase> edges = CASE_EDGES.get(l2);
 436         if (edges == null)  CASE_EDGES.put(l2, edges = new TreeSet<>());
 437         if (edges.add(l1)) {
 438             Class<?> c1 = l1.lookupClass();
 439             assert(l2.lookupClass() == c2); // [A1]
 440             int m1 = l1.lookupModes();
 441             int m2 = l2.lookupModes();
 442             assert((m1 | m2) == m1);        // [A2] (no elevation of access)
 443             LookupCase expect = dropAccess == 0 ? l1.in(c2) : l1.in(c2).dropLookupMode(dropAccess);
 444             if (!expect.equals(l2))
 445                 System.out.println("*** expect "+l1+" => "+expect+" but got "+l2);
 446             assertEquals(l2, expect);
 447         }
 448     }
 449 
 450     private void makeCases(Lookup[] originalLookups) {
 451         // make initial set of lookup test cases
 452         CASES.clear(); LOADERS.clear(); CASE_EDGES.clear();
 453         ArrayList<Class<?>> classes = new ArrayList<>();
 454         for (Lookup l : originalLookups) {
 455             CASES.add(new LookupCase(l));
 456             classes.remove(l.lookupClass());  // no dups please
 457             classes.add(l.lookupClass());
 458         }
 459         System.out.println("loaders = "+LOADERS);
 460         int rounds = 0;
 461         for (int lastCount = -1; lastCount != CASES.size(); ) {
 462             lastCount = CASES.size();  // if CASES grow in the loop we go round again
 463             for (LookupCase lc1 : CASES.toArray(new LookupCase[0])) {
 464                 for (int mode : ACCESS_CASES) {
 465                     LookupCase lc2 = new LookupCase(lc1.lookup().dropLookupMode(mode));
 466                     addLookupEdge(lc1, lc1.lookupClass(), lc2, mode);
 467                     CASES.add(lc2);
 468                 }
 469                 for (Class<?> c2 : classes) {
 470                     LookupCase lc2 = new LookupCase(lc1.lookup().in(c2));
 471                     addLookupEdge(lc1, c2, lc2, 0);
 472                     CASES.add(lc2);
 473                 }
 474             }
 475             rounds++;
 476         }
 477         System.out.println("filled in "+CASES.size()+" cases from "+originalLookups.length+" original cases in "+rounds+" rounds");
 478         if (false) {
 479             System.out.println("CASES: {");
 480             for (LookupCase lc : CASES) {
 481                 System.out.println(lc);
 482                 Set<LookupCase> edges = CASE_EDGES.get(lc);
 483                 if (edges != null)
 484                     for (LookupCase prev : edges) {
 485                         System.out.println("\t"+prev);
 486                     }
 487             }
 488             System.out.println("}");
 489         }
 490     }
 491 
 492     @Test public void test() {
 493         makeCases(lookups());
 494         if (verbosity > 0) {
 495             verbosity += 9;
 496             Method pro_in_self = targetMethod(THIS_CLASS, PROTECTED, methodType(void.class));
 497             testOneAccess(lookupCase("AccessControlTest/module"),  pro_in_self, "find");
 498             testOneAccess(lookupCase("Remote_subclass/module"),    pro_in_self, "find");
 499             testOneAccess(lookupCase("Remote_subclass"),           pro_in_self, "find");
 500             verbosity -= 9;
 501         }
 502         Set<Class<?>> targetClassesDone = new HashSet<>();
 503         for (LookupCase targetCase : CASES) {
 504             Class<?> targetClass = targetCase.lookupClass();
 505             if (!targetClassesDone.add(targetClass))  continue;  // already saw this one
 506             String targetPlace = placeName(targetClass);
 507             if (targetPlace == null)  continue;  // Object, String, not a target
 508             for (int targetAccess : ACCESS_CASES) {
 509                 if (targetAccess == MODULE || targetAccess == UNCONDITIONAL)
 510                     continue;
 511                 MethodType methodType = methodType(void.class);
 512                 Method method = targetMethod(targetClass, targetAccess, methodType);
 513                 // Try to access target method from various contexts.
 514                 for (LookupCase sourceCase : CASES) {
 515                     testOneAccess(sourceCase, method, "findClass");
 516                     testOneAccess(sourceCase, method, "accessClass");
 517                     testOneAccess(sourceCase, method, "find");
 518                     testOneAccess(sourceCase, method, "unreflect");
 519                 }
 520             }
 521         }
 522         System.out.println("tested "+testCount+" access scenarios; "+testCountFails+" accesses were denied");
 523     }
 524 
 525     private int testCount, testCountFails;
 526 
 527     private void testOneAccess(LookupCase sourceCase, Method method, String kind) {
 528         Class<?> targetClass = method.getDeclaringClass();
 529         String methodName = method.getName();
 530         MethodType methodType = methodType(method.getReturnType(), method.getParameterTypes());


 550             case "unreflect":
 551                 sourceCase.lookup().unreflect(method);
 552                 break;
 553             default:
 554                 throw new AssertionError(kind);
 555             }
 556             didAccess = true;
 557         } catch (ReflectiveOperationException ex) {
 558             accessError = ex;
 559         }
 560         if (willAccess != didAccess) {
 561             System.out.println(sourceCase+" => "+targetClass.getSimpleName()+(isFindOrAccessClass?"":"."+methodName+methodType));
 562             System.out.println("fail "+(isFindOrAccessClass?kind:"on "+method)+" ex="+accessError);
 563             assertEquals(willAccess, didAccess);
 564         }
 565         testCount++;
 566         if (!didAccess)  testCountFails++;
 567     }
 568 
 569     static Method targetMethod(Class<?> targetClass, int targetAccess, MethodType methodType) {

 570         String methodName = accessName(targetAccess)+placeName(targetClass);
 571         if (verbosity >= 2)
 572             System.out.println(targetClass.getSimpleName()+"."+methodName+methodType);
 573         try {
 574             Method method = targetClass.getDeclaredMethod(methodName, methodType.parameterArray());
 575             assertEquals(method.getReturnType(), methodType.returnType());
 576             int haveMods = method.getModifiers();
 577             assert(Modifier.isStatic(haveMods));
 578             assert(targetAccess == fixMods(haveMods));
 579             return method;
 580         } catch (NoSuchMethodException ex) {
 581             throw new AssertionError(methodName, ex);
 582         }
 583     }
 584 
 585     static String placeName(Class<?> cls) {
 586         // return "self", "sibling", "nestmate", etc.
 587         if (cls == AccessControlTest.class)  return "self";
 588         String cln = cls.getSimpleName();
 589         int under = cln.lastIndexOf('_');
 590         if (under < 0)  return null;
 591         return cln.substring(under+1);
 592     }
 593     static String accessName(int acc) {
 594         switch (acc) {
 595         case PUBLIC:     return "pub_in_";
 596         case PROTECTED:  return "pro_in_";
 597         case PACKAGE:    return "pkg_in_";
 598         case PRIVATE:    return "pri_in_";
 599         }
 600         assert(false);
 601         return "?";
 602     }

 603     private static final int[] ACCESS_CASES = {
 604         PUBLIC, PACKAGE, PRIVATE, PROTECTED, MODULE, UNCONDITIONAL
 605     };
 606     /*
 607      * Adjust PUBLIC => PUBLIC|MODULE|UNCONDITIONAL
 608      * Adjust 0 => PACKAGE
 609      */
 610     /** Return one of the ACCESS_CASES. */
 611     static int fixMods(int mods) {
 612         mods &= (PUBLIC|PRIVATE|PROTECTED);
 613         switch (mods) {
 614         case PUBLIC: case PRIVATE: case PROTECTED: return mods;
 615         case 0:  return PACKAGE;
 616         }
 617         throw new AssertionError(mods);
 618     }
 619 
 620     static Lookup[] lookups() {
 621         ArrayList<Lookup> tem = new ArrayList<>();
 622         Collections.addAll(tem,
 623                            AccessControlTest.lookup_in_self(),
 624                            Inner_nestmate.lookup_in_nestmate(),
 625                            AccessControlTest_sibling.lookup_in_sibling());
 626         if (true) {
 627             Collections.addAll(tem,Acquaintance_remote.lookups());
 628         } else {
 629             try {


< prev index next >