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 Joerg Schaible                                           *
009     *****************************************************************************/
010    
011    package org.picocontainer.defaults;
012    
013    /**
014     * Abstract utility class to detect recursion cycles.
015     * Derive from this class and implement {@link ThreadLocalCyclicDependencyGuard#run}. 
016     * The method will be called by  {@link ThreadLocalCyclicDependencyGuard#observe}. Select
017     * an appropriate guard for your scope. Any {@link ObjectReference} can be 
018     * used as long as it is initialized with  <code>Boolean.FALSE</code>.
019     * 
020     * @author Jörg Schaible
021     * @since 1.1
022     */
023    public abstract class ThreadLocalCyclicDependencyGuard extends ThreadLocal implements CyclicDependencyGuard {
024    
025        protected Object initialValue() {
026            return Boolean.FALSE;
027        }
028    
029        /**
030         * Derive from this class and implement this function with the functionality 
031         * to observe for a dependency cycle.
032         * 
033         * @return a value, if the functionality result in an expression, 
034         *      otherwise just return <code>null</code>
035         */
036        public abstract Object run();
037        
038        /**
039         * Call the observing function. The provided guard will hold the {@link Boolean} value.
040         * If the guard is already <code>Boolean.TRUE</code> a {@link CyclicDependencyException} 
041         * will be  thrown.
042         * 
043         * @param stackFrame the current stack frame
044         * @return the result of the <code>run</code> method
045         */
046        public final Object observe(Class stackFrame) {
047            if (Boolean.TRUE.equals(get())) {
048                throw new CyclicDependencyException(stackFrame);
049            }
050            Object result = null;
051            try {
052                set(Boolean.TRUE);
053                result = run();
054            } catch (final CyclicDependencyException e) {
055                e.push(stackFrame);
056                throw e;
057            } finally {
058                set(Boolean.FALSE);
059            }
060            return result;
061        }
062    }