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