CVS: plexus-container-new/src/aspect/org/apache/plexus ComponentLeakAspect.java,NONE,1.1

[email protected] Sun, 25 May 2003 15:57:01 -0500
Newsgroups gmane.comp.java.plexus.devel
Message-ID <[email protected]>
Update of /cvsroot/plexus/plexus-container-new/src/aspect/org/apache/plexus
In directory eng.werken.com:/tmp/cvs-serv2742/src/aspect/org/apache/plexus

Added Files:
	ComponentLeakAspect.java 
Log Message:
Adding an aspect that can be used to track down "component leaks".  When
I built poolserver, I didn't realize that Summit was actually using some
components without ever releasing them.  As a result, after a week, I
saw memory usage going through the roof.

Based on that experience, coupled with my desire to learn some AspectJ,
I thought this would be an ideal opportunity.  To use the aspect:

  - Build a plexus jar as follows: maven aspectj:compile jar:install
  - Add the aspectj dependency to your project.xml file
  - Run your project

Here is the type of output you will receive if you have no component
leaks (demo with a simple plexus command line application):

    kaz@coco:~/work/src/simple/target$ java -jar simple-1.0-uber.jar
    Hello World!
    >> Non-Released Component Count: 0

On the other hand, if you have a leak, you will see the following:

    kaz@coco:~/work/src/simple/target$ java -jar simple-1.0-uber.jar
    Hello World!
    >> Non-Released Component Count: 1
    >>>> org.apache.plexus.examples.simple.DefaultHelloWorld@34a1fc



--- NEW FILE: ComponentLeakAspect.java ---
package org.apache.plexus;

import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;

import org.apache.plexus.service.repository.ComponentRepository;

/**
 * Aspect to identify "component leaks".  A component leak occurs when
 * a component is looked up, but never released.
 * 
 * @author <a href="[email protected]">Pete Kazmier</a>
 * @version $Id: ComponentLeakAspect.java,v 1.1 2003/05/25 20:56:58 kaz Exp $
 */
aspect ComponentLeakAspect
{
    private List components = new LinkedList();

    /**
     * This pointcut identifies the moment in time when we should
     * actually print out the results we've been tracking in this
     * aspect.
     */
    pointcut repositoryDisposal():
        call(void ComponentRepository.dispose());

    /**
     * The lookup pointcut has one subtly, we need to be carefull to
     * remember that lookup(role, id), simply calls lookup(role).  As
     * a result, we need to make sure we exclude any calls to lookup()
     * made from other calls of lookup.
     */
    pointcut lookup():
        call(Object ComponentRepository.lookup(..)) &&
        !cflow(execution(Object ComponentRepository.lookup(..)));

    /**
     * The release pointcut is straightforward.  We just need to keep
     * track of the argument so we can remove it from our list.
     */
    pointcut release(Object o):
        call(void ComponentRepository.release(Object)) && args(o);

    /**
     * The around advice is used to get a reference to the returned
     * object so we can add this to our list of components.
     */
    Object around(): lookup()
    {
        Object result = proceed();
        components.add(result);
        return result;
    }

    /**
     * The after advice here simply removes the component from our
     * list. 
     */
    after(Object o): release(o)
    {
        components.remove(o);
    }

    /**
     * We should print the results _before_ the component repository
     * disposes() because part of the component repository's disposal
     * includes the disposal of all components (and we can't be sure
     * that it doesn't call release() which would affect our count,
     * although after looking at the code, it really doesn't so it
     * wouldn't matter, but that is an implementation detail that we
     * should not know about.  The other alternative would be to
     * exclude the control flow of ComponentRepository.dispose() from
     * our release pointcut).
     */
    before(): repositoryDisposal()
    {
        System.err.println(">> Non-Released Component Count: " + components.size());
        for (Iterator i = components.iterator(); i.hasNext(); )
        {
            System.err.println(">>>> " + i.next());
        }
    }
}