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 org.picocontainer.behaviors.Automating; 013 import org.picocontainer.behaviors.Locking; 014 import org.picocontainer.behaviors.PropertyApplying; 015 import org.picocontainer.behaviors.Synchronizing; 016 import org.picocontainer.containers.EmptyPicoContainer; 017 import org.picocontainer.containers.TransientPicoContainer; 018 import org.picocontainer.injectors.CompositeInjection; 019 import org.picocontainer.injectors.MethodInjection; 020 import org.picocontainer.lifecycle.JavaEE5LifecycleStrategy; 021 import org.picocontainer.lifecycle.NullLifecycleStrategy; 022 import org.picocontainer.lifecycle.ReflectionLifecycleStrategy; 023 import org.picocontainer.lifecycle.StartableLifecycleStrategy; 024 import org.picocontainer.monitors.ConsoleComponentMonitor; 025 import org.picocontainer.monitors.NullComponentMonitor; 026 027 import java.util.ArrayList; 028 import java.util.List; 029 import java.util.Stack; 030 031 import static org.picocontainer.behaviors.Behaviors.caching; 032 import static org.picocontainer.behaviors.Behaviors.implementationHiding; 033 import static org.picocontainer.injectors.Injectors.CDI; 034 import static org.picocontainer.injectors.Injectors.SDI; 035 import static org.picocontainer.injectors.Injectors.adaptiveDI; 036 import static org.picocontainer.injectors.Injectors.annotatedFieldDI; 037 import static org.picocontainer.injectors.Injectors.annotatedMethodDI; 038 import static org.picocontainer.injectors.Injectors.namedField; 039 import static org.picocontainer.injectors.Injectors.namedMethod; 040 import static org.picocontainer.injectors.Injectors.typedFieldDI; 041 042 /** 043 * Helps assembles the myriad items available to a picocontainer. 044 * <p>Simple Example:</p> 045 * <pre> 046 * MutablePicoContainer mpc = new PicoBuilder() 047 * .withCaching() 048 * .withLifecycle() 049 * .build(); 050 * </pre> 051 * @author Paul Hammant 052 */ 053 public class PicoBuilder { 054 055 private PicoContainer parentContainer; 056 private Class<? extends MutablePicoContainer> mpcClass = DefaultPicoContainer.class; 057 private ComponentMonitor componentMonitor; 058 private List<Object> containerComps = new ArrayList<Object>(); 059 private boolean addChildToParent; 060 private LifecycleStrategy lifecycleStrategy; 061 private final Stack<Object> behaviors = new Stack<Object>(); 062 private final List<InjectionFactory> injectors = new ArrayList<InjectionFactory>(); 063 private Class<? extends ComponentMonitor> componentMonitorClass = NullComponentMonitor.class; 064 private Class<? extends LifecycleStrategy> lifecycleStrategyClass = NullLifecycleStrategy.class; 065 066 067 public PicoBuilder(PicoContainer parentContainer, InjectionFactory injectionType) { 068 this(parentContainer); 069 injectors.add(injectionType); 070 } 071 072 public PicoBuilder(PicoContainer parentContainer) { 073 if (parentContainer != null) { 074 this.parentContainer = parentContainer; 075 } else { 076 this.parentContainer = new EmptyPicoContainer(); 077 } 078 } 079 080 public PicoBuilder(InjectionFactory injectionType) { 081 this(new EmptyPicoContainer(), injectionType); 082 } 083 084 public PicoBuilder() { 085 this(new EmptyPicoContainer()); 086 } 087 088 public PicoBuilder withLifecycle() { 089 lifecycleStrategyClass = StartableLifecycleStrategy.class; 090 lifecycleStrategy = null; 091 return this; 092 } 093 094 public PicoBuilder withReflectionLifecycle() { 095 lifecycleStrategyClass = ReflectionLifecycleStrategy.class; 096 lifecycleStrategy = null; 097 return this; 098 } 099 100 public PicoBuilder withLifecycle(Class<? extends LifecycleStrategy> lifecycleStrategyClass) { 101 this.lifecycleStrategyClass = lifecycleStrategyClass; 102 lifecycleStrategy = null; 103 return this; 104 } 105 106 public PicoBuilder withJavaEE5Lifecycle() { 107 this.lifecycleStrategyClass = JavaEE5LifecycleStrategy.class; 108 lifecycleStrategy = null; 109 return this; 110 } 111 112 public PicoBuilder withLifecycle(LifecycleStrategy lifecycleStrategy) { 113 this.lifecycleStrategy = lifecycleStrategy; 114 lifecycleStrategyClass = null; 115 return this; 116 } 117 118 119 public PicoBuilder withConsoleMonitor() { 120 componentMonitorClass = ConsoleComponentMonitor.class; 121 return this; 122 } 123 124 public PicoBuilder withMonitor(Class<? extends ComponentMonitor> cmClass) { 125 if (cmClass == null) { 126 throw new NullPointerException("monitor class cannot be null"); 127 } 128 if (!ComponentMonitor.class.isAssignableFrom(cmClass)) { 129 throw new ClassCastException(cmClass.getName() + " is not a " + ComponentMonitor.class.getName()); 130 131 } 132 componentMonitorClass = cmClass; 133 componentMonitor = null; 134 return this; 135 } 136 137 public MutablePicoContainer build() { 138 139 DefaultPicoContainer tempContainer = new TransientPicoContainer(); 140 tempContainer.addComponent(PicoContainer.class, parentContainer); 141 142 addContainerComponents(tempContainer); 143 144 ComponentFactory componentFactory; 145 if (injectors.size() == 1) { 146 componentFactory = injectors.get(0); 147 } else if (injectors.size() == 0) { 148 componentFactory = adaptiveDI(); 149 } else { 150 componentFactory = new CompositeInjection(injectors.toArray(new InjectionFactory[injectors.size()])); 151 } 152 while (!behaviors.empty()) { 153 componentFactory = buildComponentFactory(tempContainer, componentFactory); 154 } 155 156 tempContainer.addComponent(ComponentFactory.class, componentFactory); 157 158 buildComponentMonitor(tempContainer); 159 160 if (lifecycleStrategy == null) { 161 tempContainer.addComponent(LifecycleStrategy.class, lifecycleStrategyClass); 162 } else { 163 tempContainer.addComponent(LifecycleStrategy.class, lifecycleStrategy); 164 165 } 166 tempContainer.addComponent("mpc", mpcClass); 167 168 MutablePicoContainer newContainer = (MutablePicoContainer) tempContainer.getComponent("mpc"); 169 170 addChildToParent(newContainer); 171 return newContainer; 172 } 173 174 private void buildComponentMonitor(DefaultPicoContainer tempContainer) { 175 if (componentMonitorClass == null) { 176 tempContainer.addComponent(ComponentMonitor.class, componentMonitor); 177 } else { 178 tempContainer.addComponent(ComponentMonitor.class, componentMonitorClass); 179 } 180 } 181 182 private void addChildToParent(MutablePicoContainer newContainer) { 183 if (addChildToParent) { 184 if (parentContainer instanceof MutablePicoContainer) { 185 ((MutablePicoContainer)parentContainer).addChildContainer(newContainer); 186 } else { 187 throw new PicoCompositionException("If using addChildContainer() the parent must be a MutablePicoContainer"); 188 } 189 } 190 } 191 192 private void addContainerComponents(DefaultPicoContainer temp) { 193 for (Object containerComp : containerComps) { 194 temp.addComponent(containerComp); 195 } 196 } 197 198 private ComponentFactory buildComponentFactory(DefaultPicoContainer container, final ComponentFactory lastCaf) { 199 Object componentFactory = behaviors.pop(); 200 DefaultPicoContainer tmpContainer = new TransientPicoContainer(container); 201 tmpContainer.addComponent("componentFactory", componentFactory); 202 if (lastCaf != null) { 203 tmpContainer.addComponent(ComponentFactory.class, lastCaf); 204 } 205 ComponentFactory newlastCaf = (ComponentFactory) tmpContainer.getComponent("componentFactory"); 206 if (newlastCaf instanceof BehaviorFactory) { 207 ((BehaviorFactory) newlastCaf).wrap(lastCaf); 208 } 209 return newlastCaf; 210 } 211 212 public PicoBuilder withHiddenImplementations() { 213 behaviors.push(implementationHiding()); 214 return this; 215 } 216 217 public PicoBuilder withSetterInjection() { 218 injectors.add(SDI()); 219 return this; 220 } 221 222 public PicoBuilder withAnnotatedMethodInjection() { 223 injectors.add(annotatedMethodDI()); 224 return this; 225 } 226 227 228 public PicoBuilder withAnnotatedFieldInjection() { 229 injectors.add(annotatedFieldDI()); 230 return this; 231 } 232 233 public PicoBuilder withTypedFieldInjection() { 234 injectors.add(typedFieldDI()); 235 return this; 236 } 237 238 239 public PicoBuilder withConstructorInjection() { 240 injectors.add(CDI()); 241 return this; 242 } 243 244 public PicoBuilder withNamedMethodInjection() { 245 injectors.add(namedMethod()); 246 return this; 247 } 248 249 public PicoBuilder withNamedFieldInjection() { 250 injectors.add(namedField()); 251 return this; 252 } 253 254 public PicoBuilder withCaching() { 255 behaviors.push(caching()); 256 return this; 257 } 258 259 public PicoBuilder withComponentFactory(ComponentFactory componentFactory) { 260 if (componentFactory == null) { 261 throw new NullPointerException("CAF cannot be null"); 262 } 263 behaviors.push(componentFactory); 264 return this; 265 } 266 267 public PicoBuilder withSynchronizing() { 268 behaviors.push(new Synchronizing()); 269 return this; 270 } 271 272 public PicoBuilder withLocking() { 273 behaviors.push(new Locking()); 274 return this; 275 } 276 277 public PicoBuilder withBehaviors(BehaviorFactory... factories) { 278 for (BehaviorFactory componentFactory : factories) { 279 behaviors.push(componentFactory); 280 } 281 return this; 282 } 283 284 public PicoBuilder implementedBy(Class<? extends MutablePicoContainer> containerClass) { 285 mpcClass = containerClass; 286 return this; 287 } 288 289 public PicoBuilder withMonitor(ComponentMonitor componentMonitor) { 290 this.componentMonitor = componentMonitor; 291 componentMonitorClass = null; 292 return this; 293 } 294 295 public PicoBuilder withComponentFactory(Class<? extends ComponentFactory> componentFactoryClass) { 296 behaviors.push(componentFactoryClass); 297 return this; 298 } 299 300 public PicoBuilder withCustomContainerComponent(Object containerDependency) { 301 containerComps.add(containerDependency); 302 return this; 303 } 304 305 public PicoBuilder withPropertyApplier() { 306 behaviors.push(new PropertyApplying()); 307 return this; 308 } 309 310 public PicoBuilder withAutomatic() { 311 behaviors.push(new Automating()); 312 return this; 313 } 314 315 public PicoBuilder withMethodInjection() { 316 injectors.add(new MethodInjection()); 317 return this; 318 } 319 320 public PicoBuilder addChildToParent() { 321 addChildToParent = true; 322 return this; 323 } 324 }