001 /*****************************************************************************
002 * Copyright (C) PicoContainer Organization. All rights reserved. *
003 * ------------------------------------------------------------------------- *
004 * The software in this package is published under the terms of the BSD *
005 * style license a copy of which has been included with this distribution in *
006 * the LICENSE.txt file. *
007 * *
008 * Original code by *
009 *****************************************************************************/
010 package org.picocontainer;
011
012 import org.picocontainer.behaviors.Automating;
013 import org.picocontainer.behaviors.Locking;
014 import org.picocontainer.behaviors.PropertyApplying;
015 import org.picocontainer.behaviors.Synchronizing;
016 import org.picocontainer.containers.EmptyPicoContainer;
017 import org.picocontainer.containers.TransientPicoContainer;
018 import org.picocontainer.injectors.CompositeInjection;
019 import org.picocontainer.injectors.MethodInjection;
020 import org.picocontainer.lifecycle.JavaEE5LifecycleStrategy;
021 import org.picocontainer.lifecycle.NullLifecycleStrategy;
022 import org.picocontainer.lifecycle.ReflectionLifecycleStrategy;
023 import org.picocontainer.lifecycle.StartableLifecycleStrategy;
024 import org.picocontainer.monitors.ConsoleComponentMonitor;
025 import org.picocontainer.monitors.NullComponentMonitor;
026
027 import java.util.ArrayList;
028 import java.util.List;
029 import java.util.Stack;
030
031 import static org.picocontainer.behaviors.Behaviors.caching;
032 import static org.picocontainer.behaviors.Behaviors.implementationHiding;
033 import static org.picocontainer.injectors.Injectors.CDI;
034 import static org.picocontainer.injectors.Injectors.SDI;
035 import static org.picocontainer.injectors.Injectors.adaptiveDI;
036 import static org.picocontainer.injectors.Injectors.annotatedFieldDI;
037 import static org.picocontainer.injectors.Injectors.annotatedMethodDI;
038 import static org.picocontainer.injectors.Injectors.namedField;
039 import static org.picocontainer.injectors.Injectors.namedMethod;
040 import static org.picocontainer.injectors.Injectors.typedFieldDI;
041
042 /**
043 * Helps assembles the myriad items available to a picocontainer.
044 * <p>Simple Example:</p>
045 * <pre>
046 * MutablePicoContainer mpc = new PicoBuilder()
047 * .withCaching()
048 * .withLifecycle()
049 * .build();
050 * </pre>
051 * @author Paul Hammant
052 */
053 public class PicoBuilder {
054
055 private PicoContainer parentContainer;
056 private Class<? extends MutablePicoContainer> mpcClass = DefaultPicoContainer.class;
057 private ComponentMonitor componentMonitor;
058 private List<Object> containerComps = new ArrayList<Object>();
059 private boolean addChildToParent;
060 private LifecycleStrategy lifecycleStrategy;
061 private final Stack<Object> behaviors = new Stack<Object>();
062 private final List<InjectionFactory> injectors = new ArrayList<InjectionFactory>();
063 private Class<? extends ComponentMonitor> componentMonitorClass = NullComponentMonitor.class;
064 private Class<? extends LifecycleStrategy> lifecycleStrategyClass = NullLifecycleStrategy.class;
065
066
067 public PicoBuilder(PicoContainer parentContainer, InjectionFactory injectionType) {
068 this(parentContainer);
069 injectors.add(injectionType);
070 }
071
072 public PicoBuilder(PicoContainer parentContainer) {
073 if (parentContainer != null) {
074 this.parentContainer = parentContainer;
075 } else {
076 this.parentContainer = new EmptyPicoContainer();
077 }
078 }
079
080 public PicoBuilder(InjectionFactory injectionType) {
081 this(new EmptyPicoContainer(), injectionType);
082 }
083
084 public PicoBuilder() {
085 this(new EmptyPicoContainer());
086 }
087
088 public PicoBuilder withLifecycle() {
089 lifecycleStrategyClass = StartableLifecycleStrategy.class;
090 lifecycleStrategy = null;
091 return this;
092 }
093
094 public PicoBuilder withReflectionLifecycle() {
095 lifecycleStrategyClass = ReflectionLifecycleStrategy.class;
096 lifecycleStrategy = null;
097 return this;
098 }
099
100 public PicoBuilder withLifecycle(Class<? extends LifecycleStrategy> lifecycleStrategyClass) {
101 this.lifecycleStrategyClass = lifecycleStrategyClass;
102 lifecycleStrategy = null;
103 return this;
104 }
105
106 public PicoBuilder withJavaEE5Lifecycle() {
107 this.lifecycleStrategyClass = JavaEE5LifecycleStrategy.class;
108 lifecycleStrategy = null;
109 return this;
110 }
111
112 public PicoBuilder withLifecycle(LifecycleStrategy lifecycleStrategy) {
113 this.lifecycleStrategy = lifecycleStrategy;
114 lifecycleStrategyClass = null;
115 return this;
116 }
117
118
119 public PicoBuilder withConsoleMonitor() {
120 componentMonitorClass = ConsoleComponentMonitor.class;
121 return this;
122 }
123
124 public PicoBuilder withMonitor(Class<? extends ComponentMonitor> cmClass) {
125 if (cmClass == null) {
126 throw new NullPointerException("monitor class cannot be null");
127 }
128 if (!ComponentMonitor.class.isAssignableFrom(cmClass)) {
129 throw new ClassCastException(cmClass.getName() + " is not a " + ComponentMonitor.class.getName());
130
131 }
132 componentMonitorClass = cmClass;
133 componentMonitor = null;
134 return this;
135 }
136
137 public MutablePicoContainer build() {
138
139 DefaultPicoContainer tempContainer = new TransientPicoContainer();
140 tempContainer.addComponent(PicoContainer.class, parentContainer);
141
142 addContainerComponents(tempContainer);
143
144 ComponentFactory componentFactory;
145 if (injectors.size() == 1) {
146 componentFactory = injectors.get(0);
147 } else if (injectors.size() == 0) {
148 componentFactory = adaptiveDI();
149 } else {
150 componentFactory = new CompositeInjection(injectors.toArray(new InjectionFactory[injectors.size()]));
151 }
152 while (!behaviors.empty()) {
153 componentFactory = buildComponentFactory(tempContainer, componentFactory);
154 }
155
156 tempContainer.addComponent(ComponentFactory.class, componentFactory);
157
158 buildComponentMonitor(tempContainer);
159
160 if (lifecycleStrategy == null) {
161 tempContainer.addComponent(LifecycleStrategy.class, lifecycleStrategyClass);
162 } else {
163 tempContainer.addComponent(LifecycleStrategy.class, lifecycleStrategy);
164
165 }
166 tempContainer.addComponent("mpc", mpcClass);
167
168 MutablePicoContainer newContainer = (MutablePicoContainer) tempContainer.getComponent("mpc");
169
170 addChildToParent(newContainer);
171 return newContainer;
172 }
173
174 private void buildComponentMonitor(DefaultPicoContainer tempContainer) {
175 if (componentMonitorClass == null) {
176 tempContainer.addComponent(ComponentMonitor.class, componentMonitor);
177 } else {
178 tempContainer.addComponent(ComponentMonitor.class, componentMonitorClass);
179 }
180 }
181
182 private void addChildToParent(MutablePicoContainer newContainer) {
183 if (addChildToParent) {
184 if (parentContainer instanceof MutablePicoContainer) {
185 ((MutablePicoContainer)parentContainer).addChildContainer(newContainer);
186 } else {
187 throw new PicoCompositionException("If using addChildContainer() the parent must be a MutablePicoContainer");
188 }
189 }
190 }
191
192 private void addContainerComponents(DefaultPicoContainer temp) {
193 for (Object containerComp : containerComps) {
194 temp.addComponent(containerComp);
195 }
196 }
197
198 private ComponentFactory buildComponentFactory(DefaultPicoContainer container, final ComponentFactory lastCaf) {
199 Object componentFactory = behaviors.pop();
200 DefaultPicoContainer tmpContainer = new TransientPicoContainer(container);
201 tmpContainer.addComponent("componentFactory", componentFactory);
202 if (lastCaf != null) {
203 tmpContainer.addComponent(ComponentFactory.class, lastCaf);
204 }
205 ComponentFactory newlastCaf = (ComponentFactory) tmpContainer.getComponent("componentFactory");
206 if (newlastCaf instanceof BehaviorFactory) {
207 ((BehaviorFactory) newlastCaf).wrap(lastCaf);
208 }
209 return newlastCaf;
210 }
211
212 public PicoBuilder withHiddenImplementations() {
213 behaviors.push(implementationHiding());
214 return this;
215 }
216
217 public PicoBuilder withSetterInjection() {
218 injectors.add(SDI());
219 return this;
220 }
221
222 public PicoBuilder withAnnotatedMethodInjection() {
223 injectors.add(annotatedMethodDI());
224 return this;
225 }
226
227
228 public PicoBuilder withAnnotatedFieldInjection() {
229 injectors.add(annotatedFieldDI());
230 return this;
231 }
232
233 public PicoBuilder withTypedFieldInjection() {
234 injectors.add(typedFieldDI());
235 return this;
236 }
237
238
239 public PicoBuilder withConstructorInjection() {
240 injectors.add(CDI());
241 return this;
242 }
243
244 public PicoBuilder withNamedMethodInjection() {
245 injectors.add(namedMethod());
246 return this;
247 }
248
249 public PicoBuilder withNamedFieldInjection() {
250 injectors.add(namedField());
251 return this;
252 }
253
254 public PicoBuilder withCaching() {
255 behaviors.push(caching());
256 return this;
257 }
258
259 public PicoBuilder withComponentFactory(ComponentFactory componentFactory) {
260 if (componentFactory == null) {
261 throw new NullPointerException("CAF cannot be null");
262 }
263 behaviors.push(componentFactory);
264 return this;
265 }
266
267 public PicoBuilder withSynchronizing() {
268 behaviors.push(new Synchronizing());
269 return this;
270 }
271
272 public PicoBuilder withLocking() {
273 behaviors.push(new Locking());
274 return this;
275 }
276
277 public PicoBuilder withBehaviors(BehaviorFactory... factories) {
278 for (BehaviorFactory componentFactory : factories) {
279 behaviors.push(componentFactory);
280 }
281 return this;
282 }
283
284 public PicoBuilder implementedBy(Class<? extends MutablePicoContainer> containerClass) {
285 mpcClass = containerClass;
286 return this;
287 }
288
289 public PicoBuilder withMonitor(ComponentMonitor componentMonitor) {
290 this.componentMonitor = componentMonitor;
291 componentMonitorClass = null;
292 return this;
293 }
294
295 public PicoBuilder withComponentFactory(Class<? extends ComponentFactory> componentFactoryClass) {
296 behaviors.push(componentFactoryClass);
297 return this;
298 }
299
300 public PicoBuilder withCustomContainerComponent(Object containerDependency) {
301 containerComps.add(containerDependency);
302 return this;
303 }
304
305 public PicoBuilder withPropertyApplier() {
306 behaviors.push(new PropertyApplying());
307 return this;
308 }
309
310 public PicoBuilder withAutomatic() {
311 behaviors.push(new Automating());
312 return this;
313 }
314
315 public PicoBuilder withMethodInjection() {
316 injectors.add(new MethodInjection());
317 return this;
318 }
319
320 public PicoBuilder addChildToParent() {
321 addChildToParent = true;
322 return this;
323 }
324 }