@Override
    public Plugin loadPlugin(PluginCoordinates coordinates) throws InvalidPluginException {
        boolean isSnapshot = PluginUtils.isSnapshot(coordinates);
        synchronized (mutex) {
            if (pluginCache.containsKey(coordinates)) {
                Plugin cachedPlugin = pluginCache.get(coordinates);
                if (isSnapshot) {
                    pluginCache.remove(coordinates);
                    try { cachedPlugin.getLoader().close(); } catch (IOException e) { e.printStackTrace(); }
                } else {
                    return cachedPlugin;
                }
            }
            String pluginRelativePath = PluginUtils.getPluginRelativePath(coordinates);
            File pluginDir = new File(pluginsDir, pluginRelativePath);
            if (!pluginDir.exists()) {
                pluginDir.mkdirs();
            }
            File pluginFile = new File(pluginDir, "plugin." + coordinates.getType()); //$NON-NLS-1$

            // Clean up stale files in the case of a snapshot.
            if (pluginFile.exists() && isSnapshot) {
                try {
                    FileUtils.deleteDirectory(pluginFile.getParentFile());
                    pluginFile.getParentFile().mkdirs();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            // Doesn't exist (or it's a snapshot)?  Better download it.
            if (!pluginFile.exists()) {
                downloadPlugin(pluginFile, coordinates);
            }
            // Still doesn't exist?  That's a failure.
            if (!pluginFile.exists()) {
                throw new InvalidPluginException(Messages.i18n.format("AbstractPluginRegistry.PluginNotFound")); //$NON-NLS-1$
            }
            PluginClassLoader pluginClassLoader;
            try {
                pluginClassLoader = createPluginClassLoader(pluginFile);
            } catch (IOException e) {
                throw new InvalidPluginException(Messages.i18n.format("AbstractPluginRegistry.InvalidPlugin", pluginFile.getAbsolutePath()), e); //$NON-NLS-1$
            }
            URL specFile = pluginClassLoader.getResource(PluginUtils.PLUGIN_SPEC_PATH);
            if (specFile == null) {
                throw new InvalidPluginException(Messages.i18n.format("AbstractPluginRegistry.MissingPluginSpecFile", PluginUtils.PLUGIN_SPEC_PATH)); //$NON-NLS-1$
            }
            try {
                PluginSpec spec = PluginUtils.readPluginSpecFile(specFile);
                Plugin plugin = new Plugin(spec, coordinates, pluginClassLoader);
                pluginCache.put(coordinates, plugin);
                return plugin;
            } catch (Exception e) {
                throw new InvalidPluginException(Messages.i18n.format("AbstractPluginRegistry.FailedToReadSpecFile", PluginUtils.PLUGIN_SPEC_PATH), e); //$NON-NLS-1$
            }
        }
    }
@see io.apiman.manager.api.core.IPluginRegistry#loadPlugin(io.apiman.common.plugin.PluginCoordinates)
manager/api/core/src/main/java/io/apiman/manager/api/core/plugin/AbstractPluginRegistry.java