1 /*
2  * Copyright (C) 2008 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.inject.util;
18 
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.ImmutableSet;
21 import com.google.common.collect.Iterables;
22 import com.google.common.collect.Lists;
23 import com.google.common.collect.Maps;
24 import com.google.common.collect.Sets;
25 import com.google.inject.AbstractModule;
26 import com.google.inject.Binder;
27 import com.google.inject.Binding;
28 import com.google.inject.Key;
29 import com.google.inject.Module;
30 import com.google.inject.PrivateBinder;
31 import com.google.inject.PrivateModule;
32 import com.google.inject.Scope;
33 import com.google.inject.internal.Errors;
34 import com.google.inject.spi.DefaultBindingScopingVisitor;
35 import com.google.inject.spi.DefaultElementVisitor;
36 import com.google.inject.spi.Element;
37 import com.google.inject.spi.ElementVisitor;
38 import com.google.inject.spi.Elements;
39 import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding;
40 import com.google.inject.spi.PrivateElements;
41 import com.google.inject.spi.ScopeBinding;
42 import java.lang.annotation.Annotation;
43 import java.util.Arrays;
44 import java.util.LinkedHashSet;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.Set;
48 
49 /**
50  * Static utility methods for creating and working with instances of {@link Module}.
51  *
52  * @author jessewilson@google.com (Jesse Wilson)
53  * @since 2.0
54  */
55 public final class Modules {
Modules()56   private Modules() {}
57 
58   public static final Module EMPTY_MODULE = new EmptyModule();
59 
60   private static class EmptyModule implements Module {
61     @Override
configure(Binder binder)62     public void configure(Binder binder) {}
63   }
64 
65   /**
66    * Returns a builder that creates a module that overlays override modules over the given modules.
67    * If a key is bound in both sets of modules, only the binding from the override modules is kept.
68    * If a single {@link PrivateModule} is supplied or all elements are from a single {@link
69    * PrivateBinder}, then this will overwrite the private bindings. Otherwise, private bindings will
70    * not be overwritten unless they are exposed. This can be used to replace the bindings of a
71    * production module with test bindings:
72    *
73    * <pre>
74    * Module functionalTestModule
75    *     = Modules.override(new ProductionModule()).with(new TestModule());
76    * </pre>
77    *
78    * <p>Prefer to write smaller modules that can be reused and tested without overrides.
79    *
80    * @param modules the modules whose bindings are open to be overridden
81    */
override(Module... modules)82   public static OverriddenModuleBuilder override(Module... modules) {
83     return new RealOverriddenModuleBuilder(Arrays.asList(modules));
84   }
85 
86   /**
87    * Returns a builder that creates a module that overlays override modules over the given modules.
88    * If a key is bound in both sets of modules, only the binding from the override modules is kept.
89    * If a single {@link PrivateModule} is supplied or all elements are from a single {@link
90    * PrivateBinder}, then this will overwrite the private bindings. Otherwise, private bindings will
91    * not be overwritten unless they are exposed. This can be used to replace the bindings of a
92    * production module with test bindings:
93    *
94    * <pre>
95    * Module functionalTestModule
96    *     = Modules.override(getProductionModules()).with(getTestModules());
97    * </pre>
98    *
99    * <p>Prefer to write smaller modules that can be reused and tested without overrides.
100    *
101    * @param modules the modules whose bindings are open to be overridden
102    */
override(Iterable<? extends Module> modules)103   public static OverriddenModuleBuilder override(Iterable<? extends Module> modules) {
104     return new RealOverriddenModuleBuilder(modules);
105   }
106 
107   /** Returns a new module that installs all of {@code modules}. */
combine(Module... modules)108   public static Module combine(Module... modules) {
109     return combine(ImmutableSet.copyOf(modules));
110   }
111 
112   /** Returns a new module that installs all of {@code modules}. */
combine(Iterable<? extends Module> modules)113   public static Module combine(Iterable<? extends Module> modules) {
114     return new CombinedModule(modules);
115   }
116 
117   private static class CombinedModule implements Module {
118     final Set<Module> modulesSet;
119 
CombinedModule(Iterable<? extends Module> modules)120     CombinedModule(Iterable<? extends Module> modules) {
121       this.modulesSet = ImmutableSet.copyOf(modules);
122     }
123 
124     @Override
configure(Binder binder)125     public void configure(Binder binder) {
126       binder = binder.skipSources(getClass());
127       for (Module module : modulesSet) {
128         binder.install(module);
129       }
130     }
131   }
132 
133   /** See the EDSL example at {@link Modules#override(Module[]) override()}. */
134   public interface OverriddenModuleBuilder {
135 
136     /** See the EDSL example at {@link Modules#override(Module[]) override()}. */
with(Module... overrides)137     Module with(Module... overrides);
138 
139     /** See the EDSL example at {@link Modules#override(Module[]) override()}. */
with(Iterable<? extends Module> overrides)140     Module with(Iterable<? extends Module> overrides);
141   }
142 
143   private static final class RealOverriddenModuleBuilder implements OverriddenModuleBuilder {
144     private final ImmutableSet<Module> baseModules;
145 
RealOverriddenModuleBuilder(Iterable<? extends Module> baseModules)146     private RealOverriddenModuleBuilder(Iterable<? extends Module> baseModules) {
147       this.baseModules = ImmutableSet.copyOf(baseModules);
148     }
149 
150     @Override
with(Module... overrides)151     public Module with(Module... overrides) {
152       return with(Arrays.asList(overrides));
153     }
154 
155     @Override
with(Iterable<? extends Module> overrides)156     public Module with(Iterable<? extends Module> overrides) {
157       return new OverrideModule(overrides, baseModules);
158     }
159   }
160 
161   static class OverrideModule extends AbstractModule {
162     private final ImmutableSet<Module> overrides;
163     private final ImmutableSet<Module> baseModules;
164 
OverrideModule(Iterable<? extends Module> overrides, ImmutableSet<Module> baseModules)165     OverrideModule(Iterable<? extends Module> overrides, ImmutableSet<Module> baseModules) {
166       this.overrides = ImmutableSet.copyOf(overrides);
167       this.baseModules = baseModules;
168     }
169 
170     @Override
configure()171     public void configure() {
172       Binder baseBinder = binder();
173       List<Element> baseElements = Elements.getElements(currentStage(), baseModules);
174 
175       // If the sole element was a PrivateElements, we want to override
176       // the private elements within that -- so refocus our elements
177       // and binder.
178       if (baseElements.size() == 1) {
179         Element element = Iterables.getOnlyElement(baseElements);
180         if (element instanceof PrivateElements) {
181           PrivateElements privateElements = (PrivateElements) element;
182           PrivateBinder privateBinder =
183               baseBinder.newPrivateBinder().withSource(privateElements.getSource());
184           for (Key exposed : privateElements.getExposedKeys()) {
185             privateBinder.withSource(privateElements.getExposedSource(exposed)).expose(exposed);
186           }
187           baseBinder = privateBinder;
188           baseElements = privateElements.getElements();
189         }
190       }
191 
192       final Binder binder = baseBinder.skipSources(this.getClass());
193       final LinkedHashSet<Element> elements = new LinkedHashSet<>(baseElements);
194       final Module scannersModule = extractScanners(elements);
195       final List<Element> overrideElements =
196           Elements.getElements(
197               currentStage(),
198               ImmutableList.<Module>builder().addAll(overrides).add(scannersModule).build());
199 
200       final Set<Key<?>> overriddenKeys = Sets.newHashSet();
201       final Map<Class<? extends Annotation>, ScopeBinding> overridesScopeAnnotations =
202           Maps.newHashMap();
203 
204       // execute the overrides module, keeping track of which keys and scopes are bound
205       new ModuleWriter(binder) {
206         @Override
207         public <T> Void visit(Binding<T> binding) {
208           overriddenKeys.add(binding.getKey());
209           return super.visit(binding);
210         }
211 
212         @Override
213         public Void visit(ScopeBinding scopeBinding) {
214           overridesScopeAnnotations.put(scopeBinding.getAnnotationType(), scopeBinding);
215           return super.visit(scopeBinding);
216         }
217 
218         @Override
219         public Void visit(PrivateElements privateElements) {
220           overriddenKeys.addAll(privateElements.getExposedKeys());
221           return super.visit(privateElements);
222         }
223       }.writeAll(overrideElements);
224 
225       // execute the original module, skipping all scopes and overridden keys. We only skip each
226       // overridden binding once so things still blow up if the module binds the same thing
227       // multiple times.
228       final Map<Scope, List<Object>> scopeInstancesInUse = Maps.newHashMap();
229       final List<ScopeBinding> scopeBindings = Lists.newArrayList();
230       new ModuleWriter(binder) {
231         @Override
232         public <T> Void visit(Binding<T> binding) {
233           if (!overriddenKeys.remove(binding.getKey())) {
234             super.visit(binding);
235 
236             // Record when a scope instance is used in a binding
237             Scope scope = getScopeInstanceOrNull(binding);
238             if (scope != null) {
239               List<Object> existing = scopeInstancesInUse.get(scope);
240               if (existing == null) {
241                 existing = Lists.newArrayList();
242                 scopeInstancesInUse.put(scope, existing);
243               }
244               existing.add(binding.getSource());
245             }
246           }
247 
248           return null;
249         }
250 
251         void rewrite(Binder binder, PrivateElements privateElements, Set<Key<?>> keysToSkip) {
252           PrivateBinder privateBinder =
253               binder.withSource(privateElements.getSource()).newPrivateBinder();
254 
255           Set<Key<?>> skippedExposes = Sets.newHashSet();
256 
257           for (Key<?> key : privateElements.getExposedKeys()) {
258             if (keysToSkip.remove(key)) {
259               skippedExposes.add(key);
260             } else {
261               privateBinder.withSource(privateElements.getExposedSource(key)).expose(key);
262             }
263           }
264 
265           for (Element element : privateElements.getElements()) {
266             if (element instanceof Binding && skippedExposes.remove(((Binding) element).getKey())) {
267               continue;
268             }
269             if (element instanceof PrivateElements) {
270               rewrite(privateBinder, (PrivateElements) element, skippedExposes);
271               continue;
272             }
273             element.applyTo(privateBinder);
274           }
275         }
276 
277         @Override
278         public Void visit(PrivateElements privateElements) {
279           rewrite(binder, privateElements, overriddenKeys);
280           return null;
281         }
282 
283         @Override
284         public Void visit(ScopeBinding scopeBinding) {
285           scopeBindings.add(scopeBinding);
286           return null;
287         }
288       }.writeAll(elements);
289 
290       // execute the scope bindings, skipping scopes that have been overridden. Any scope that
291       // is overridden and in active use will prompt an error
292       new ModuleWriter(binder) {
293         @Override
294         public Void visit(ScopeBinding scopeBinding) {
295           ScopeBinding overideBinding =
296               overridesScopeAnnotations.remove(scopeBinding.getAnnotationType());
297           if (overideBinding == null) {
298             super.visit(scopeBinding);
299           } else {
300             List<Object> usedSources = scopeInstancesInUse.get(scopeBinding.getScope());
301             if (usedSources != null) {
302               StringBuilder sb =
303                   new StringBuilder(
304                       "The scope for @%s is bound directly and cannot be overridden.");
305               sb.append("%n     original binding at " + Errors.convert(scopeBinding.getSource()));
306               for (Object usedSource : usedSources) {
307                 sb.append("%n     bound directly at " + Errors.convert(usedSource) + "");
308               }
309               binder
310                   .withSource(overideBinding.getSource())
311                   .addError(sb.toString(), scopeBinding.getAnnotationType().getSimpleName());
312             }
313           }
314           return null;
315         }
316       }.writeAll(scopeBindings);
317     }
318 
getScopeInstanceOrNull(Binding<?> binding)319     private Scope getScopeInstanceOrNull(Binding<?> binding) {
320       return binding.acceptScopingVisitor(
321           new DefaultBindingScopingVisitor<Scope>() {
322             @Override
323             public Scope visitScope(Scope scope) {
324               return scope;
325             }
326           });
327     }
328   }
329 
330   private static class ModuleWriter extends DefaultElementVisitor<Void> {
331     protected final Binder binder;
332 
333     ModuleWriter(Binder binder) {
334       this.binder = binder.skipSources(this.getClass());
335     }
336 
337     @Override
338     protected Void visitOther(Element element) {
339       element.applyTo(binder);
340       return null;
341     }
342 
343     void writeAll(Iterable<? extends Element> elements) {
344       for (Element element : elements) {
345         element.acceptVisitor(this);
346       }
347     }
348   }
349 
350   private static Module extractScanners(Iterable<Element> elements) {
351     final List<ModuleAnnotatedMethodScannerBinding> scanners = Lists.newArrayList();
352     ElementVisitor<Void> visitor =
353         new DefaultElementVisitor<Void>() {
354           @Override
355           public Void visit(ModuleAnnotatedMethodScannerBinding binding) {
356             scanners.add(binding);
357             return null;
358           }
359         };
360     for (Element element : elements) {
361       element.acceptVisitor(visitor);
362     }
363     return new AbstractModule() {
364       @Override
365       protected void configure() {
366         for (ModuleAnnotatedMethodScannerBinding scanner : scanners) {
367           scanner.applyTo(binder());
368         }
369       }
370     };
371   }
372 }
373