    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     * &nbsp;&nbsp;.withCaching()
    042     * &nbsp;&nbsp;.withLifecycle()
    043     * &nbsp;&nbsp;.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    }