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 */ 25package jdk.tools.jlink.internal; 26 27import java.util.ArrayList; 28import java.util.HashMap; 29import java.util.Iterator; 30import java.util.List; 31import java.util.Map; 32import java.util.Objects; 33import java.util.ServiceLoader; 34import jdk.tools.jlink.plugin.Plugin; 35import jdk.tools.jlink.plugin.PluginException; 36 37/** 38 * 39 * Plugin Providers repository. Plugin Providers are 40 * retrieved thanks to the ServiceLoader mechanism. 41 */ 42public final class PluginRepository { 43 44 private PluginRepository() { 45 } 46 47 private static final Map<String, Plugin> registeredPlugins = new HashMap<>(); 48 49 /** 50 * Retrieves the plugin associated to the passed name. If multiple providers 51 * exist for the same name, 52 * then an exception is thrown. 53 * @param name The plugin provider name. 54 * @param pluginsLayer 55 * @return A provider or null if not found. 56 */ 57 public static Plugin getPlugin(String name, 58 ModuleLayer pluginsLayer) { 59 return getPlugin(Plugin.class, name, pluginsLayer); 60 } 61 62 /** 63 * Build plugin for the passed name. 64 * 65 * @param config Optional config. 66 * @param name Non null name. 67 * @param pluginsLayer 68 * @return A plugin or null if no plugin found. 69 */ 70 public static Plugin newPlugin(Map<String, String> config, String name, 71 ModuleLayer pluginsLayer) { 72 Objects.requireNonNull(name); 73 Objects.requireNonNull(pluginsLayer); 74 Plugin plugin = getPlugin(name, pluginsLayer); 75 if (plugin != null) { 76 try { 77 plugin.configure(config); 78 } catch (IllegalArgumentException e) { 79 if (JlinkTask.DEBUG) { 80 System.err.println("Plugin " + plugin.getName() + " threw exception with config: " + config); 81 e.printStackTrace(); 82 } 83 throw e; 84 } 85 } 86 return plugin; 87 } 88 89 /** 90 * Explicit registration of a plugin in the repository. Used by unit tests 91 * @param plugin The plugin to register. 92 */ 93 public synchronized static void registerPlugin(Plugin plugin) { 94 Objects.requireNonNull(plugin); 95 registeredPlugins.put(plugin.getName(), plugin); 96 } 97 98 /** 99 * Explicit unregistration of a plugin in the repository. Used by unit 100 * tests 101 * 102 * @param name Plugin name 103 */ 104 public synchronized static void unregisterPlugin(String name) { 105 Objects.requireNonNull(name); 106 registeredPlugins.remove(name); 107 } 108 109 public static List<Plugin> getPlugins(ModuleLayer pluginsLayer) { 110 return getPlugins(Plugin.class, pluginsLayer); 111 } 112 113 private static <T extends Plugin> T getPlugin(Class<T> clazz, String name, 114 ModuleLayer pluginsLayer) { 115 Objects.requireNonNull(name); 116 Objects.requireNonNull(pluginsLayer); 117 @SuppressWarnings("unchecked") 118 T provider = null; 119 List<T> javaProviders = getPlugins(clazz, pluginsLayer); 120 for(T factory : javaProviders) { 121 if (factory.getName().equals(name)) { 122 if (provider != null) { 123 throw new PluginException("Multiple plugin " 124 + "for the name " + name); 125 } 126 provider = factory; 127 } 128 } 129 return provider; 130 } 131 132 /** 133 * The plugins accessible in the current context. 134 * 135 * @param pluginsLayer 136 * @return The list of plugins. 137 */ 138 private static <T extends Plugin> List<T> getPlugins(Class<T> clazz, ModuleLayer pluginsLayer) { 139 Objects.requireNonNull(pluginsLayer); 140 List<T> factories = new ArrayList<>(); 141 try { 142 Iterator<T> providers 143 = ServiceLoader.load(pluginsLayer, clazz).iterator(); 144 while (providers.hasNext()) { 145 factories.add(providers.next()); 146 } 147 registeredPlugins.values().stream().forEach((fact) -> { 148 if (clazz.isInstance(fact)) { 149 @SuppressWarnings("unchecked") 150 T trans = (T) fact; 151 factories.add(trans); 152 } 153 }); 154 return factories; 155 } catch (Exception ex) { 156 throw new PluginException(ex); 157 } 158 } 159 160} 161