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.Automatic;
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 public class PicoBuilder {
037
038 private PicoContainer parentContainer;
039 private Class<? extends MutablePicoContainer> mpcClass = DefaultPicoContainer.class;
040 private ComponentMonitor componentMonitor;
041 private List<Object> containerComps = new ArrayList<Object>();
042
043 public PicoBuilder(PicoContainer parentContainer, InjectionFactory injectionType) {
044 this.injectionType = injectionType;
045 if (parentContainer != null) {
046 this.parentContainer = parentContainer;
047 } else {
048 this.parentContainer = new EmptyPicoContainer();
049 }
050 }
051
052 public PicoBuilder(PicoContainer parentContainer) {
053 this(parentContainer, adaptiveDI());
054 }
055
056 public PicoBuilder(InjectionFactory injectionType) {
057 this(new EmptyPicoContainer(), injectionType);
058 }
059
060 public PicoBuilder() {
061 this(new EmptyPicoContainer(), adaptiveDI());
062 }
063
064 private final Stack<Object> componentFactories = new Stack<Object>();
065
066 private InjectionFactory injectionType;
067
068 private Class<? extends ComponentMonitor> componentMonitorClass = NullComponentMonitor.class;
069 private Class<? extends LifecycleStrategy> lifecycleStrategyClass = NullLifecycleStrategy.class;
070
071 public PicoBuilder withLifecycle() {
072 lifecycleStrategyClass = StartableLifecycleStrategy.class;
073 return this;
074 }
075
076 public PicoBuilder withReflectionLifecycle() {
077 lifecycleStrategyClass = ReflectionLifecycleStrategy.class;
078 return this;
079 }
080
081 public PicoBuilder withConsoleMonitor() {
082 componentMonitorClass = ConsoleComponentMonitor.class;
083 return this;
084 }
085
086 public PicoBuilder withMonitor(Class<? extends ComponentMonitor> cmClass) {
087 if (cmClass == null) {
088 throw new NullPointerException("monitor class cannot be null");
089 }
090 if (!ComponentMonitor.class.isAssignableFrom(cmClass)) {
091 throw new ClassCastException(cmClass.getName() + " is not a " + ComponentMonitor.class.getName());
092
093 }
094 componentMonitorClass = cmClass;
095 componentMonitor = null;
096 return this;
097 }
098
099 public MutablePicoContainer build() {
100
101 DefaultPicoContainer temp = new TransientPicoContainer();
102 temp.addComponent(PicoContainer.class, parentContainer);
103
104 for (Object containerComp : containerComps) {
105 temp.addComponent(containerComp);
106 }
107
108 ComponentFactory lastCaf = injectionType;
109 while (!componentFactories.empty()) {
110 Object componentFactory = componentFactories.pop();
111 DefaultPicoContainer temp2 = new TransientPicoContainer(temp);
112 temp2.addComponent("componentFactory", componentFactory);
113 if (lastCaf != null) {
114 temp2.addComponent(ComponentFactory.class, lastCaf);
115 }
116 ComponentFactory penultimateCaf = lastCaf;
117 lastCaf = (ComponentFactory) temp2.getComponent("componentFactory");
118 if (lastCaf instanceof BehaviorFactory) {
119 ((BehaviorFactory) lastCaf).wrap(penultimateCaf);
120 }
121 }
122
123 temp.addComponent(ComponentFactory.class, lastCaf);
124 if (componentMonitorClass == null) {
125 temp.addComponent(ComponentMonitor.class, componentMonitor);
126 } else {
127 temp.addComponent(ComponentMonitor.class, componentMonitorClass);
128 }
129 temp.addComponent(LifecycleStrategy.class, lifecycleStrategyClass);
130 temp.addComponent("mpc", mpcClass);
131
132
133 return (MutablePicoContainer) temp.getComponent("mpc");
134 }
135
136 public PicoBuilder withHiddenImplementations() {
137 componentFactories.push(implementationHiding());
138 return this;
139 }
140
141 public PicoBuilder withSetterInjection() {
142 injectionType = SDI();
143 return this;
144 }
145
146 public PicoBuilder withAnnotatedMethodInjection() {
147 injectionType = annotatedMethodDI();
148 return this;
149 }
150
151
152 public PicoBuilder withAnnotatedFieldInjection() {
153 injectionType = annotatedFieldDI();
154 return this;
155 }
156
157
158 public PicoBuilder withConstructorInjection() {
159 injectionType = CDI();
160 return this;
161 }
162
163 public PicoBuilder withCaching() {
164 componentFactories.push(caching());
165 return this;
166 }
167
168 public PicoBuilder withComponentFactory(ComponentFactory componentFactory) {
169 if (componentFactory == null) {
170 throw new NullPointerException("CAF cannot be null");
171 }
172 componentFactories.push(componentFactory);
173 return this;
174 }
175
176 public PicoBuilder withSynchronizing() {
177 componentFactories.push(Synchronizing.class);
178 return this;
179 }
180
181 public PicoBuilder withLocking() {
182 componentFactories.push(Locking.class);
183 return this;
184 }
185
186 public PicoBuilder withBehaviors(BehaviorFactory... factories) {
187 for (ComponentFactory componentFactory : factories) {
188 componentFactories.push(componentFactory);
189 }
190 return this;
191 }
192
193 public PicoBuilder implementedBy(Class<? extends MutablePicoContainer> containerClass) {
194 mpcClass = containerClass;
195 return this;
196 }
197
198 public PicoBuilder withMonitor(ComponentMonitor componentMonitor) {
199 this.componentMonitor = componentMonitor;
200 componentMonitorClass = null;
201 return this;
202 }
203
204 public PicoBuilder withComponentFactory(Class<? extends ComponentFactory> componentFactoryClass) {
205 componentFactories.push(componentFactoryClass);
206 return this;
207 }
208
209 public PicoBuilder withCustomContainerComponent(Object containerDependency) {
210 containerComps.add(containerDependency);
211 return this;
212 }
213
214 public PicoBuilder withPropertyApplier() {
215 componentFactories.push(PropertyApplying.class);
216 return this;
217 }
218
219 public PicoBuilder withAutomatic() {
220 componentFactories.push(Automatic.class);
221 return this;
222 }
223
224 public PicoBuilder withMethodInjection() {
225 componentFactories.push(new MethodInjection());
226 return this;
227 }
228 }