1 /* 2 * Copyright (c) 2016 Mockito contributors 3 * This program is made available under the terms of the MIT License. 4 */ 5 package org.mockito.internal.configuration.plugins; 6 7 import org.mockito.plugins.PluginSwitch; 8 9 import java.lang.reflect.InvocationHandler; 10 import java.lang.reflect.Method; 11 import java.lang.reflect.Proxy; 12 13 class PluginLoader { 14 15 private final DefaultMockitoPlugins plugins; 16 private final PluginInitializer initializer; 17 18 PluginLoader(DefaultMockitoPlugins plugins, PluginInitializer initializer) { 19 this.plugins = plugins; 20 this.initializer = initializer; 21 } 22 23 PluginLoader(PluginSwitch pluginSwitch) { 24 this(new DefaultMockitoPlugins(), new PluginInitializer(pluginSwitch, null, new DefaultMockitoPlugins())); 25 } 26 27 /** 28 * @deprecated Let's avoid adding more aliases. It complicates the API. 29 * Instead of an alias, we can use fully qualified class name of the alternative implementation. 30 * <p> 31 * Adds an alias for a class name to this plugin loader. Instead of the fully qualified type name, 32 * the alias can be used as a convenience name for a known plugin. 33 */ 34 @Deprecated 35 PluginLoader(PluginSwitch pluginSwitch, String alias) { 36 this(new DefaultMockitoPlugins(), new PluginInitializer(pluginSwitch, alias, new DefaultMockitoPlugins())); 37 } 38 39 /** 40 * Scans the classpath for given pluginType. If not found, default class is used. 41 */ 42 @SuppressWarnings("unchecked") 43 <T> T loadPlugin(final Class<T> pluginType) { 44 return (T) loadPlugin(pluginType, null); 45 } 46 47 /** 48 * Scans the classpath for given {@code preferredPluginType}. If not found scan for {@code 49 * alternatePluginType}. If neither a preferred or alternate plugin is found, default to default 50 * class of {@code preferredPluginType}. 51 * 52 * @return An object of either {@code preferredPluginType} or {@code alternatePluginType} 53 */ 54 @SuppressWarnings("unchecked") 55 <PreferredType, AlternateType> Object loadPlugin(final Class<PreferredType> preferredPluginType, final Class<AlternateType> alternatePluginType) { 56 try { 57 PreferredType preferredPlugin = initializer.loadImpl(preferredPluginType); 58 if (preferredPlugin != null) { 59 return preferredPlugin; 60 } else if (alternatePluginType != null) { 61 AlternateType alternatePlugin = initializer.loadImpl(alternatePluginType); 62 if (alternatePlugin != null) { 63 return alternatePlugin; 64 } 65 } 66 67 return plugins.getDefaultPlugin(preferredPluginType); 68 } catch (final Throwable t) { 69 return Proxy.newProxyInstance(preferredPluginType.getClassLoader(), 70 new Class<?>[]{preferredPluginType}, 71 new InvocationHandler() { 72 @Override 73 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 74 throw new IllegalStateException("Could not initialize plugin: " + preferredPluginType + " (alternate: " + alternatePluginType + ")", t); 75 } 76 }); 77 } 78 } 79 } 80