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 temp = new TransientPicoContainer();
114 temp.addComponent(PicoContainer.class, parentContainer);
115
116 for (Object containerComp : containerComps) {
117 temp.addComponent(containerComp);
118 }
119
120 ComponentFactory lastCaf = injectionType;
121 while (!componentFactories.empty()) {
122 Object componentFactory = componentFactories.pop();
123 DefaultPicoContainer temp2 = new TransientPicoContainer(temp);
124 temp2.addComponent("componentFactory", componentFactory);
125 if (lastCaf != null) {
126 temp2.addComponent(ComponentFactory.class, lastCaf);
127 }
128 ComponentFactory penultimateCaf = lastCaf;
129 lastCaf = (ComponentFactory) temp2.getComponent("componentFactory");
130 if (lastCaf instanceof BehaviorFactory) {
131 ((BehaviorFactory) lastCaf).wrap(penultimateCaf);
132 }
133 }
134
135 temp.addComponent(ComponentFactory.class, lastCaf);
136 if (componentMonitorClass == null) {
137 temp.addComponent(ComponentMonitor.class, componentMonitor);
138 } else {
139 temp.addComponent(ComponentMonitor.class, componentMonitorClass);
140 }
141 temp.addComponent(LifecycleStrategy.class, lifecycleStrategyClass);
142 temp.addComponent("mpc", mpcClass);
143
144
145 MutablePicoContainer newContainer = (MutablePicoContainer) temp.getComponent("mpc");
146 if (addChildToParent) {
147 if (parentContainer instanceof MutablePicoContainer) {
148 ((MutablePicoContainer)parentContainer).addChildContainer(newContainer);
149 } else {
150 throw new PicoCompositionException("If using addChildContainer() the parent must be a MutablePicoContainer");
151 }
152 }
153 return newContainer;
154 }
155
156 public PicoBuilder withHiddenImplementations() {
157 componentFactories.push(implementationHiding());
158 return this;
159 }
160
161 public PicoBuilder withSetterInjection() {
162 injectionType = SDI();
163 return this;
164 }
165
166 public PicoBuilder withAnnotatedMethodInjection() {
167 injectionType = annotatedMethodDI();
168 return this;
169 }
170
171
172 public PicoBuilder withAnnotatedFieldInjection() {
173 injectionType = annotatedFieldDI();
174 return this;
175 }
176
177
178 public PicoBuilder withConstructorInjection() {
179 injectionType = CDI();
180 return this;
181 }
182
183 public PicoBuilder withCaching() {
184 componentFactories.push(caching());
185 return this;
186 }
187
188 public PicoBuilder withComponentFactory(ComponentFactory componentFactory) {
189 if (componentFactory == null) {
190 throw new NullPointerException("CAF cannot be null");
191 }
192 componentFactories.push(componentFactory);
193 return this;
194 }
195
196 public PicoBuilder withSynchronizing() {
197 componentFactories.push(Synchronizing.class);
198 return this;
199 }
200
201 public PicoBuilder withLocking() {
202 componentFactories.push(Locking.class);
203 return this;
204 }
205
206 public PicoBuilder withBehaviors(BehaviorFactory... factories) {
207 for (ComponentFactory componentFactory : factories) {
208 componentFactories.push(componentFactory);
209 }
210 return this;
211 }
212
213 public PicoBuilder implementedBy(Class<? extends MutablePicoContainer> containerClass) {
214 mpcClass = containerClass;
215 return this;
216 }
217
218 public PicoBuilder withMonitor(ComponentMonitor componentMonitor) {
219 this.componentMonitor = componentMonitor;
220 componentMonitorClass = null;
221 return this;
222 }
223
224 public PicoBuilder withComponentFactory(Class<? extends ComponentFactory> componentFactoryClass) {
225 componentFactories.push(componentFactoryClass);
226 return this;
227 }
228
229 public PicoBuilder withCustomContainerComponent(Object containerDependency) {
230 containerComps.add(containerDependency);
231 return this;
232 }
233
234 public PicoBuilder withPropertyApplier() {
235 componentFactories.push(PropertyApplying.class);
236 return this;
237 }
238
239 public PicoBuilder withAutomatic() {
240 componentFactories.push(Automating.class);
241 return this;
242 }
243
244 public PicoBuilder withMethodInjection() {
245 componentFactories.push(new MethodInjection());
246 return this;
247 }
248
249 public PicoBuilder addChildToParent() {
250 addChildToParent = true;
251 return this;
252 }
253 }