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 }