Announcement Announcement Module
Collapse
No announcement yet.
Pooling with CommonsPoolTargetSource, maxSize never hit Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Pooling with CommonsPoolTargetSource, maxSize never hit

    Hi,

    I'm pooling POJOs with CommonsPoolTargetSource - I can get instances from the pool (even unique instances), but I can't seem to hit the max limit. The pool keeps on handing out instances.

    I've written a test case that deals directly with the pool - and that seems to work, but it is very intrusive code, i.e. you can't just wrap a pool around beans, you also have to write code to deal with the Apache Commons Pool, by retrieving and then releaseing objects back to the pool. The test case also attempts to use the ProxyFactoryBean around the pool - but it doesn't block when the pool is exhausted, i.e. when requesting the third instance from the pool.

    I've tested this with the latest version of CommonsPoolTargetSource out of CVS, which allows support for setMaxWait. Other than that I'm using Spring 1.2.2.

    Here is the pooling-beans.xml file:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http&#58;//www.springframework.org/dtd/spring-beans.dtd">
    
    <beans>
    
        <!--  junit testing a simple pooled POJO -->
        
        <bean id="commonsPoolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
            <property name="maxSize"><value>2</value></property>
            <property name="maxWait"><value>1</value></property>
            <property name="targetBeanName"><value>parserTarget</value></property>
        </bean>
    
        <bean id="parserTarget" class="example.DocumentParser" singleton="false">
            <property name="message"><value>Hello cruel world!</value></property>
        </bean>
    
        <bean id="parser" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="targetSource"><ref local="commonsPoolTargetSource" /></property>
            <property name="singleton"><value>false</value></property>
            <property name="interfaces">
                <value>example.IDocumentParser</value>
            </property>
        </bean>
    
    </beans>
    Here is the test case:

    Code:
    package example.pooling;
    
    import junit.framework.TestCase;
    
    import java.util.List;
    import java.util.ArrayList;
    import java.util.ListIterator;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.aop.target.PoolingConfig;
    
    import org.springframework.aop.target.CommonsPoolTargetSource;
    
    public class DocumentParserPoolJunit extends TestCase &#123;
    
        public void testPojoPools&#40;&#41; &#123;
            // using Spring
            ApplicationContext context =
                new ClassPathXmlApplicationContext&#40;"pooling-beans.xml"&#41;;
    
            IDocumentParser parser1 = null;
            IDocumentParser parser2 = null;
            IDocumentParser parser3 = null;
    
            CommonsPoolTargetSource pool = &#40;CommonsPoolTargetSource&#41; context.getBean&#40;"commonsPoolTargetSource"&#41;;
    
            // this tests Apache Common's pooling - i.e. not using the TargetFactoryBean
    
            try &#123;
                // set maximum pool size
                pool.setMaxSize&#40;2&#41;;
                pool.setMaxWait&#40;1&#41;; // you'll need the latest CommonsPoolTargetSource from CVS for this
                
                parser1 = &#40;IDocumentParser&#41; pool.getTarget&#40;&#41;;
                parser2 = &#40;IDocumentParser&#41; pool.getTarget&#40;&#41;;
    
                assertTrue&#40;"object references via pool are the same instance",parser1!=parser2&#41;;
    
                // next should throw an exception if the setMaxSize is 2 and a setMaxWait has been specified
                parser3 = &#40;IDocumentParser&#41; pool.getTarget&#40;&#41;;
    
            &#125; catch &#40;java.util.NoSuchElementException e&#41; &#123;
                // do nothing, test passed
            &#125; catch &#40;Exception e&#41; &#123;
                fail&#40;e.getClass&#40;&#41;.getName&#40;&#41; + " thrown where java.util.NoSuchElementException expected"&#41;;
            &#125; finally &#123;
                try &#123;
                    if &#40;parser1 != null&#41; &#123;
                        pool.releaseTarget&#40;parser1&#41;;
                        parser1 = null;
                    &#125;
                    if &#40;parser2 != null&#41; &#123;
                        pool.releaseTarget&#40;parser2&#41;;
                        parser2 = null;
                    &#125;
                    if &#40;parser3 != null&#41; &#123;
                        pool.releaseTarget&#40;parser3&#41;;
                        parser3 = null;
                    &#125;
                &#125;
                catch &#40;Exception e&#41; &#123;
                    fail&#40;"exception&#58;" + e.getMessage&#40;&#41;&#41;;
                &#125;
            &#125;
    
            // this tests Spring's pooling
            
            // get the 1st parser
            parser1 = &#40;IDocumentParser&#41; context.getBean&#40;"parser"&#41;;
            System.out.println&#40; parser1.getMessage&#40;&#41; &#41;;
            
            // get the 2nd parser
            parser2 = &#40;IDocumentParser&#41; context.getBean&#40;"parser"&#41;;
            System.out.println&#40; parser2.getMessage&#40;&#41; &#41;;
    
            // this fails if the TargetFactoryBean is a singleton
            assertTrue&#40;"object references via factory bean are the same instance",parser1!=parser2&#41;;
            
            // ERROR! get the 3rd parser - this should block but doesn't
            parser3 = &#40;IDocumentParser&#41; context.getBean&#40;"parser"&#41;;
            System.out.println&#40; parser3.getMessage&#40;&#41; &#41;;
    
            // be good and loose references
            parser1 = null;
            parser2 = null;
            parser3 = null;
        &#125;
    &#125;
    Here is the POJO:


    Code:
    package example.pooling;
    
    public class DocumentParser implements IDocumentParser &#123;
        private String message = "hello world";
    
        /**
         * @param message The message to set.
         */
        public void setMessage&#40;String message&#41; &#123;
            this.message = message;
        &#125;
    
        /**
         * @return Returns the message.
         */
        public String getMessage&#40;&#41; &#123;
            return message;
        &#125;
    &#125;
    And the interface:

    Code:
    package example.pooling;
    
    public interface IDocumentParser &#123;
        /**
         * @param message The message to set.
         */
        public abstract void setMessage&#40;String message&#41;;
    
        /**
         * @return Returns the message.
         */
        public abstract String getMessage&#40;&#41;;
    &#125;
    As an aside, it would be useful to be able to specify the whenExhaustedAction behaviour, but this doesn't seem to be exposed.

    Any help gratefully received...

    Regards
    Martin

  • #2
    Martin,

    Can you post JIRA issues for these problems and post the issue numbers back here?

    Regards,

    Rob

    Comment


    • #3
      Rob,

      http://opensource.atlassian.com/proj...rowse/SPR-1186 - for maxLimit not being hit

      http://opensource.atlassian.com/proj...rowse/SPR-1187 - for exposing whenExhaustedAction

      Regards
      Martin

      Comment


      • #4
        Thanks Martin, Ill schedule these for 1.3.

        Rob

        Comment


        • #5
          Rob,

          Sorry for long delay in replying, been busy doing something else. Now I need to return to this issue. I've looked at the unit test case method testHitMaxSize added to CommonsPoolTargetSourceTests.java - however, this appears to me to be testing the commons pooling and its ability to know when the max has been hit.

          What I'm looking for is the ability of Spring's pooling to know when the max has been hit. As can be seen in the original test case on this message - I correctly tested Commons Polling, but then couldn't get Spring to test correctly using the code: parser1 = (IDocumentParser) context.getBean("parser");

          I want to be able to add pooling around a bean without either the bean knowing it has been pooled, or the client requesting the bean having to know or deal with the bean being pooled.

          It appears from your unit test case, that the client needs to know that the bean should be pooled, and that it should also know when to release the bean back to the pool.

          Regards
          Martin

          Comment

          Working...
          X