1 /*
   2  * Copyright (c) 2015, 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 package jdk.dynalink.test;
  26 
  27 import java.lang.invoke.CallSite;
  28 import java.lang.invoke.MethodHandle;
  29 import java.lang.invoke.MethodHandles;
  30 import java.lang.invoke.MethodType;
  31 import java.util.List;
  32 import java.util.ServiceConfigurationError;


  33 import jdk.dynalink.CallSiteDescriptor;
  34 import jdk.dynalink.DynamicLinker;
  35 import jdk.dynalink.DynamicLinkerFactory;
  36 import jdk.dynalink.NoSuchDynamicMethodException;

  37 import jdk.dynalink.Operation;
  38 import jdk.dynalink.StandardOperation;
  39 import jdk.dynalink.linker.GuardingDynamicLinker;
  40 import jdk.dynalink.linker.LinkRequest;
  41 import jdk.dynalink.linker.LinkerServices;
  42 import jdk.dynalink.support.SimpleRelinkableCallSite;
  43 import jdk.dynalink.linker.GuardedInvocation;

  44 import org.testng.Assert;
  45 import org.testng.annotations.Test;
  46 
  47 @SuppressWarnings("javadoc")
  48 public class DynamicLinkerFactoryTest {
  49 
  50     private static DynamicLinkerFactory newDynamicLinkerFactory(final boolean resetClassLoader) {
  51         final DynamicLinkerFactory factory = new DynamicLinkerFactory();
  52         if (resetClassLoader) {
  53             factory.setClassLoader(null);
  54         }
  55         return factory;
  56     }
  57 
  58     @Test
  59     public void callSiteCreationTest() {
  60         final DynamicLinkerFactory factory = newDynamicLinkerFactory(true);
  61         final DynamicLinker linker = factory.createLinker();
  62         final StandardOperation[] operations = StandardOperation.values();
  63         final MethodType mt = MethodType.methodType(Object.class, Object.class);
  64         for (final Operation op : operations) {
  65             final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
  66                     MethodHandles.publicLookup(), op, mt)));
  67             Assert.assertNotNull(cs);
  68             Assert.assertEquals(cs.type(), mt);
  69             Assert.assertNotNull(cs.getTarget());
  70         }
  71     }
  72 
  73     @Test
  74     public void fallbackLinkerTest() {
  75         final DynamicLinkerFactory factory = newDynamicLinkerFactory(true);
  76         final Operation myOperation = new Operation() {
  77         };
  78         final boolean[] reachedFallback = { false };
  79         factory.setFallbackLinkers((GuardingDynamicLinker) (LinkRequest linkRequest, LinkerServices linkerServices) -> {
  80             Assert.assertEquals(linkRequest.getCallSiteDescriptor().getOperation(), myOperation);
  81             reachedFallback[0] = true;
  82             return null;
  83         });
  84 
  85         final DynamicLinker linker = factory.createLinker();
  86         final MethodType mt = MethodType.methodType(Object.class);
  87         final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
  88                 MethodHandles.publicLookup(), myOperation, mt)));
  89 
  90         // linking the call site initially does not invoke the linkers!
  91         Assert.assertFalse(reachedFallback[0]);
  92         try {
  93             cs.getTarget().invoke();
  94         } catch (NoSuchDynamicMethodException nsdm) {
  95             // we do expect NoSuchDynamicMethod!
  96             // because our dummy fallback linker returns null!
  97         } catch (Throwable th) {
  98             throw new RuntimeException("should not reach here with: " + th);
  99         }
 100 
 101         // check that the control reached fallback linker!
 102         Assert.assertTrue(reachedFallback[0]);
 103     }
 104 
 105     @Test
 106     public void priorityLinkerTest() {
 107         final DynamicLinkerFactory factory = newDynamicLinkerFactory(true);
 108         final Operation myOperation = new Operation() {
 109         };
 110         final boolean[] reachedProrityLinker = { false };
 111         factory.setPrioritizedLinker((GuardingDynamicLinker) (LinkRequest linkRequest, LinkerServices linkerServices) -> {
 112             Assert.assertEquals(linkRequest.getCallSiteDescriptor().getOperation(), myOperation);
 113             reachedProrityLinker[0] = true;
 114             return null;
 115         });
 116 
 117         final DynamicLinker linker = factory.createLinker();
 118         final MethodType mt = MethodType.methodType(Object.class);
 119         final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
 120                 MethodHandles.publicLookup(), myOperation, mt)));
 121 
 122         // linking the call site initially does not invoke the linkers!
 123         Assert.assertFalse(reachedProrityLinker[0]);
 124         try {
 125             cs.getTarget().invoke();
 126         } catch (NoSuchDynamicMethodException nsdm) {
 127             // we do expect NoSuchDynamicMethod!
 128             // because our dummy priority linker returns null!
 129         } catch (Throwable th) {
 130             throw new RuntimeException("should not reach here with: " + th);
 131         }
 132 
 133         // check that the control reached fallback linker!
 134         Assert.assertTrue(reachedProrityLinker[0]);
 135     }
 136 
 137     @Test
 138     public void priorityAndFallbackLinkerTest() {
 139         final DynamicLinkerFactory factory = newDynamicLinkerFactory(true);
 140         final Operation myOperation = new Operation() {
 141         };
 142         final int[] linkerReachCounter = { 0 };
 143         factory.setPrioritizedLinker((GuardingDynamicLinker) (LinkRequest linkRequest, LinkerServices linkerServices) -> {
 144             Assert.assertEquals(linkRequest.getCallSiteDescriptor().getOperation(), myOperation);
 145             linkerReachCounter[0]++;
 146             return null;
 147         });
 148         factory.setFallbackLinkers((GuardingDynamicLinker) (LinkRequest linkRequest, LinkerServices linkerServices) -> {
 149             Assert.assertEquals(linkRequest.getCallSiteDescriptor().getOperation(), myOperation);
 150             Assert.assertEquals(linkerReachCounter[0], 1);
 151             linkerReachCounter[0]++;
 152             return null;
 153         });
 154 
 155         final DynamicLinker linker = factory.createLinker();
 156         final MethodType mt = MethodType.methodType(Object.class);
 157         final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
 158                 MethodHandles.publicLookup(), myOperation, mt)));
 159 
 160         // linking the call site initially does not invoke the linkers!
 161         Assert.assertEquals(linkerReachCounter[0], 0);
 162 
 163         try {
 164             cs.getTarget().invoke();
 165         } catch (NoSuchDynamicMethodException nsdm) {
 166             // we do expect NoSuchDynamicMethod!
 167         } catch (Throwable th) {
 168             throw new RuntimeException("should not reach here with: " + th);
 169         }
 170 
 171         Assert.assertEquals(linkerReachCounter[0], 2);
 172     }
 173 
 174     @Test
 175     public void prelinkTransformerTest() throws Throwable {
 176         final DynamicLinkerFactory factory = newDynamicLinkerFactory(true);
 177         final boolean[] reachedPrelinkTransformer = { false };
 178 
 179         factory.setPrelinkTransformer((GuardedInvocation inv, LinkRequest linkRequest, LinkerServices linkerServices) -> {
 180             reachedPrelinkTransformer[0] = true;
 181             // just identity transformer!
 182             return inv;
 183         });
 184 
 185         final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class);
 186         final DynamicLinker linker = factory.createLinker();
 187         final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
 188                 MethodHandles.publicLookup(), StandardOperation.GET_PROPERTY, mt)));
 189         Assert.assertFalse(reachedPrelinkTransformer[0]);
 190         Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class);
 191         Assert.assertTrue(reachedPrelinkTransformer[0]);
 192     }
 193 
 194     @Test
 195     public void internalObjectsFilterTest() throws Throwable {
 196         final DynamicLinkerFactory factory = newDynamicLinkerFactory(true);
 197         final boolean[] reachedInternalObjectsFilter = { false };
 198 
 199         factory.setInternalObjectsFilter((MethodHandle mh) -> {
 200             reachedInternalObjectsFilter[0] = true;
 201             return mh;
 202         });
 203 
 204         final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class);
 205         final DynamicLinker linker = factory.createLinker();
 206         final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
 207                 MethodHandles.publicLookup(), StandardOperation.GET_PROPERTY, mt)));
 208         Assert.assertFalse(reachedInternalObjectsFilter[0]);
 209         Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class);
 210         Assert.assertTrue(reachedInternalObjectsFilter[0]);
 211     }
 212 
 213     private static void checkOneAutoLoadingError(final DynamicLinkerFactory factory) {
 214         // expect one error as we have one untrusted linker exporter in META-INF/services
 215         final List<ServiceConfigurationError> autoLoadingErrors = factory.getAutoLoadingErrors();
 216         // single error ...
 217         Assert.assertFalse(autoLoadingErrors.isEmpty());
 218         final Throwable cause = autoLoadingErrors.get(0).getCause();
 219         // ..  due to permission check..
 220         Assert.assertTrue(cause.toString().contains("dynalink.exportLinkersAutomatically"));
 221     }
 222 
 223     @Test
 224     public void autoLoadedLinkerNegativeTest() {
 225         // enable auto loaded linkers
 226         final DynamicLinkerFactory factory = newDynamicLinkerFactory(false);
 227         factory.createLinker();
 228         checkOneAutoLoadingError(factory);
 229     }
 230 
 231     @Test
 232     public void autoLoadedLinkerTest() {
 233         final DynamicLinkerFactory factory = newDynamicLinkerFactory(false);
 234         final DynamicLinker linker = factory.createLinker();
 235 
 236         // we should still get one error due to untrusted dynamic linker exporter!
 237         checkOneAutoLoadingError(factory);
 238 
 239         final MethodType mt = MethodType.methodType(Object.class, Object.class);
 240         // create a callsite with TestLinkerOperation
 241         final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
 242                 MethodHandles.publicLookup(), new TestLinkerOperation(), mt)));
 243         boolean reachedAutoLinker = false;
 244 
 245 
 246         try {
 247             cs.getTarget().invoke(new Object());
 248         } catch (ReachedAutoLoadedDynamicLinkerException e) {
 249             // TrustedGuardingDynamicLinkerExporter threw exception on TestLinkerOperation as expected!
 250             reachedAutoLinker = true;
 251         } catch (Throwable th) {
 252             throw new RuntimeException(th);
 253         }
 254 
 255         Assert.assertTrue(reachedAutoLinker);








































 256     }
 257 }
--- EOF ---