com.cloudbees.sdk.extensibility.ExtensionLoaderModule Maven / Gradle / Ivy
/*
* Copyright 2010-2013, CloudBees 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 com.cloudbees.sdk.extensibility;
import com.google.inject.AbstractModule;
import com.google.inject.Binding;
import com.google.inject.BindingAnnotation;
import com.google.inject.Injector;
import com.google.inject.Key;
import javax.inject.Named;
import javax.inject.Qualifier;
import java.lang.annotation.Annotation;
/**
* Responsible for producing {@link Binding}s inside {@link Injector}
* from a discovered extension.
*
* @author Kohsuke Kawaguchi
* @see ExtensionPoint
*/
public abstract class ExtensionLoaderModule extends AbstractModule {
/**
* The type of the extension implementation discovered.
*/
protected Class extends T> impl;
/**
* The type of the extension point.
*/
protected Class extensionPoint;
/**
* Called by {@link ExtensionFinder} to initialize this module.
*/
public void init(Class extends T> impl, Class extensionPoint) {
this.impl = impl;
this.extensionPoint = extensionPoint;
}
/**
* The default implementation of {@link ExtensionLoaderModule}.
*
* If the discovered implementation has any {@linkplain BindingAnnotation binding annotation},
* that is used as the key. This allows an extension point that supports named lookup, such as:
*
*
* @Retention(RUNTIME)
* @Target(TYPE)
* @Indexed
* @BindingAnnotation
* @ExtensionImplementation
* public @interface CLICommand {
* String value();
* }
*
* @CLICommand("acme")
* public class AcmeCommand extends Command { ... }
*
* // then somewhere else
* Command cmd = injector.getBinding(Key.get(Command.class,AnnotationLiteral.of(CLICommand.class,"acme"))
*
*
* If no binding annotation is present, this implementation creates a unique binding
* annotation, so that at least it can be looked up via {@link ExtensionPointList}.
*/
static class Default extends ExtensionLoaderModule {
@Override
protected void configure() {
Annotation qa = findQualifierAnnotation(impl);
if (qa==null)
// this is just to make it unique among others that implement the same contract
qa = AnnotationLiteral.of(Named.class,impl.getName());
binder().withSource(impl).bind(Key.get(extensionPoint, qa)).to(impl);
bind(impl);
}
private Annotation findQualifierAnnotation(Class extends T> impl) {
for (Annotation a : impl.getAnnotations()) {
Class extends Annotation> at = a.annotationType();
if (at.isAnnotationPresent(Qualifier.class)
|| at.isAnnotationPresent(BindingAnnotation.class))
return a;
}
return null;
}
}
}