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 ---