Last active
December 10, 2015 17:49
-
-
Save bbeck/4470742 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.common.base.Objects; | |
import com.google.common.collect.Lists; | |
import com.google.inject.AbstractModule; | |
import com.google.inject.Binding; | |
import com.google.inject.BindingAnnotation; | |
import com.google.inject.Guice; | |
import com.google.inject.Inject; | |
import com.google.inject.Injector; | |
import com.google.inject.Key; | |
import com.google.inject.Module; | |
import com.google.inject.PrivateModule; | |
import com.google.inject.Provider; | |
import com.google.inject.TypeLiteral; | |
import com.google.inject.multibindings.Multibinder; | |
import java.lang.annotation.Annotation; | |
import java.lang.annotation.ElementType; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.Target; | |
import java.util.List; | |
import java.util.Set; | |
import static java.lang.annotation.RetentionPolicy.RUNTIME; | |
public class GuiceProblem { | |
public static void main(String[] args) { | |
// Pretend this came from args | |
List<Region> regions = Lists.newArrayList(US_EAST_1, US_WEST_1, US_WEST_2, EU_WEST_1); | |
Injector injector = createInjector(regions); | |
System.out.println("Crawlers:"); | |
System.out.println(" global:"); | |
System.out.println(" crawler service: " + injector.getInstance(Key.get(CrawlerService.class, GLOBAL))); | |
System.out.println(); | |
for (Region region : regions) { | |
System.out.println(" " + region + ":"); | |
System.out.println(" crawler service: " + injector.getInstance(Key.get(CrawlerService.class, region))); | |
System.out.println(); | |
} | |
System.out.println(" all crawler services:"); | |
for (CrawlerService crawler : findBindingsByType(injector, CrawlerService.class)) { | |
System.out.println(" " + crawler); | |
} | |
System.out.println(); | |
} | |
private static Injector createInjector(List<Region> regions) { | |
List<Module> modules = Lists.newArrayList(); | |
modules.add(new AWSModule()); | |
// Global modules | |
modules.add(new PrivateModule() { | |
@Override | |
protected void configure() { | |
install(new GlobalClientModule()); | |
install(new GlobalCrawlerModule()); | |
bind(CrawlerService.class).annotatedWith(GLOBAL).to(CrawlerService.class).asEagerSingleton(); | |
expose(CrawlerService.class).annotatedWith(GLOBAL); | |
} | |
}); | |
// Regional modules | |
for (final Region region : regions) { | |
modules.add(new PrivateModule() { | |
@Override | |
protected void configure() { | |
install(new RegionClientModule()); | |
install(new RegionCrawlerModule()); | |
bind(Region.class).toInstance(region); | |
bind(CrawlerService.class).annotatedWith(region).to(CrawlerService.class).asEagerSingleton(); | |
expose(CrawlerService.class).annotatedWith(region); | |
} | |
}); | |
} | |
return Guice.createInjector(modules); | |
} | |
private static <T> List<T> findBindingsByType(Injector injector, Class<T> cls) { | |
List<Binding<T>> bindings = injector.findBindingsByType(TypeLiteral.get(cls)); | |
List<T> instances = Lists.newArrayList(); | |
for (Binding<T> binding : bindings) { | |
Key<T> key = binding.getKey(); | |
T instance = injector.getInstance(key); | |
instances.add(instance); | |
} | |
return instances; | |
} | |
////////////////////////////////////////////////////////////////////// | |
// Global AWS parameters | |
////////////////////////////////////////////////////////////////////// | |
private static final class AWSCredentials {} | |
private static final class AWSModule extends AbstractModule { | |
@Override | |
protected void configure() { | |
bind(AWSCredentials.class).asEagerSingleton(); | |
} | |
} | |
////////////////////////////////////////////////////////////////////// | |
// Clients | |
////////////////////////////////////////////////////////////////////// | |
private static final class IAMClient { | |
IAMClient(AWSCredentials credentials) {} | |
} | |
private static final class IAMClientProvider implements Provider<IAMClient> { | |
private final AWSCredentials credentials; | |
@Inject IAMClientProvider(AWSCredentials credentials) { this.credentials = credentials; } | |
public IAMClient get() { return new IAMClient(credentials); } | |
} | |
private static final class EC2Client { | |
EC2Client(AWSCredentials credentials, Region region) {} | |
} | |
private static final class EC2ClientProvider implements Provider<EC2Client> { | |
private final AWSCredentials credentials; | |
private final Region region; | |
@Inject EC2ClientProvider(AWSCredentials credentials, Region region) { this.credentials = credentials; this.region = region; } | |
public EC2Client get() { return new EC2Client(credentials, region); } | |
} | |
private static final class CFNClient { | |
CFNClient(AWSCredentials credentials, Region region) {} | |
} | |
private static final class CFNClientProvider implements Provider<CFNClient> { | |
private final AWSCredentials credentials; | |
private final Region region; | |
@Inject CFNClientProvider(AWSCredentials credentials, Region region) { this.credentials = credentials; this.region = region; } | |
public CFNClient get() { return new CFNClient(credentials, region); } | |
} | |
private static final class GlobalClientModule extends AbstractModule { | |
@Override | |
protected void configure() { | |
bind(IAMClient.class).toProvider(IAMClientProvider.class).asEagerSingleton(); | |
} | |
} | |
private static final class RegionClientModule extends AbstractModule { | |
@Override | |
protected void configure() { | |
bind(EC2Client.class).toProvider(EC2ClientProvider.class).asEagerSingleton(); | |
bind(CFNClient.class).toProvider(CFNClientProvider.class).asEagerSingleton(); | |
} | |
} | |
////////////////////////////////////////////////////////////////////// | |
// Crawlers | |
////////////////////////////////////////////////////////////////////// | |
private static interface Crawler {} | |
private static final class IAMProfileCrawler implements Crawler { | |
private final IAMClient iam; | |
@Inject IAMProfileCrawler(IAMClient iam) { this.iam = iam; } | |
public String toString() { return Objects.toStringHelper(this).add("iam", iam).toString(); } | |
} | |
private static final class EC2InstanceCrawler implements Crawler { | |
private final EC2Client ec2; | |
private final Region region; | |
@Inject EC2InstanceCrawler(EC2Client ec2, Region region) { this.ec2 = ec2; this.region = region; } | |
public String toString() { return Objects.toStringHelper(this).add("ec2", ec2).add("region", region).toString(); } | |
} | |
private static final class EC2SecurityGroupCrawler implements Crawler { | |
private final EC2Client ec2; | |
private final Region region; | |
@Inject EC2SecurityGroupCrawler(EC2Client ec2, Region region) { this.ec2 = ec2; this.region = region; } | |
public String toString() { return Objects.toStringHelper(this).add("ec2", ec2).add("region", region).toString(); } | |
} | |
private static final class CFNStackCrawler implements Crawler { | |
private final CFNClient cfn; | |
private final Region region; | |
@Inject CFNStackCrawler(CFNClient cfn, Region region) { this.cfn = cfn; this.region = region; } | |
public String toString() { return Objects.toStringHelper(this).add("cfn", cfn).add("region", region).toString(); } | |
} | |
private static final class GlobalCrawlerModule extends AbstractModule { | |
@Override | |
protected void configure() { | |
Multibinder<Crawler> crawlers = Multibinder.newSetBinder(binder(), Crawler.class); | |
crawlers.addBinding().to(IAMProfileCrawler.class); | |
bind(CrawlerService.class).asEagerSingleton(); | |
} | |
} | |
private static final class RegionCrawlerModule extends AbstractModule { | |
@Override | |
protected void configure() { | |
Multibinder<Crawler> crawlers = Multibinder.newSetBinder(binder(), Crawler.class); | |
crawlers.addBinding().to(EC2InstanceCrawler.class); | |
crawlers.addBinding().to(EC2SecurityGroupCrawler.class); | |
crawlers.addBinding().to(CFNStackCrawler.class); | |
bind(CrawlerService.class).asEagerSingleton(); | |
} | |
} | |
////////////////////////////////////////////////////////////////////// | |
// Crawler service | |
////////////////////////////////////////////////////////////////////// | |
private static final class CrawlerService { | |
private final Set<Crawler> crawlers; | |
@Inject CrawlerService(Set<Crawler> crawlers) { this.crawlers = crawlers; } | |
public String toString() { return Objects.toStringHelper(this).add("crawlers", crawlers).toString(); } | |
} | |
////////////////////////////////////////////////////////////////////// | |
// Region, this is the same technique used for @Named. | |
////////////////////////////////////////////////////////////////////// | |
@Retention(RUNTIME) | |
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD }) | |
@BindingAnnotation | |
public @interface Region { | |
String name(); | |
} | |
@SuppressWarnings("ClassExplicitlyAnnotation") | |
private static final class RegionImpl implements Region { | |
private final String name; | |
public RegionImpl(String name) { this.name = name; } | |
public Class<? extends Annotation> annotationType() { return Region.class; } | |
public String name() { return name;} | |
public String toString() { return name; } | |
} | |
private static final Region GLOBAL = new RegionImpl("global"); | |
private static final Region US_EAST_1 = new RegionImpl("us-east-1"); | |
private static final Region US_WEST_1 = new RegionImpl("us-west-1"); | |
private static final Region US_WEST_2 = new RegionImpl("us-west-2"); | |
private static final Region EU_WEST_1 = new RegionImpl("eu-west-1"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment