org.hudsonci.inject.internal.SmoothieContainerImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hudson-inject Show documentation
Show all versions of hudson-inject Show documentation
Contains the strategy to wire up JSR-330 components in Hudson.
/*******************************************************************************
*
* Copyright (c) 2010-2011 Sonatype, Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*
*
*
*
*******************************************************************************/
package org.hudsonci.inject.internal;
import com.google.inject.AbstractModule;
import com.google.inject.Binding;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.name.Names;
import org.hudsonci.inject.SmoothieContainer;
import org.hudsonci.inject.internal.extension.ExtensionLocator;
import org.hudsonci.inject.internal.extension.ExtensionModule;
import org.hudsonci.inject.internal.extension.SmoothieExtensionLocator;
import org.hudsonci.inject.internal.plugin.PluginClassLoader;
import org.hudsonci.inject.internal.plugin.SmoothiePluginStrategy;
import hudson.PluginStrategy;
import hudson.PluginWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonatype.guice.bean.binders.WireModule;
import org.sonatype.guice.bean.locators.DefaultBeanLocator;
import org.sonatype.guice.bean.locators.MutableBeanLocator;
import org.sonatype.guice.bean.reflect.ClassSpace;
import org.sonatype.guice.bean.reflect.URLClassSpace;
import org.sonatype.inject.BeanEntry;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* {@link SmoothieContainer} implementation.
*
* @author Jason Dillon
* @since 1.397
*/
public class SmoothieContainerImpl
implements SmoothieContainer
{
private static final Logger log = LoggerFactory.getLogger(SmoothieContainerImpl.class);
private final MutableBeanLocator locator = new DefaultBeanLocator();
private final Injector root;
private final Map injectors = new HashMap();
public SmoothieContainerImpl(final Module... modules) {
this.root = createInjector(new BootModule(modules));
}
private Injector createInjector(final Module... modules) {
assert modules != null;
Injector injector = Guice.createInjector(new WireModule(modules));
if (log.isTraceEnabled()) {
log.trace("Created injector: {} w/bindings:", OID.get(injector));
for (Map.Entry,Binding>> entry : injector.getAllBindings().entrySet()) {
log.trace(" {} -> {}", entry.getKey(), entry.getValue());
}
}
return injector;
}
/**
* Not officially part of {@link SmoothieContainer} API, exposed for {@link org.hudsonci.inject.injecto.Injectomatic}.
*
* @since 1.397
*/
public Injector rootInjector() {
return root;
}
/**
* Common bindings.
*/
private class CommonModule
extends AbstractModule
{
private final Module[] modules;
private CommonModule(final Module[] modules) {
assert modules != null;
this.modules = modules;
}
private CommonModule() {
this(new Module[0]);
}
@Override
protected void configure() {
bind(MutableBeanLocator.class).toInstance(locator);
bind(SmoothieContainer.class).toInstance(SmoothieContainerImpl.this);
install(new HudsonModule());
for (Module module : modules) {
install(module);
}
}
}
/**
* Bindings for bootstrapping container bits. Scan path needs to be configured as additional module.
*/
private class BootModule
extends CommonModule
{
private BootModule(final Module[] modules) {
super(modules);
}
@Override
protected void configure() {
bind(PluginStrategy.class).annotatedWith(Names.named("default")).to(SmoothiePluginStrategy.class);
bind(ExtensionLocator.class).annotatedWith(Names.named("default")).to(SmoothieExtensionLocator.class);
super.configure();
}
}
// FIXME: Bootstrap probably needs to be aware of WEB-INF/lib/* bits, and should include its own ExtensionModule?
/**
* Bindings and class space for plugins.
*/
private class PluginModule
extends CommonModule
{
private final PluginWrapper plugin;
private PluginModule(final PluginWrapper plugin) {
assert plugin != null;
this.plugin = plugin;
}
@Override
protected void configure() {
ClassSpace space = createClassSpace();
install(new ExtensionModule(space, false));
super.configure();
}
private ClassSpace createClassSpace() {
URLClassSpace space;
if (plugin.classLoader instanceof PluginClassLoader) {
PluginClassLoader cl = (PluginClassLoader) plugin.classLoader;
space = new URLClassSpace(cl, cl.getURLs()); // urls logged from PluginWrapperFactory
}
else {
log.warn("Expected plugin to have PluginClassLoader; instead found: {}", plugin.classLoader.getClass().getName());
space = new URLClassSpace(plugin.classLoader);
}
return space;
}
}
public void register(final PluginWrapper plugin) {
assert plugin != null;
if (log.isTraceEnabled()) {
log.trace("Registering plugin: {}", plugin.getShortName());
}
// Don't allow re-registration of plugins
if (injectors.containsKey(plugin)) {
throw new IllegalStateException("Plugin already registered");
}
Injector injector = createInjector(new PluginModule(plugin));
injectors.put(plugin, injector);
}
public Injector injector(final PluginWrapper plugin) {
assert plugin != null;
Injector injector = injectors.get(plugin);
// All plugins must be registered
if (injector == null) {
throw new IllegalStateException("Plugin not registered");
}
return injector;
}
public Iterable> locate(final Key key) {
return locator.locate(key);
}
public T get(final Key key) {
Iterator> iter = locate(key).iterator();
assert iter != null;
if (iter.hasNext()) {
BeanEntry bean = iter.next();
log.debug("Found: {}", bean);
T value = bean.getValue();
// If more than one component is found, complain softly
if (log.isDebugEnabled()) {
if (iter.hasNext()) {
log.debug("More than one instance bound for key: {}", key);
while (iter.hasNext()) {
log.debug(" {}", iter.next());
}
}
}
return value;
}
throw new RuntimeException("No object bound for key: " + key);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy