View Javadoc

1   /*
2    * Grapht, an open source dependency injector.
3    * Copyright 2014-2015 various contributors (see CONTRIBUTORS.txt)
4    * Copyright 2010-2014 Regents of the University of Minnesota
5    *
6    * This program is free software; you can redistribute it and/or modify
7    * it under the terms of the GNU Lesser General Public License as
8    * published by the Free Software Foundation; either version 2.1 of the
9    * License, or (at your option) any later version.
10   *
11   * This program is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14   * details.
15   *
16   * You should have received a copy of the GNU General Public License along with
17   * this program; if not, write to the Free Software Foundation, Inc., 51
18   * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19   */
20  package org.grouplens.grapht;
21  
22  import org.grouplens.grapht.BindingFunctionBuilder.RuleSet;
23  import org.grouplens.grapht.solver.BindingFunction;
24  import org.grouplens.grapht.solver.DefaultDesireBindingFunction;
25  import org.grouplens.grapht.solver.DefaultInjector;
26  import org.grouplens.grapht.solver.ProviderBindingFunction;
27  import org.grouplens.grapht.context.ContextPattern;
28  import org.grouplens.grapht.util.ClassLoaders;
29  import org.grouplens.grapht.util.Types;
30  
31  import java.lang.annotation.Annotation;
32  
33  /**
34   * <p>
35   * InjectorBuilder is a Builder implementation that is capable of creating a
36   * simple {@link Injector}. Additionally, it is root {@link Context} to make
37   * configuring the built Injector as easy as possible. Injectors created by
38   * InjectorBuilder instances memoize their created objects.
39   * </p>
40   * <p>
41   * Internally, it uses an {@link BindingFunctionBuilder} to accumulate
42   * bind rules and a {@link DefaultInjector} to resolve dependencies.
43   * 
44   * @author <a href="http://grouplens.org">GroupLens Research</a>
45   */
46  public class InjectorBuilder extends AbstractContext {
47      private final ClassLoader classLoader;
48      private final BindingFunctionBuilder builder;
49      private CachePolicy cachePolicy;
50      private boolean enableProviderInjection;
51  
52      /**
53       * Create a new injector builder.
54       * @param bld The binding function builder.
55       */
56      private InjectorBuilder(ClassLoader loader, BindingFunctionBuilder bld) {
57          classLoader = loader;
58          builder = bld;
59          cachePolicy = CachePolicy.MEMOIZE;
60          enableProviderInjection = false;
61      }
62  
63      /**
64       * Create a new InjectorBuilder that automatically applies the given Modules
65       * via {@link #applyModule(Module)}. Additional Modules can be applied later
66       * as well. Configuration via the {@link Context} interface is also possible
67       * (and recommended if Modules aren't used) before calling {@link #build()}.
68       * 
69       * @param modules Any modules to apply immediately
70       * @deprecated use {@link #create(Module...)} instead
71       */
72      @Deprecated
73      public InjectorBuilder(Module... modules) {
74          this(Types.getDefaultClassLoader(), new BindingFunctionBuilder());
75          for (Module m: modules) {
76              applyModule(m);
77          }
78      }
79  
80      /**
81       * Create a new injector builder using the specified class loader.
82       * @param loader The class loader.
83       * @param modules The initial modules to configure.
84       * @return The injector builder.
85       */
86      public static InjectorBuilder create(ClassLoader loader, Module... modules) {
87          InjectorBuilder bld = new InjectorBuilder(loader, new BindingFunctionBuilder(true));
88          for (Module m: modules) {
89              bld.applyModule(m);
90          }
91          return bld;
92      }
93  
94      /**
95       * Create a new injector builder with the default SPI.
96       * @param modules The initial modules to configure.
97       * @return The injector builder.
98       */
99      public static InjectorBuilder create(Module... modules) {
100         return create(ClassLoaders.inferDefault(), modules);
101     }
102     
103     /**
104      * Set the default cache policy used by injectors created by this builder.
105      * 
106      * @param policy The default policy
107      * @return This builder
108      * @throws NullPointerException if policy is null
109      * @throws IllegalArgumentException if policy is NO_PREFERENCE
110      */
111     public InjectorBuilder setDefaultCachePolicy(CachePolicy policy) {
112         if (policy.equals(CachePolicy.NO_PREFERENCE)) {
113             throw new IllegalArgumentException("Cannot be NO_PREFERENCE");
114         }
115         
116         cachePolicy = policy;
117         return this;
118     }
119     
120     /**
121      * Set whether or not to enable provider injection support in the built
122      * Injectors.
123      * 
124      * @param enable True if the injector should support "provider injection"
125      * @return This builder
126      */
127     public InjectorBuilder setProviderInjectionEnabled(boolean enable) {
128         enableProviderInjection = enable;
129         return this;
130     }
131     
132     @Override
133     public <T> Binding<T> bind(Class<T> type) {
134         return builder.getRootContext().bind(type);
135     }
136     
137     @Override
138     public <T> Binding<T> bindAny(Class<T> type) {
139         return builder.getRootContext().bindAny(type);
140     }
141     
142     @Override
143     public Context within(Class<?> type) {
144         return builder.getRootContext().within(type);
145     }
146 
147     @Override
148     public Context within(Class<? extends Annotation> qualifier, Class<?> type) {
149         return builder.getRootContext().within(qualifier, type);
150     }
151     
152     @Override
153     public Context within(Annotation annot, Class<?> type) {
154         return builder.getRootContext().within(annot, type);
155     }
156 
157     @Override
158     public Context matching(ContextPattern pattern) {
159         return builder.getRootContext().matching(pattern);
160     }
161 
162     @Override
163     public Context at(Class<?> type) {
164         return builder.getRootContext().at(type);
165     }
166 
167     @Override
168     public Context at(Class<? extends Annotation> qualifier, Class<?> type) {
169         return builder.getRootContext().at(qualifier, type);
170     }
171 
172     @Override
173     public Context at(Annotation annot, Class<?> type) {
174         return builder.getRootContext().at(annot, type);
175     }
176 
177     /**
178      * Apply a module to the root context of this InjectorBuilder (i.e.
179      * {@link Module#configure(Context)}).
180      * 
181      * @param module The module to apply
182      * @return This InjectorBuilder
183      */
184     public InjectorBuilder applyModule(Module module) {
185         builder.applyModule(module);
186         return this;
187     }
188 
189     public Injector build() {
190         BindingFunction[] functions;
191         if (enableProviderInjection) {
192             functions = new BindingFunction[] { 
193                 builder.build(RuleSet.EXPLICIT),
194                 builder.build(RuleSet.INTERMEDIATE_TYPES),
195                 builder.build(RuleSet.SUPER_TYPES),
196                 new ProviderBindingFunction(), // insert extra provider injection
197                 DefaultDesireBindingFunction.create(classLoader)
198             };
199         } else {
200             functions = new BindingFunction[] { 
201                 builder.build(RuleSet.EXPLICIT),
202                 builder.build(RuleSet.INTERMEDIATE_TYPES),
203                 builder.build(RuleSet.SUPER_TYPES),
204                 DefaultDesireBindingFunction.create(classLoader)
205             };
206         }
207         
208         return new DefaultInjector(cachePolicy, 100, functions);
209     }
210 }