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    }