001 package org.picocontainer.containers; 002 003 import java.lang.annotation.Annotation; 004 005 import org.picocontainer.ComponentAdapter; 006 import org.picocontainer.ComponentFactory; 007 import org.picocontainer.ComponentMonitor; 008 import org.picocontainer.DefaultPicoContainer; 009 import org.picocontainer.LifecycleStrategy; 010 import org.picocontainer.MutablePicoContainer; 011 import org.picocontainer.NameBinding; 012 import org.picocontainer.PicoContainer; 013 import org.picocontainer.behaviors.AdaptingBehavior; 014 import org.picocontainer.injectors.AdaptingInjection; 015 016 @SuppressWarnings("serial") 017 public class TieringPicoContainer extends DefaultPicoContainer { 018 019 /** 020 * Creates a new container with a custom ComponentFactory, LifecycleStrategy for instance registration, 021 * and a parent container. 022 * <em> 023 * Important note about caching: If you intend the components to be cached, you should pass 024 * in a factory that creates {@link org.picocontainer.behaviors.Cached} instances, such as for example 025 * {@link org.picocontainer.behaviors.Caching}. Caching can delegate to other ComponentAdapterFactories. 026 * </em> 027 * 028 * @param componentFactory the factory to use for creation of ComponentAdapters. 029 * @param lifecycleStrategy 030 * the lifecycle strategy chosen for registered 031 * instance (not implementations!) 032 * @param parent the parent container (used for component dependency lookups). 033 */ 034 public TieringPicoContainer(final ComponentFactory componentFactory, final LifecycleStrategy lifecycleStrategy, 035 final PicoContainer parent) { 036 super(componentFactory, lifecycleStrategy, parent); 037 } 038 039 public TieringPicoContainer(final ComponentFactory componentFactory, final LifecycleStrategy lifecycleStrategy, 040 final PicoContainer parent, final ComponentMonitor componentMonitor) { 041 super(componentFactory, lifecycleStrategy, parent, componentMonitor); 042 } 043 044 /** 045 * Creates a new container with the AdaptingInjection using a 046 * custom ComponentMonitor 047 * 048 * @param monitor the ComponentMonitor to use 049 * @param parent the parent container (used for component dependency lookups). 050 */ 051 public TieringPicoContainer(final ComponentMonitor monitor, final PicoContainer parent) { 052 super(monitor, parent); 053 } 054 055 /** 056 * Creates a new container with the AdaptingInjection using a 057 * custom ComponentMonitor and lifecycle strategy 058 * 059 * @param monitor the ComponentMonitor to use 060 * @param lifecycleStrategy the lifecycle strategy to use. 061 * @param parent the parent container (used for component dependency lookups). 062 */ 063 public TieringPicoContainer(final ComponentMonitor monitor, final LifecycleStrategy lifecycleStrategy, 064 final PicoContainer parent) { 065 super(monitor, lifecycleStrategy, parent); 066 } 067 068 /** 069 * Creates a new container with the AdaptingInjection using a 070 * custom lifecycle strategy 071 * 072 * @param lifecycleStrategy the lifecycle strategy to use. 073 * @param parent the parent container (used for component dependency lookups). 074 */ 075 public TieringPicoContainer(final LifecycleStrategy lifecycleStrategy, final PicoContainer parent) { 076 super(lifecycleStrategy, parent); 077 } 078 079 080 /** 081 * Creates a new container with a custom ComponentFactory and no parent container. 082 * 083 * @param componentFactory the ComponentFactory to use. 084 */ 085 public TieringPicoContainer(final ComponentFactory componentFactory) { 086 super(componentFactory); 087 } 088 089 /** 090 * Creates a new container with the AdaptingInjection using a 091 * custom ComponentMonitor 092 * 093 * @param monitor the ComponentMonitor to use 094 */ 095 public TieringPicoContainer(final ComponentMonitor monitor) { 096 super(monitor); 097 } 098 099 /** 100 * Creates a new container with a (caching) {@link AdaptingInjection} 101 * and a parent container. 102 * 103 * @param parent the parent container (used for component dependency lookups). 104 */ 105 public TieringPicoContainer(final PicoContainer parent) { 106 super(parent); 107 } 108 109 /** Creates a new container with a {@link AdaptingBehavior} and no parent container. */ 110 public TieringPicoContainer() { 111 super(); 112 } 113 114 public PicoContainer getParent() { 115 return new TieringGuard(super.getParent()); 116 } 117 118 public MutablePicoContainer makeChildContainer() { 119 return new TieringPicoContainer(super.componentFactory, super.lifecycleStrategy, this, super.componentMonitor); 120 } 121 122 private static class TieringGuard extends AbstractDelegatingPicoContainer { 123 124 private static final AskingParentForComponent askingParentForComponent = new AskingParentForComponent(); 125 126 public TieringGuard(PicoContainer parent) { 127 super(parent); 128 } 129 130 public <T> ComponentAdapter<T> getComponentAdapter(Class<T> componentType, NameBinding componentNameBinding) { 131 boolean iDidIt = false; 132 try { 133 if (notYetAskingParentForComponent()) { 134 nowAskingParentForComponent(); 135 iDidIt = true; 136 return super.getComponentAdapter(componentType, componentNameBinding); 137 } else { 138 return null; 139 } 140 } finally { 141 if (iDidIt) { 142 doneAskingParentForComponent(); 143 } 144 } 145 } 146 147 private <T> void nowAskingParentForComponent() { 148 askingParentForComponent.set(Boolean.TRUE); 149 } 150 151 public <T> ComponentAdapter<T> getComponentAdapter(Class<T> componentType, Class<? extends Annotation> binding) { 152 boolean iDidIt = false; 153 try { 154 if (notYetAskingParentForComponent()) { 155 nowAskingParentForComponent(); 156 iDidIt = true; 157 return super.getComponentAdapter(componentType, binding); 158 } else { 159 return null; 160 } 161 } finally { 162 if (iDidIt) { 163 doneAskingParentForComponent(); 164 } 165 } 166 } 167 168 private <T> void doneAskingParentForComponent() { 169 askingParentForComponent.set(Boolean.FALSE); 170 } 171 172 private <T> boolean notYetAskingParentForComponent() { 173 return askingParentForComponent.get() == Boolean.FALSE; 174 } 175 176 public ComponentAdapter<?> getComponentAdapter(Object componentKey) { 177 boolean iDidIt = false; 178 try { 179 if (notYetAskingParentForComponent()) { 180 nowAskingParentForComponent(); 181 iDidIt = true; 182 return super.getComponentAdapter(componentKey); 183 } else { 184 return null; 185 } 186 } finally { 187 if (iDidIt) { 188 doneAskingParentForComponent(); 189 } 190 } 191 } 192 } 193 private static class AskingParentForComponent extends ThreadLocal { 194 protected Object initialValue() { 195 return Boolean.FALSE; 196 } 197 } 198 }