Package org.hudsonci.inject.internal.plugin

Source Code of org.hudsonci.inject.internal.plugin.SmoothiePluginStrategy

/**
* The MIT License
*
* Copyright (c) 2010-2011 Sonatype, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package org.hudsonci.inject.internal.plugin;

import org.hudsonci.inject.SmoothieContainer;
import org.hudsonci.inject.internal.extension.ExtensionLocator;

import hudson.ExtensionComponent;
import hudson.ExtensionFinder;
import hudson.Plugin;
import hudson.PluginStrategy;
import hudson.PluginWrapper;
import hudson.PluginWrapper.Dependency;
import hudson.model.Hudson;
import hudson.util.IOException2;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.List;

import static com.google.common.base.Preconditions.checkNotNull;

/**
* Smoothie {@link PluginStrategy}.
*
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 1.397
*/
@Named("default")
@Singleton
public class SmoothiePluginStrategy
    implements PluginStrategy
{
    private static final Logger log = LoggerFactory.getLogger(SmoothiePluginStrategy.class);

    private final SmoothieContainer container;

    private final PluginWrapperFactory pluginFactory;

    private final ExtensionLocator extensionLocator;
   
    private final List<ExtensionFinder> extensionFinders;

    @Inject
    public SmoothiePluginStrategy(final SmoothieContainer container,
                                  final PluginWrapperFactory pluginFactory,
                                  final @Named("default") ExtensionLocator extensionLocator,
                                  final List<ExtensionFinder> extensionFinders) {
        this.container = checkNotNull(container);
        this.pluginFactory = checkNotNull(pluginFactory);
        this.extensionLocator = checkNotNull(extensionLocator);
        this.extensionFinders = checkNotNull(extensionFinders);
    }

    private String basename(String name) {
        assert name != null;
        if (name.endsWith("/")) {
            name = name.substring(0, name.length() - 1);
        }
        int i = name.lastIndexOf("/");
        if (i != -1) {
            return name.substring(i + 1, name.length());
        }
        return name;
    }

    /**
     * Load the plugins wrapper and inject it with the {@link SmoothieContainer}.
     */
    public PluginWrapper createPluginWrapper(final File archive) throws IOException {
        checkNotNull(archive);
        PluginWrapper plugin;
        try {
            plugin = pluginFactory.create(archive);
        }
        catch (Exception e) {
            throw new IOException2(e);
        }

        if (log.isDebugEnabled()) {
            logPluginDetails(plugin);
        }

        return plugin;
    }

    private void logPluginDetails(final PluginWrapper plugin) {
        assert plugin != null;

        log.debug("Loaded plugin: {} ({})", plugin.getShortName(), plugin.getVersion());

        // Some details are not valid until the createPluginWrapper() has returned... like bundled status

        log.debug("  State: active={}, enabled={}, pinned={}, downgradable={}", new Object[] {
            plugin.isActive(),
            plugin.isEnabled(),
            plugin.isPinned(),
            plugin.isDowngradable()
        });

        // Spit out some debug/trace details about the classpath
        PluginClassLoader cl = (PluginClassLoader)plugin.classLoader;
        URL[] classpath = cl.getURLs();
        if (classpath.length > 1) {
            log.debug("  Classpath:");
            int i=0;
            boolean trace = log.isTraceEnabled();
            for (URL url : classpath) {
                // skip the classes/ dir its always there
                if (i++ == 0) {
                    continue;
                }
                // for trace still log as debug, but flip on the full URL
                log.debug("    {}", trace ? url.toString() : basename(url.getFile()));
            }
        }

        // Spit out some debug information about the plugin dependencies
        List<Dependency> dependencies = plugin.getDependencies();
        if (dependencies != null && !dependencies.isEmpty()) {
            log.debug("  Dependencies:");
            for (Dependency dependency : dependencies) {
                log.debug("    {}", dependency);
            }
        }

        dependencies = plugin.getOptionalDependencies();
        if (dependencies != null && !dependencies.isEmpty()) {
            log.debug("  Optional dependencies:");
            for (Dependency dependency : plugin.getOptionalDependencies()) {
                log.debug("    {}", dependency);
            }
        }
    }

    /**
     * Loads the optional {@link hudson.Plugin} instance, configures and starts it.
     */
    public void load(final PluginWrapper plugin) throws IOException {
        checkNotNull(plugin);
        if (log.isDebugEnabled()) {
            log.debug("Configuring plugin: {}", plugin.getShortName());
        }

        container.register(plugin);

        ClassLoader old = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(plugin.classLoader);
        try {
            Plugin instance;

            // Load the plugin instance, if one has been configured.
            if (plugin.getPluginClass() == null) {
                instance = new Plugin.DummyImpl();
            }
            else {
                try {
                    // Ask the container to construct the instance
                    Class<? extends Plugin> type = loadPluginClass(plugin);
                    instance = container.injector(plugin).getInstance(type);
                    log.trace("Plugin instance: {}", instance);
                }
                catch (Throwable e) {
                    throw new IOException2("Failed to load plugin instance for: " + plugin.getShortName(), e);
                }
            }

            plugin.setPlugin(instance);

            try {
                start(plugin);
            }
            catch (Exception e) {
                throw new IOException2("Failed to start plugin: " + plugin.getShortName(), e);
            }
        }
        finally {
            Thread.currentThread().setContextClassLoader(old);
        }
    }

    /**
     * Isolates cast compiler warning.
     */
    @SuppressWarnings({"unchecked"})
    private Class<? extends Plugin> loadPluginClass(final PluginWrapper plugin) throws ClassNotFoundException {
        assert plugin != null;
        return (Class<? extends Plugin>) plugin.classLoader.loadClass(plugin.getPluginClass());
    }

    /**
     * Configures and starts the {@link hudson.Plugin} instance.
     */
    private void start(final PluginWrapper plugin) throws Exception {
        assert plugin != null;

        if (log.isDebugEnabled()) {
            log.debug("Starting plugin: {}", plugin.getShortName());
        }

        Plugin instance = plugin.getPlugin();
        instance.setServletContext(Hudson.getInstance().servletContext);
        instance.start();
    }

    /**
     * This method of the PluginStrategy interface is completely unused.
     */
    public void initializeComponents(final PluginWrapper plugin) {
        throw new Error("Unused operation");
    }

    public <T> List<ExtensionComponent<T>> findComponents(final Class<T> type, final Hudson hudson) {
        List<ExtensionComponent<T>> components = extensionLocator.locate(type);

        for (ExtensionFinder finder : extensionFinders) {
            try {
                try {
                    components.addAll(finder._find(type, hudson));
                } catch (AbstractMethodError e) {
                    // support legacy finders that only have the old method
                    for (T instance : finder.findExtensions(type, hudson)) {
                        components.add(new ExtensionComponent<T>(instance));
                    }
                }
            } catch (Throwable e) {
                log.warn("Failed to query ExtensionFinder: "+finder, e);                   
            }
        }

        return components;
    }
}
TOP

Related Classes of org.hudsonci.inject.internal.plugin.SmoothiePluginStrategy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.