    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    }