io.apiman.manager.api.core.plugin.AbstractPluginRegistry.java Source code

Java tutorial

Introduction

Here is the source code for io.apiman.manager.api.core.plugin.AbstractPluginRegistry.java

Source

/*
 * Copyright 2015 JBoss Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.apiman.manager.api.core.plugin;

import io.apiman.common.plugin.Plugin;
import io.apiman.common.plugin.PluginClassLoader;
import io.apiman.common.plugin.PluginCoordinates;
import io.apiman.common.plugin.PluginSpec;
import io.apiman.common.plugin.PluginUtils;
import io.apiman.manager.api.core.IPluginRegistry;
import io.apiman.manager.api.core.exceptions.InvalidPluginException;
import io.apiman.manager.api.core.i18n.Messages;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

/**
 * Serves as a common base class for concrete implementations of {@link IPluginRegistry}.
 *
 * @author eric.wittmann@redhat.com
 */
public abstract class AbstractPluginRegistry implements IPluginRegistry {

    private File pluginsDir;
    private Map<PluginCoordinates, Plugin> pluginCache = new HashMap<>();
    private Object mutex = new Object();

    /**
     * Constructor.
     */
    public AbstractPluginRegistry() {
    }

    /**
     * Constructor.
     * @param pluginsDir the plugin's directory
     */
    public AbstractPluginRegistry(File pluginsDir) {
        this.setPluginsDir(pluginsDir);
    }

    /**
     * @see io.apiman.manager.api.core.IPluginRegistry#loadPlugin(io.apiman.common.plugin.PluginCoordinates)
     */
    @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()), //$NON-NLS-1$
                        e);
            }
            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", //$NON-NLS-1$
                        PluginUtils.PLUGIN_SPEC_PATH), e);
            }
        }
    }

    /**
     * Creates a plugin classloader for the given plugin file.
     */
    protected PluginClassLoader createPluginClassLoader(final File pluginFile) throws IOException {
        return new PluginClassLoader(pluginFile, Thread.currentThread().getContextClassLoader()) {
            @Override
            protected File createWorkDir(File pluginArtifactFile) throws IOException {
                File workDir = new File(pluginFile.getParentFile(), ".work"); //$NON-NLS-1$
                workDir.mkdirs();
                return workDir;
            }
        };
    }

    /**
     * Downloads the plugin via its maven GAV information.  This will first look in the local
     * .m2 directory.  If the plugin is not found there, then it will try to download the
     * plugin from one of the configured remote maven repositories.
     */
    protected void downloadPlugin(File pluginFile, PluginCoordinates coordinates) {
        // First check the .m2 directory
        File m2Dir = PluginUtils.getUserM2Repository();
        if (m2Dir != null) {
            File artifactFile = PluginUtils.getM2Path(m2Dir, coordinates);
            if (artifactFile.isFile()) {
                try {
                    FileUtils.copyFile(artifactFile, pluginFile);
                    return;
                } catch (IOException e) {
                    artifactFile.delete();
                    throw new RuntimeException(e);
                }
            }
        }

        // Didn't find it in .m2, so try downloading it.
        Set<URI> repositories = getMavenRepositories();
        for (URI mavenRepoUrl : repositories) {
            if (downloadFromMavenRepo(pluginFile, coordinates, mavenRepoUrl)) {
                return;
            }
        }
    }

    /**
     * Tries to download the plugin from the given remote maven repository.
     */
    protected boolean downloadFromMavenRepo(File pluginFile, PluginCoordinates coordinates, URI mavenRepoUrl) {
        String artifactSubPath = PluginUtils.getMavenPath(coordinates);
        InputStream istream = null;
        OutputStream ostream = null;
        try {
            URL artifactUrl = new URL(mavenRepoUrl.toURL(), artifactSubPath);
            URLConnection connection = artifactUrl.openConnection();
            connection.connect();
            if (connection instanceof HttpURLConnection) {
                HttpURLConnection httpConnection = (HttpURLConnection) connection;
                if (httpConnection.getResponseCode() != 200) {
                    throw new IOException();
                }
            }

            istream = connection.getInputStream();
            ostream = new FileOutputStream(pluginFile);
            IOUtils.copy(istream, ostream);
            ostream.flush();
            return true;
        } catch (Exception e) {
            return false;
        } finally {
            IOUtils.closeQuietly(istream);
            IOUtils.closeQuietly(ostream);
        }
    }

    /**
     * A valid set of remove maven repository URLs.
     */
    protected Set<URI> getMavenRepositories() {
        return PluginUtils.getDefaultMavenRepositories();
    }

    /**
     * @param pluginsDir the pluginsDir to set
     */
    public void setPluginsDir(File pluginsDir) {
        this.pluginsDir = pluginsDir;
        if (!this.pluginsDir.exists()) {
            this.pluginsDir.mkdirs();
        }
    }

}