You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@avalon.apache.org by Ryan Shaw <ry...@silveregg.co.jp> on 2002/02/18 09:54:07 UTC

[PATCH] ExcaliburComponentManager patch

Attached is a patch and unit test suite for some changes I
needed to fix problems I was having with the ECM.

Specifically:

1) Components being disposed before other components finished using them.
2) SingleThreaded Components never being disposed at all.

You can run the unit test suite with the command:

./build.sh -Djunit.test=**/ExcaliburComponentManagerTestCase.class test-subset

The test suite sets up an ECM with combinations of Components of various
lifestyles (SingleThreaded, ThreadSafe, Poolable) and behaviors (proper
releasing of other components or not) and checks to see if the two problems
mentioned above are occurring.

Please check it out and let me know if you see any problems.

Thanks,

Ryan

Re: [PATCH] ExcaliburComponentManager patch

Posted by Leif Mortenson <le...@silveregg.co.jp>.
This problem fixes some problems that we have been having with the 
current ExcalibutComponentManager, and includes tests.  So if nobody 
finds any problems testing the patch, I will go ahead and commit these 
changes in the morning.

Cheers,
Leif

Ryan Shaw wrote:

>The changes to PoolableComponentHandler (so it uses ResourceLimitingPool)
>broke the unit test suite I posted earlier, since Component instances are
>now not created until they are needed (thus the expected number of 
>Component disposals is different).
>
>I have attached the updated test suite, which works with these latest
>changes.
>
>Ryan
>
>Ryan wrote:
>
>||| I haven't been following the "ComponentManager Interface" thread in its
>||| entirety, as I occasionally like to step away from my computer for things
>||| like food and sleep. :^)
>||| 
>||| But I did notice in skimming through some of the posts that you guys were
>||| discussing Peter's "releaseless" CM. I have tried to implement that in this
>||| patch. The CM allows Composables to release components they have looked up
>||| but does not require this--it will release components for them.
>||| 
>||| Note, however, that classes with "direct" access to the CM--i.e. classes
>||| that did not obtain references to the CM via a "compose()" method--must
>||| release their components, or else warnings will be logged when those
>||| components are disposed. This is because the resource tracking is done,
>||| per Peter's suggestion, via proxy ComponentManagers provided to Composables.
>||| Classes with "direct" access do not have these proxies so their lookups
>||| are not tracked.
>||| 
>||| That also means that in a situation where classes with direct ECM access
>||| do not release their components, correct ordering of disposal is currently
>||| not guaranteed. I can think of some ways to fix this (like having the ECM
>||| keep track of "direct" lookups so it knows which "top-level" components
>||| to dispose of first in order to kick off the component disposal process)
>||| but they aren't in this patch.
>||| 
>||| Ryan
>||| 
>||| Ryan wrote:
>||| 
>||| ||| Attached is a patch and unit test suite for some changes I
>||| ||| needed to fix problems I was having with the ECM.
>||| ||| 
>||| ||| Specifically:
>||| ||| 
>||| ||| 1) Components being disposed before other components finished using them.
>||| ||| 2) SingleThreaded Components never being disposed at all.
>||| ||| 
>||| ||| You can run the unit test suite with the command:
>||| ||| 
>||| ||| ./build.sh -Djunit.test=**/ExcaliburComponentManagerTestCase.class test-subset
>||| ||| 
>||| ||| The test suite sets up an ECM with combinations of Components of various
>||| ||| lifestyles (SingleThreaded, ThreadSafe, Poolable) and behaviors (proper
>||| ||| releasing of other components or not) and checks to see if the two problems
>||| ||| mentioned above are occurring.
>||| ||| 
>||| ||| Please check it out and let me know if you see any problems.
>||| ||| 
>||| ||| Thanks,
>||| ||| 
>||| ||| Ryan
>||| 
>||| --
>||| To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
>||| For additional commands, e-mail: <ma...@jakarta.apache.org>
>||| 
>||| 
>
>
>------------------------------------------------------------------------
>
>/*
> * Copyright (C) The Apache Software Foundation. All rights reserved.
> *
> * This software is published under the terms of the Apache Software License
> * version 1.1, a copy of which has been included with this distribution in
> * the LICENSE.txt file.
> */
>package org.apache.avalon.excalibur.component.test;
>
>import org.apache.avalon.excalibur.pool.Poolable;
>import org.apache.avalon.excalibur.component.DefaultComponentPool;
>import org.apache.avalon.excalibur.component.ExcaliburComponentManager;
>import org.apache.avalon.excalibur.util.ComponentStateValidator;
>
>import org.apache.avalon.framework.logger.Logger;
>import org.apache.avalon.framework.logger.AbstractLogEnabled;
>import org.apache.avalon.framework.context.DefaultContext;
>import org.apache.avalon.framework.configuration.DefaultConfiguration;
>import org.apache.avalon.framework.configuration.Configuration;
>import org.apache.avalon.framework.component.Component;
>import org.apache.avalon.framework.component.Composable;
>import org.apache.avalon.framework.component.ComponentManager;
>import org.apache.avalon.framework.component.ComponentException;
>import org.apache.avalon.framework.activity.Disposable;
>import org.apache.avalon.framework.thread.ThreadSafe;
>import org.apache.avalon.framework.thread.SingleThreaded;
>
>import junit.framework.TestSuite;
>import junit.framework.TestCase;
>
>import org.apache.log.Hierarchy;
>import org.apache.log.Priority;
>import org.apache.log.LogTarget;
>import org.apache.log.format.PatternFormatter;
>import org.apache.log.output.io.StreamTarget;
>
>/**
> * This class is for testing the ExcaliburComponentManager to verify that
> * it is correctly handling component lifestyle management.
> *
> * @author <a href="mailto:ryan@silveregg.co.jp">Ryan Shaw</a>
> * @version $Revision$
> */
>public class ExcaliburComponentManagerTestCase extends TestCase 
>{
>    /**
>     * Here we create a suite lots of tests to test the interactions of 
>     * various types of components. Basically there are three Roles 
>     * involved: Mom, Dad, and Kid. Each of the three Roles can be 
>     * implemented by a SingleThreaded, ThreadSafe, or Poolable component.
>     * The Mom and Dad components both are Composable, and they use the
>     * ComponentManager that they are provided with to obtain references
>     * to a Kid component. The Mom and Dad components may be "Good" (they
>     * properly release their Kid) or "Bad" (they don't release their Kid).
>     *
>     * Each of the tests sets up a different combo of these component
>     * implementations and checks to make sure that everything gets disposed,
>     * and that Kids never get disposed before parents are done using them.
>     *
>     * @return a <code>TestSuite</code>
>     */
>    public static TestSuite suite()
>    {
>        TestSuite suite = new TestSuite();
>        
>        String[] behaviors  = { "Bad", "Good" }; 
>        String[] kidTypes   = { "" }; // , "BadCircular", "GoodCircular" };
>        String[] lifestyles = { "SingleThreaded" , "ThreadSafe", "Poolable" }; 
>
>        for ( int mb = 0; mb < behaviors.length; mb++ )
>        {
>            for ( int db = 0; db < behaviors.length; db++ )
>            {
>                for ( int kt = 0; kt < kidTypes.length; kt++ )
>                {
>                    for ( int ml = 0; ml < lifestyles.length; ml++ ) 
>                    {
>                        for ( int dl = 0; dl < lifestyles.length; dl++ ) 
>                        {
>                            for ( int kl = 0; kl < lifestyles.length; kl++ ) 
>                            {
>                                final String momClassName = 
>                                    lifestyles[ ml ] + behaviors[ mb ] + "Mom";
>                                final String dadClassName = 
>                                    lifestyles[ dl ] + behaviors[ db ] + "Dad";
>                                final String kidClassName = 
>                                    lifestyles[ kl ] +  kidTypes[ kt ] + "Kid";
>                                
>                                final String prefix = 
>                                    ExcaliburComponentManagerTestCase.class.getName() + "$";
>                                
>                                suite.addTest
>                                    ( new ExcaliburComponentManagerTestCase( momClassName + 
>                                                                             dadClassName + 
>                                                                             kidClassName ) 
>                                        {
>                                            public void runTest() throws Exception 
>                                            {
>                                                managerLifecycle( Class.forName
>                                                                  ( prefix + momClassName ), 
>                                                                  Class.forName
>                                                                  ( prefix + dadClassName ),
>                                                                  Class.forName
>                                                                  ( prefix + kidClassName ) );
>                                            }
>                                        }
>                                      );
>                            }
>                        }
>                    }
>                }
>            }
>        }
>        
>        return suite;
>    }
>
>    private void managerLifecycle(Class momClass, Class dadClass, Class kidClass) 
>        throws Exception
>    {
>        Configuration emptyConfig = new DefaultConfiguration( "", "" );
>        
>        m_manager.addComponent( Mom.ROLE, momClass, emptyConfig );
>        m_manager.addComponent( Dad.ROLE, dadClass, emptyConfig );
>        m_manager.addComponent( Kid.ROLE, kidClass, emptyConfig );
>        
>        m_manager.initialize();
>        
>        Component mom = m_manager.lookup( Mom.ROLE );
>        Component dad = m_manager.lookup( Dad.ROLE );
>
>        m_manager.release( mom );
>        m_manager.release( dad );
>        
>        m_manager.dispose();
>
>	checkNumberOfDisposals( momClass, dadClass, kidClass );
>    }
>    
>    private void checkNumberOfDisposals( Class momClass, Class dadClass, Class kidClass ) 
>    {
>        int momInstances = 1, dadInstances = 1;
>        
>	int kidInstances = determineNumberOfKidInstances( kidClass, momInstances, dadInstances );
>        
>        int expectedDisposals = momInstances + dadInstances + kidInstances;
>        
>        assertEquals( expectedDisposals, m_disposals ); 
>    }
>
>    private int determineNumberOfKidInstances( Class kidClass, int momInstances, int dadInstances ) 
>    {
>        int parentInstances = ( momInstances + dadInstances );
>        
>        if ( ThreadSafe.class.isAssignableFrom( kidClass ) )
>        { 
>            // parents share reference to same kid instance
>            return 1;
>        } 
>        else if ( Poolable.class.isAssignableFrom( kidClass ) )
>        {
>            int poolGrowParameter = DefaultComponentPool.DEFAULT_POOL_SIZE / 4;
>
>            int extraKidsNeeded = parentInstances % poolGrowParameter;
>            
>            if ( extraKidsNeeded > 0 )
>            {
>                // kid pool will grow to feed parents
>                return parentInstances + ( poolGrowParameter - extraKidsNeeded );
>            }
>        }
>
>        // each parent has a single kid reference
>        return parentInstances;
>    }
>
>    /* ======================================================================== *
>     *                           Test Components.                               *
>     * ======================================================================== */
>
>    public static abstract class AbstractBadParent extends AbstractLogEnabled
>        implements Component, Composable, Disposable
>    {
>        private final ComponentStateValidator m_validator = new ComponentStateValidator( this );
>        
>        protected ComponentManager m_manager;
>        protected Kid              m_kid;
>        
>        public void enableLogging( Logger logger )
>        {
>            m_validator.checkLogEnabled();
>            
>            super.enableLogging( logger );
>        }
>        
>        public void compose( ComponentManager manager ) throws ComponentException
>        {
>            m_validator.checkComposed();
>
>            m_manager = manager;
>            
>            m_kid = (Kid) m_manager.lookup( Kid.ROLE );
>        }
>
>        public void dispose()
>        {
>            m_validator.checkDisposed();
>
>            try
>            {
>                m_kid.getName();
>            } 
>            catch ( IllegalStateException ise )
>            {
>                fail( ise.getMessage() );
>            }
>            
>            m_disposals++;
>        }
>    }
>
>    public static abstract class AbstractGoodParent extends AbstractBadParent
>    {
>        public void dispose()
>        {
>            super.dispose();
>            m_manager.release( m_kid );
>        }
>    }
>    
>    public interface Mom extends Component
>    {
>        String ROLE = "Mom";
>    }
>    
>    public static class SingleThreadedBadMom extends AbstractBadParent
>        implements Mom, SingleThreaded
>    {}
>    public static class SingleThreadedGoodMom extends AbstractGoodParent
>        implements Mom, SingleThreaded
>    {}
>    public static class ThreadSafeBadMom extends AbstractBadParent
>        implements Mom, ThreadSafe
>    {}
>    public static class ThreadSafeGoodMom extends AbstractGoodParent
>        implements Mom, ThreadSafe
>    {}
>    public static class PoolableBadMom extends AbstractBadParent
>        implements Mom, Poolable
>    {}
>    public static class PoolableGoodMom extends AbstractGoodParent
>        implements Mom, Poolable
>    {}
>
>    public interface Dad extends Component
>    {
>        String ROLE = "Dad";
>    }
>    
>    public static class SingleThreadedBadDad extends AbstractBadParent
>        implements Dad, SingleThreaded
>    {}
>    public static class SingleThreadedGoodDad extends AbstractGoodParent
>        implements Dad, SingleThreaded
>    {}
>    public static class ThreadSafeBadDad extends AbstractBadParent
>        implements Dad, ThreadSafe
>    {}
>    public static class ThreadSafeGoodDad extends AbstractGoodParent
>        implements Dad, ThreadSafe
>    {}
>    public static class PoolableBadDad extends AbstractBadParent
>        implements Dad, Poolable
>    {}
>    public static class PoolableGoodDad extends AbstractGoodParent
>        implements Dad, Poolable
>    {}
>    
>    public interface Kid extends Component
>    {
>        String ROLE = "Kid";
>
>        String getName();
>    }
>    
>    public static abstract class AbstractKid extends AbstractLogEnabled
>        implements Kid, Disposable
>    {
>        public final static String ROLE = "Kid";
>
>        protected final ComponentStateValidator m_validator = new ComponentStateValidator( this );
>
>        public void enableLogging( Logger logger )
>        {
>            m_validator.checkLogEnabled();
>
>            super.enableLogging( logger );
>        }
>
>        public void dispose()
>        {
>            m_validator.checkDisposed();
>
>            m_disposals++;
>        }
>
>        public String getName()
>        {
>            m_validator.checkActive();
>            
>            return "Kid";
>        } 
>    }
>
>    public static class SingleThreadedKid extends AbstractKid
>        implements SingleThreaded
>    {}
>    public static class ThreadSafeKid extends AbstractKid
>        implements ThreadSafe
>    {}
>    public static class PoolableKid extends AbstractKid
>        implements Poolable
>    {}
>    
>    public static abstract class AbstractBadCircularKid extends AbstractKid
>        implements Composable
>    {
>        protected ComponentManager m_manager;
>        protected Mom              m_mom;
>        protected Dad              m_dad;
>        
>        public void compose( ComponentManager manager ) throws ComponentException
>        {
>            m_validator.checkComposed();
>            
>            m_manager = manager;
>        }
>
>        public String getName()
>        {
>            String name = super.getName();
>            
>            try 
>            {
>                m_mom = (Mom) m_manager.lookup( Mom.ROLE );
>                m_dad = (Dad) m_manager.lookup( Dad.ROLE );
>            }
>            catch ( ComponentException ce )
>            {
>                fail( ce.getMessage() );
>            }
>
>            return ( name + " belongs to " + m_mom + " and " + m_dad );
>        }
>    }
>
>    public static abstract class AbstractGoodCircularKid extends AbstractBadCircularKid
>    {
>        public void dispose()
>        {
>            super.dispose();
>            
>            m_manager.release( m_mom );
>            m_manager.release( m_dad );
>        }
>    }
>
>    public static class SingleThreadedBadCircularKid extends AbstractBadCircularKid
>        implements SingleThreaded
>    {}
>    public static class ThreadSafeBadCircularKid extends AbstractBadCircularKid
>        implements ThreadSafe
>    {}
>    public static class PoolableBadCircularKid extends AbstractBadCircularKid
>        implements Poolable
>    {}
>    public static class SingleThreadedGoodCircularKid extends AbstractGoodCircularKid
>        implements SingleThreaded
>    {}
>    public static class ThreadSafeGoodCircularKid extends AbstractGoodCircularKid
>        implements ThreadSafe
>    {}
>    public static class PoolableGoodCircularKid extends AbstractGoodCircularKid
>        implements Poolable
>    {}
>    
>    /* ======================================================================== *
>     *                           Housekeeping.                                  *
>     * ======================================================================== */
>    
>    private static int m_disposals;
>    
>    private ExcaliburComponentManager m_manager;
>    
>    public ExcaliburComponentManagerTestCase( String name ) 
>    {
>        super( name );
>    }
>
>    public void setUp() throws Exception
>    {
>        m_disposals = 0;
>
>        m_manager = new ExcaliburComponentManager();
>        
>        final String pattern = 
>            ( "%5.5{priority} [%40.40{category}]: %{message}\n%{throwable}" );
>        
>        org.apache.log.Logger logger = Hierarchy.getDefaultHierarchy().getLoggerFor( getName() );
>        logger.setLogTargets
>            ( new LogTarget[] 
>            { new StreamTarget( System.out, new PatternFormatter( pattern ) ) } );
>        logger.setPriority( Priority.INFO );
>        
>        m_manager.setLogger( logger );
>        m_manager.contextualize( new DefaultContext() );
>        m_manager.configure( new DefaultConfiguration( "", "" ) );
>    }
>
>    public void tearDown() 
>    {
>        m_manager = null;
>    }
>
>}
>
>
>------------------------------------------------------------------------
>
>--
>To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
>For additional commands, e-mail: <ma...@jakarta.apache.org>
>


Re: [PATCH] ExcaliburComponentManager patch

Posted by Leif Mortenson <le...@silveregg.co.jp>.
Committed Thanks.

Ryan Shaw wrote:

>The changes to PoolableComponentHandler (so it uses ResourceLimitingPool)
>broke the unit test suite I posted earlier, since Component instances are
>now not created until they are needed (thus the expected number of 
>Component disposals is different).
>
>I have attached the updated test suite, which works with these latest
>changes.
>
>Ryan
>
>Ryan wrote:
>
>||| I haven't been following the "ComponentManager Interface" thread in its
>||| entirety, as I occasionally like to step away from my computer for things
>||| like food and sleep. :^)
>||| 
>||| But I did notice in skimming through some of the posts that you guys were
>||| discussing Peter's "releaseless" CM. I have tried to implement that in this
>||| patch. The CM allows Composables to release components they have looked up
>||| but does not require this--it will release components for them.
>||| 
>||| Note, however, that classes with "direct" access to the CM--i.e. classes
>||| that did not obtain references to the CM via a "compose()" method--must
>||| release their components, or else warnings will be logged when those
>||| components are disposed. This is because the resource tracking is done,
>||| per Peter's suggestion, via proxy ComponentManagers provided to Composables.
>||| Classes with "direct" access do not have these proxies so their lookups
>||| are not tracked.
>||| 
>||| That also means that in a situation where classes with direct ECM access
>||| do not release their components, correct ordering of disposal is currently
>||| not guaranteed. I can think of some ways to fix this (like having the ECM
>||| keep track of "direct" lookups so it knows which "top-level" components
>||| to dispose of first in order to kick off the component disposal process)
>||| but they aren't in this patch.
>||| 
>||| Ryan
>||| 
>||| Ryan wrote:
>||| 
>||| ||| Attached is a patch and unit test suite for some changes I
>||| ||| needed to fix problems I was having with the ECM.
>||| ||| 
>||| ||| Specifically:
>||| ||| 
>||| ||| 1) Components being disposed before other components finished using them.
>||| ||| 2) SingleThreaded Components never being disposed at all.
>||| ||| 
>||| ||| You can run the unit test suite with the command:
>||| ||| 
>||| ||| ./build.sh -Djunit.test=**/ExcaliburComponentManagerTestCase.class test-subset
>||| ||| 
>||| ||| The test suite sets up an ECM with combinations of Components of various
>||| ||| lifestyles (SingleThreaded, ThreadSafe, Poolable) and behaviors (proper
>||| ||| releasing of other components or not) and checks to see if the two problems
>||| ||| mentioned above are occurring.
>||| ||| 
>||| ||| Please check it out and let me know if you see any problems.
>||| ||| 
>||| ||| Thanks,
>||| ||| 
>||| ||| Ryan
>||| 
>||| --
>||| To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
>||| For additional commands, e-mail: <ma...@jakarta.apache.org>
>||| 
>||| 
>
>
>------------------------------------------------------------------------
>
>/*
> * Copyright (C) The Apache Software Foundation. All rights reserved.
> *
> * This software is published under the terms of the Apache Software License
> * version 1.1, a copy of which has been included with this distribution in
> * the LICENSE.txt file.
> */
>package org.apache.avalon.excalibur.component.test;
>
>import org.apache.avalon.excalibur.pool.Poolable;
>import org.apache.avalon.excalibur.component.DefaultComponentPool;
>import org.apache.avalon.excalibur.component.ExcaliburComponentManager;
>import org.apache.avalon.excalibur.util.ComponentStateValidator;
>
>import org.apache.avalon.framework.logger.Logger;
>import org.apache.avalon.framework.logger.AbstractLogEnabled;
>import org.apache.avalon.framework.context.DefaultContext;
>import org.apache.avalon.framework.configuration.DefaultConfiguration;
>import org.apache.avalon.framework.configuration.Configuration;
>import org.apache.avalon.framework.component.Component;
>import org.apache.avalon.framework.component.Composable;
>import org.apache.avalon.framework.component.ComponentManager;
>import org.apache.avalon.framework.component.ComponentException;
>import org.apache.avalon.framework.activity.Disposable;
>import org.apache.avalon.framework.thread.ThreadSafe;
>import org.apache.avalon.framework.thread.SingleThreaded;
>
>import junit.framework.TestSuite;
>import junit.framework.TestCase;
>
>import org.apache.log.Hierarchy;
>import org.apache.log.Priority;
>import org.apache.log.LogTarget;
>import org.apache.log.format.PatternFormatter;
>import org.apache.log.output.io.StreamTarget;
>
>/**
> * This class is for testing the ExcaliburComponentManager to verify that
> * it is correctly handling component lifestyle management.
> *
> * @author <a href="mailto:ryan@silveregg.co.jp">Ryan Shaw</a>
> * @version $Revision$
> */
>public class ExcaliburComponentManagerTestCase extends TestCase 
>{
>    /**
>     * Here we create a suite lots of tests to test the interactions of 
>     * various types of components. Basically there are three Roles 
>     * involved: Mom, Dad, and Kid. Each of the three Roles can be 
>     * implemented by a SingleThreaded, ThreadSafe, or Poolable component.
>     * The Mom and Dad components both are Composable, and they use the
>     * ComponentManager that they are provided with to obtain references
>     * to a Kid component. The Mom and Dad components may be "Good" (they
>     * properly release their Kid) or "Bad" (they don't release their Kid).
>     *
>     * Each of the tests sets up a different combo of these component
>     * implementations and checks to make sure that everything gets disposed,
>     * and that Kids never get disposed before parents are done using them.
>     *
>     * @return a <code>TestSuite</code>
>     */
>    public static TestSuite suite()
>    {
>        TestSuite suite = new TestSuite();
>        
>        String[] behaviors  = { "Bad", "Good" }; 
>        String[] kidTypes   = { "" }; // , "BadCircular", "GoodCircular" };
>        String[] lifestyles = { "SingleThreaded" , "ThreadSafe", "Poolable" }; 
>
>        for ( int mb = 0; mb < behaviors.length; mb++ )
>        {
>            for ( int db = 0; db < behaviors.length; db++ )
>            {
>                for ( int kt = 0; kt < kidTypes.length; kt++ )
>                {
>                    for ( int ml = 0; ml < lifestyles.length; ml++ ) 
>                    {
>                        for ( int dl = 0; dl < lifestyles.length; dl++ ) 
>                        {
>                            for ( int kl = 0; kl < lifestyles.length; kl++ ) 
>                            {
>                                final String momClassName = 
>                                    lifestyles[ ml ] + behaviors[ mb ] + "Mom";
>                                final String dadClassName = 
>                                    lifestyles[ dl ] + behaviors[ db ] + "Dad";
>                                final String kidClassName = 
>                                    lifestyles[ kl ] +  kidTypes[ kt ] + "Kid";
>                                
>                                final String prefix = 
>                                    ExcaliburComponentManagerTestCase.class.getName() + "$";
>                                
>                                suite.addTest
>                                    ( new ExcaliburComponentManagerTestCase( momClassName + 
>                                                                             dadClassName + 
>                                                                             kidClassName ) 
>                                        {
>                                            public void runTest() throws Exception 
>                                            {
>                                                managerLifecycle( Class.forName
>                                                                  ( prefix + momClassName ), 
>                                                                  Class.forName
>                                                                  ( prefix + dadClassName ),
>                                                                  Class.forName
>                                                                  ( prefix + kidClassName ) );
>                                            }
>                                        }
>                                      );
>                            }
>                        }
>                    }
>                }
>            }
>        }
>        
>        return suite;
>    }
>
>    private void managerLifecycle(Class momClass, Class dadClass, Class kidClass) 
>        throws Exception
>    {
>        Configuration emptyConfig = new DefaultConfiguration( "", "" );
>        
>        m_manager.addComponent( Mom.ROLE, momClass, emptyConfig );
>        m_manager.addComponent( Dad.ROLE, dadClass, emptyConfig );
>        m_manager.addComponent( Kid.ROLE, kidClass, emptyConfig );
>        
>        m_manager.initialize();
>        
>        Component mom = m_manager.lookup( Mom.ROLE );
>        Component dad = m_manager.lookup( Dad.ROLE );
>
>        m_manager.release( mom );
>        m_manager.release( dad );
>        
>        m_manager.dispose();
>
>	checkNumberOfDisposals( momClass, dadClass, kidClass );
>    }
>    
>    private void checkNumberOfDisposals( Class momClass, Class dadClass, Class kidClass ) 
>    {
>        int momInstances = 1, dadInstances = 1;
>        
>	int kidInstances = determineNumberOfKidInstances( kidClass, momInstances, dadInstances );
>        
>        int expectedDisposals = momInstances + dadInstances + kidInstances;
>        
>        assertEquals( expectedDisposals, m_disposals ); 
>    }
>
>    private int determineNumberOfKidInstances( Class kidClass, int momInstances, int dadInstances ) 
>    {
>        int parentInstances = ( momInstances + dadInstances );
>        
>        if ( ThreadSafe.class.isAssignableFrom( kidClass ) )
>        { 
>            // parents share reference to same kid instance
>            return 1;
>        } 
>        else if ( Poolable.class.isAssignableFrom( kidClass ) )
>        {
>            int poolGrowParameter = DefaultComponentPool.DEFAULT_POOL_SIZE / 4;
>
>            int extraKidsNeeded = parentInstances % poolGrowParameter;
>            
>            if ( extraKidsNeeded > 0 )
>            {
>                // kid pool will grow to feed parents
>                return parentInstances + ( poolGrowParameter - extraKidsNeeded );
>            }
>        }
>
>        // each parent has a single kid reference
>        return parentInstances;
>    }
>
>    /* ======================================================================== *
>     *                           Test Components.                               *
>     * ======================================================================== */
>
>    public static abstract class AbstractBadParent extends AbstractLogEnabled
>        implements Component, Composable, Disposable
>    {
>        private final ComponentStateValidator m_validator = new ComponentStateValidator( this );
>        
>        protected ComponentManager m_manager;
>        protected Kid              m_kid;
>        
>        public void enableLogging( Logger logger )
>        {
>            m_validator.checkLogEnabled();
>            
>            super.enableLogging( logger );
>        }
>        
>        public void compose( ComponentManager manager ) throws ComponentException
>        {
>            m_validator.checkComposed();
>
>            m_manager = manager;
>            
>            m_kid = (Kid) m_manager.lookup( Kid.ROLE );
>        }
>
>        public void dispose()
>        {
>            m_validator.checkDisposed();
>
>            try
>            {
>                m_kid.getName();
>            } 
>            catch ( IllegalStateException ise )
>            {
>                fail( ise.getMessage() );
>            }
>            
>            m_disposals++;
>        }
>    }
>
>    public static abstract class AbstractGoodParent extends AbstractBadParent
>    {
>        public void dispose()
>        {
>            super.dispose();
>            m_manager.release( m_kid );
>        }
>    }
>    
>    public interface Mom extends Component
>    {
>        String ROLE = "Mom";
>    }
>    
>    public static class SingleThreadedBadMom extends AbstractBadParent
>        implements Mom, SingleThreaded
>    {}
>    public static class SingleThreadedGoodMom extends AbstractGoodParent
>        implements Mom, SingleThreaded
>    {}
>    public static class ThreadSafeBadMom extends AbstractBadParent
>        implements Mom, ThreadSafe
>    {}
>    public static class ThreadSafeGoodMom extends AbstractGoodParent
>        implements Mom, ThreadSafe
>    {}
>    public static class PoolableBadMom extends AbstractBadParent
>        implements Mom, Poolable
>    {}
>    public static class PoolableGoodMom extends AbstractGoodParent
>        implements Mom, Poolable
>    {}
>
>    public interface Dad extends Component
>    {
>        String ROLE = "Dad";
>    }
>    
>    public static class SingleThreadedBadDad extends AbstractBadParent
>        implements Dad, SingleThreaded
>    {}
>    public static class SingleThreadedGoodDad extends AbstractGoodParent
>        implements Dad, SingleThreaded
>    {}
>    public static class ThreadSafeBadDad extends AbstractBadParent
>        implements Dad, ThreadSafe
>    {}
>    public static class ThreadSafeGoodDad extends AbstractGoodParent
>        implements Dad, ThreadSafe
>    {}
>    public static class PoolableBadDad extends AbstractBadParent
>        implements Dad, Poolable
>    {}
>    public static class PoolableGoodDad extends AbstractGoodParent
>        implements Dad, Poolable
>    {}
>    
>    public interface Kid extends Component
>    {
>        String ROLE = "Kid";
>
>        String getName();
>    }
>    
>    public static abstract class AbstractKid extends AbstractLogEnabled
>        implements Kid, Disposable
>    {
>        public final static String ROLE = "Kid";
>
>        protected final ComponentStateValidator m_validator = new ComponentStateValidator( this );
>
>        public void enableLogging( Logger logger )
>        {
>            m_validator.checkLogEnabled();
>
>            super.enableLogging( logger );
>        }
>
>        public void dispose()
>        {
>            m_validator.checkDisposed();
>
>            m_disposals++;
>        }
>
>        public String getName()
>        {
>            m_validator.checkActive();
>            
>            return "Kid";
>        } 
>    }
>
>    public static class SingleThreadedKid extends AbstractKid
>        implements SingleThreaded
>    {}
>    public static class ThreadSafeKid extends AbstractKid
>        implements ThreadSafe
>    {}
>    public static class PoolableKid extends AbstractKid
>        implements Poolable
>    {}
>    
>    public static abstract class AbstractBadCircularKid extends AbstractKid
>        implements Composable
>    {
>        protected ComponentManager m_manager;
>        protected Mom              m_mom;
>        protected Dad              m_dad;
>        
>        public void compose( ComponentManager manager ) throws ComponentException
>        {
>            m_validator.checkComposed();
>            
>            m_manager = manager;
>        }
>
>        public String getName()
>        {
>            String name = super.getName();
>            
>            try 
>            {
>                m_mom = (Mom) m_manager.lookup( Mom.ROLE );
>                m_dad = (Dad) m_manager.lookup( Dad.ROLE );
>            }
>            catch ( ComponentException ce )
>            {
>                fail( ce.getMessage() );
>            }
>
>            return ( name + " belongs to " + m_mom + " and " + m_dad );
>        }
>    }
>
>    public static abstract class AbstractGoodCircularKid extends AbstractBadCircularKid
>    {
>        public void dispose()
>        {
>            super.dispose();
>            
>            m_manager.release( m_mom );
>            m_manager.release( m_dad );
>        }
>    }
>
>    public static class SingleThreadedBadCircularKid extends AbstractBadCircularKid
>        implements SingleThreaded
>    {}
>    public static class ThreadSafeBadCircularKid extends AbstractBadCircularKid
>        implements ThreadSafe
>    {}
>    public static class PoolableBadCircularKid extends AbstractBadCircularKid
>        implements Poolable
>    {}
>    public static class SingleThreadedGoodCircularKid extends AbstractGoodCircularKid
>        implements SingleThreaded
>    {}
>    public static class ThreadSafeGoodCircularKid extends AbstractGoodCircularKid
>        implements ThreadSafe
>    {}
>    public static class PoolableGoodCircularKid extends AbstractGoodCircularKid
>        implements Poolable
>    {}
>    
>    /* ======================================================================== *
>     *                           Housekeeping.                                  *
>     * ======================================================================== */
>    
>    private static int m_disposals;
>    
>    private ExcaliburComponentManager m_manager;
>    
>    public ExcaliburComponentManagerTestCase( String name ) 
>    {
>        super( name );
>    }
>
>    public void setUp() throws Exception
>    {
>        m_disposals = 0;
>
>        m_manager = new ExcaliburComponentManager();
>        
>        final String pattern = 
>            ( "%5.5{priority} [%40.40{category}]: %{message}\n%{throwable}" );
>        
>        org.apache.log.Logger logger = Hierarchy.getDefaultHierarchy().getLoggerFor( getName() );
>        logger.setLogTargets
>            ( new LogTarget[] 
>            { new StreamTarget( System.out, new PatternFormatter( pattern ) ) } );
>        logger.setPriority( Priority.INFO );
>        
>        m_manager.setLogger( logger );
>        m_manager.contextualize( new DefaultContext() );
>        m_manager.configure( new DefaultConfiguration( "", "" ) );
>    }
>
>    public void tearDown() 
>    {
>        m_manager = null;
>    }
>
>}
>
>
>------------------------------------------------------------------------
>
>--
>To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
>For additional commands, e-mail: <ma...@jakarta.apache.org>
>



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: [PATCH] ExcaliburComponentManager patch

Posted by Ryan Shaw <ry...@silveregg.co.jp>.
The changes to PoolableComponentHandler (so it uses ResourceLimitingPool)
broke the unit test suite I posted earlier, since Component instances are
now not created until they are needed (thus the expected number of 
Component disposals is different).

I have attached the updated test suite, which works with these latest
changes.

Ryan

Ryan wrote:

||| I haven't been following the "ComponentManager Interface" thread in its
||| entirety, as I occasionally like to step away from my computer for things
||| like food and sleep. :^)
||| 
||| But I did notice in skimming through some of the posts that you guys were
||| discussing Peter's "releaseless" CM. I have tried to implement that in this
||| patch. The CM allows Composables to release components they have looked up
||| but does not require this--it will release components for them.
||| 
||| Note, however, that classes with "direct" access to the CM--i.e. classes
||| that did not obtain references to the CM via a "compose()" method--must
||| release their components, or else warnings will be logged when those
||| components are disposed. This is because the resource tracking is done,
||| per Peter's suggestion, via proxy ComponentManagers provided to Composables.
||| Classes with "direct" access do not have these proxies so their lookups
||| are not tracked.
||| 
||| That also means that in a situation where classes with direct ECM access
||| do not release their components, correct ordering of disposal is currently
||| not guaranteed. I can think of some ways to fix this (like having the ECM
||| keep track of "direct" lookups so it knows which "top-level" components
||| to dispose of first in order to kick off the component disposal process)
||| but they aren't in this patch.
||| 
||| Ryan
||| 
||| Ryan wrote:
||| 
||| ||| Attached is a patch and unit test suite for some changes I
||| ||| needed to fix problems I was having with the ECM.
||| ||| 
||| ||| Specifically:
||| ||| 
||| ||| 1) Components being disposed before other components finished using them.
||| ||| 2) SingleThreaded Components never being disposed at all.
||| ||| 
||| ||| You can run the unit test suite with the command:
||| ||| 
||| ||| ./build.sh -Djunit.test=**/ExcaliburComponentManagerTestCase.class test-subset
||| ||| 
||| ||| The test suite sets up an ECM with combinations of Components of various
||| ||| lifestyles (SingleThreaded, ThreadSafe, Poolable) and behaviors (proper
||| ||| releasing of other components or not) and checks to see if the two problems
||| ||| mentioned above are occurring.
||| ||| 
||| ||| Please check it out and let me know if you see any problems.
||| ||| 
||| ||| Thanks,
||| ||| 
||| ||| Ryan
||| 
||| --
||| To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
||| For additional commands, e-mail: <ma...@jakarta.apache.org>
||| 
||| 

Re: [PATCH] ExcaliburComponentManager patch

Posted by Ryan Shaw <ry...@silveregg.co.jp>.
I haven't been following the "ComponentManager Interface" thread in its
entirety, as I occasionally like to step away from my computer for things
like food and sleep. :^)

But I did notice in skimming through some of the posts that you guys were
discussing Peter's "releaseless" CM. I have tried to implement that in this
patch. The CM allows Composables to release components they have looked up
but does not require this--it will release components for them.

Note, however, that classes with "direct" access to the CM--i.e. classes
that did not obtain references to the CM via a "compose()" method--must
release their components, or else warnings will be logged when those
components are disposed. This is because the resource tracking is done,
per Peter's suggestion, via proxy ComponentManagers provided to Composables.
Classes with "direct" access do not have these proxies so their lookups
are not tracked.

That also means that in a situation where classes with direct ECM access
do not release their components, correct ordering of disposal is currently
not guaranteed. I can think of some ways to fix this (like having the ECM
keep track of "direct" lookups so it knows which "top-level" components
to dispose of first in order to kick off the component disposal process)
but they aren't in this patch.

Ryan

Ryan wrote:

||| Attached is a patch and unit test suite for some changes I
||| needed to fix problems I was having with the ECM.
||| 
||| Specifically:
||| 
||| 1) Components being disposed before other components finished using them.
||| 2) SingleThreaded Components never being disposed at all.
||| 
||| You can run the unit test suite with the command:
||| 
||| ./build.sh -Djunit.test=**/ExcaliburComponentManagerTestCase.class test-subset
||| 
||| The test suite sets up an ECM with combinations of Components of various
||| lifestyles (SingleThreaded, ThreadSafe, Poolable) and behaviors (proper
||| releasing of other components or not) and checks to see if the two problems
||| mentioned above are occurring.
||| 
||| Please check it out and let me know if you see any problems.
||| 
||| Thanks,
||| 
||| Ryan

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>