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 static org.picocontainer.behaviors.Behaviors.caching;
013 import static org.picocontainer.behaviors.Behaviors.implementationHiding;
014 import org.picocontainer.behaviors.PropertyApplying;
015 import org.picocontainer.behaviors.Synchronizing;
016 import org.picocontainer.behaviors.Locking;
017 import org.picocontainer.behaviors.Automating;
018 import org.picocontainer.injectors.MethodInjection;
019 import org.picocontainer.containers.EmptyPicoContainer;
020 import org.picocontainer.containers.TransientPicoContainer;
021 import static org.picocontainer.injectors.Injectors.CDI;
022 import static org.picocontainer.injectors.Injectors.annotatedMethodDI;
023 import static org.picocontainer.injectors.Injectors.annotatedFieldDI;
024 import static org.picocontainer.injectors.Injectors.SDI;
025 import static org.picocontainer.injectors.Injectors.adaptiveDI;
026 import org.picocontainer.lifecycle.NullLifecycleStrategy;
027 import org.picocontainer.lifecycle.ReflectionLifecycleStrategy;
028 import org.picocontainer.lifecycle.StartableLifecycleStrategy;
029 import org.picocontainer.monitors.ConsoleComponentMonitor;
030 import org.picocontainer.monitors.NullComponentMonitor;
031
032 import java.util.ArrayList;
033 import java.util.Stack;
034 import java.util.List;
035
036 /**
037 * Helps assembles the myriad items available to a picocontainer.
038 * <p>Simple Example:</p>
039 * <pre>
040 * MutablePicoContainer mpc = new PicoBuilder()
041 * .withCaching()
042 * .withLifecycle()
043 * .build();
044 * </pre>
045 * @author Paul Hammant
046 */
047 public class PicoBuilder {
048
049 private PicoContainer parentContainer;
050 private Class<? extends MutablePicoContainer> mpcClass = DefaultPicoContainer.class;
051 private ComponentMonitor componentMonitor;
052 private List<Object> containerComps = new ArrayList<Object>();
053 private boolean addChildToParent;
054
055 public PicoBuilder(PicoContainer parentContainer, InjectionFactory injectionType) {
056 this.injectionType = injectionType;
057 if (parentContainer != null) {
058 this.parentContainer = parentContainer;
059 } else {
060 this.parentContainer = new EmptyPicoContainer();
061 }
062 }
063
064 public PicoBuilder(PicoContainer parentContainer) {
065 this(parentContainer, adaptiveDI());
066 }
067
068 public PicoBuilder(InjectionFactory injectionType) {
069 this(new EmptyPicoContainer(), injectionType);
070 }
071
072 public PicoBuilder() {
073 this(new EmptyPicoContainer(), adaptiveDI());
074 }
075
076 private final Stack<Object> componentFactories = new Stack<Object>();
077
078 private InjectionFactory injectionType;
079
080 private Class<? extends ComponentMonitor> componentMonitorClass = NullComponentMonitor.class;
081 private Class<? extends LifecycleStrategy> lifecycleStrategyClass = NullLifecycleStrategy.class;
082
083 public PicoBuilder withLifecycle() {
084 lifecycleStrategyClass = StartableLifecycleStrategy.class;
085 return this;
086 }
087
088 public PicoBuilder withReflectionLifecycle() {
089 lifecycleStrategyClass = ReflectionLifecycleStrategy.class;
090 return this;
091 }
092
093 public PicoBuilder withConsoleMonitor() {
094 componentMonitorClass = ConsoleComponentMonitor.class;
095 return this;
096 }
097
098 public PicoBuilder withMonitor(Class<? extends ComponentMonitor> cmClass) {
099 if (cmClass == null) {
100 throw new NullPointerException("monitor class cannot be null");
101 }
102 if (!ComponentMonitor.class.isAssignableFrom(cmClass)) {
103 throw new ClassCastException(cmClass.getName() + " is not a " + ComponentMonitor.class.getName());
104
105 }
106 componentMonitorClass = cmClass;
107 componentMonitor = null;
108 return this;
109 }
110
111 public MutablePicoContainer build() {
112
113 DefaultPicoContainer tempContainer = new TransientPicoContainer();
114 tempContainer.addComponent(PicoContainer.class, parentContainer);
115
116 addContainerComponents(tempContainer);
117
118 ComponentFactory lastCaf = injectionType;
119 while (!componentFactories.empty()) {
120 lastCaf = buildComponentFactory(tempContainer, lastCaf);
121 }
122
123 tempContainer.addComponent(ComponentFactory.class, lastCaf);
124
125 buildComponentMonitor(tempContainer);
126
127 tempContainer.addComponent(LifecycleStrategy.class, lifecycleStrategyClass);
128 tempContainer.addComponent("mpc", mpcClass);
129
130 MutablePicoContainer newContainer = (MutablePicoContainer) tempContainer.getComponent("mpc");
131
132 addChildToParent(newContainer);
133 return newContainer;
134 }
135
136 private void buildComponentMonitor(DefaultPicoContainer tempContainer) {
137 if (componentMonitorClass == null) {
138 tempContainer.addComponent(ComponentMonitor.class, componentMonitor);
139 } else {
140 tempContainer.addComponent(ComponentMonitor.class, componentMonitorClass);
141 }
142 }
143
144 private void addChildToParent(MutablePicoContainer newContainer) {
145 if (addChildToParent) {
146 if (parentContainer instanceof MutablePicoContainer) {
147 ((MutablePicoContainer)parentContainer).addChildContainer(newContainer);
148 } else {
149 throw new PicoCompositionException("If using addChildContainer() the parent must be a MutablePicoContainer");
150 }
151 }
152 }
153
154 private void addContainerComponents(DefaultPicoContainer temp) {
155 for (Object containerComp : containerComps) {
156 temp.addComponent(containerComp);
157 }
158 }
159
160 private ComponentFactory buildComponentFactory(DefaultPicoContainer container, final ComponentFactory lastCaf) {
161 Object componentFactory = componentFactories.pop();
162 DefaultPicoContainer tmpContainer = new TransientPicoContainer(container);
163 tmpContainer.addComponent("componentFactory", componentFactory);
164 if (lastCaf != null) {
165 tmpContainer.addComponent(ComponentFactory.class, lastCaf);
166 }
167 ComponentFactory newlastCaf = (ComponentFactory) tmpContainer.getComponent("componentFactory");
168 if (newlastCaf instanceof BehaviorFactory) {
169 ((BehaviorFactory) newlastCaf).wrap(lastCaf);
170 }
171 return newlastCaf;
172 }
173
174 public PicoBuilder withHiddenImplementations() {
175 componentFactories.push(implementationHiding());
176 return this;
177 }
178
179 public PicoBuilder withSetterInjection() {
180 injectionType = SDI();
181 return this;
182 }
183
184 public PicoBuilder withAnnotatedMethodInjection() {
185 injectionType = annotatedMethodDI();
186 return this;
187 }
188
189
190 public PicoBuilder withAnnotatedFieldInjection() {
191 injectionType = annotatedFieldDI();
192 return this;
193 }
194
195
196 public PicoBuilder withConstructorInjection() {
197 injectionType = CDI();
198 return this;
199 }
200
201 public PicoBuilder withCaching() {
202 componentFactories.push(caching());
203 return this;
204 }
205
206 public PicoBuilder withComponentFactory(ComponentFactory componentFactory) {
207 if (componentFactory == null) {
208 throw new NullPointerException("CAF cannot be null");
209 }
210 componentFactories.push(componentFactory);
211 return this;
212 }
213
214 public PicoBuilder withSynchronizing() {
215 componentFactories.push(Synchronizing.class);
216 return this;
217 }
218
219 public PicoBuilder withLocking() {
220 componentFactories.push(Locking.class);
221 return this;
222 }
223
224 public PicoBuilder withBehaviors(BehaviorFactory... factories) {
225 for (ComponentFactory componentFactory : factories) {
226 componentFactories.push(componentFactory);
227 }
228 return this;
229 }
230
231 public PicoBuilder implementedBy(Class<? extends MutablePicoContainer> containerClass) {
232 mpcClass = containerClass;
233 return this;
234 }
235
236 public PicoBuilder withMonitor(ComponentMonitor componentMonitor) {
237 this.componentMonitor = componentMonitor;
238 componentMonitorClass = null;
239 return this;
240 }
241
242 public PicoBuilder withComponentFactory(Class<? extends ComponentFactory> componentFactoryClass) {
243 componentFactories.push(componentFactoryClass);
244 return this;
245 }
246
247 public PicoBuilder withCustomContainerComponent(Object containerDependency) {
248 containerComps.add(containerDependency);
249 return this;
250 }
251
252 public PicoBuilder withPropertyApplier() {
253 componentFactories.push(PropertyApplying.class);
254 return this;
255 }
256
257 public PicoBuilder withAutomatic() {
258 componentFactories.push(Automating.class);
259 return this;
260 }
261
262 public PicoBuilder withMethodInjection() {
263 componentFactories.push(new MethodInjection());
264 return this;
265 }
266
267 public PicoBuilder addChildToParent() {
268 addChildToParent = true;
269 return this;
270 }
271 }