Author: tabish
Date: Wed Aug 31 21:07:28 2011
New Revision: 1163815
URL: http://svn.apache.org/viewvc?rev=1163815&view=rev
Log:
apply patch for: https://issues.apache.org/jira/browse/AMQ-3482
Added:
activemq/trunk/activemq-pool/src/test/java/org/apache/activemq/pool/PooledConnectionFactoryTest.java
(with props)
Modified:
activemq/trunk/activemq-pool/src/main/java/org/apache/activemq/pool/PooledConnectionFactory.java
activemq/trunk/activemq-pool/src/test/resources/log4j.properties
Modified:
activemq/trunk/activemq-pool/src/main/java/org/apache/activemq/pool/PooledConnectionFactory.java
URL:
http://svn.apache.org/viewvc/activemq/trunk/activemq-pool/src/main/java/org/apache/activemq/pool/PooledConnectionFactory.java?rev=1163815&r1=1163814&r2=1163815&view=diff
==============================================================================
---
activemq/trunk/activemq-pool/src/main/java/org/apache/activemq/pool/PooledConnectionFactory.java
(original)
+++
activemq/trunk/activemq-pool/src/main/java/org/apache/activemq/pool/PooledConnectionFactory.java
Wed Aug 31 21:07:28 2011
@@ -31,6 +31,7 @@ import org.apache.activemq.util.IOExcept
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.pool.ObjectPoolFactory;
+import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.commons.pool.impl.GenericObjectPoolFactory;
/**
@@ -65,6 +66,7 @@ public class PooledConnectionFactory imp
private int maximumActive = 500;
private int maxConnections = 1;
private int idleTimeout = 30 * 1000;
+ private boolean blockIfSessionPoolIsFull = false;
private AtomicBoolean stopped = new AtomicBoolean(false);
private long expiryTimeout = 0l;
@@ -193,6 +195,26 @@ public class PooledConnectionFactory imp
public void setMaximumActive(int maximumActive) {
this.maximumActive = maximumActive;
}
+
+ /**
+ * Controls the behavior of the internal session pool.
+ * By default the call to Connection.getSession() will
+ * return a JMSException if the session pool is full.
+ * If the argument true is given, it will change the
+ * default behavior and instead the call to getSession()
+ * will block until a session is available in the pool, which
+ * used to be the default behavior in ActiveMQ versions < 5.6.
+ *
+ * The size of the session pool is controlled by the @see #maximumActive
+ * property.
+ *
+ * @param block - if true, the call to getSession() blocks if the pool
+ * is full until a session object is available.
+ * defaults to false.
+ */
+ public void setBlockIfSessionPoolIsFull(boolean block) {
+ this.blockIfSessionPoolIsFull = block;
+ }
/**
* @return the maxConnections
@@ -208,8 +230,21 @@ public class PooledConnectionFactory imp
this.maxConnections = maxConnections;
}
+ /**
+ * Creates an ObjectPoolFactory. Its behavior is controlled by the two
+ * properties @see #maximumActive and @see #blockIfSessionPoolIsFull.
+ *
+ * @return the newly created but empty ObjectPoolFactory
+ */
protected ObjectPoolFactory createPoolFactory() {
- return new GenericObjectPoolFactory(null, maximumActive);
+ if (blockIfSessionPoolIsFull) {
+ return new GenericObjectPoolFactory(null, maximumActive);
+ } else {
+ return new GenericObjectPoolFactory(null,
+ maximumActive,
+ GenericObjectPool.WHEN_EXHAUSTED_FAIL,
+ GenericObjectPool.DEFAULT_MAX_WAIT);
+ }
}
public int getIdleTimeout() {
Added:
activemq/trunk/activemq-pool/src/test/java/org/apache/activemq/pool/PooledConnectionFactoryTest.java
URL:
http://svn.apache.org/viewvc/activemq/trunk/activemq-pool/src/test/java/org/apache/activemq/pool/PooledConnectionFactoryTest.java?rev=1163815&view=auto
==============================================================================
---
activemq/trunk/activemq-pool/src/test/java/org/apache/activemq/pool/PooledConnectionFactoryTest.java
(added)
+++
activemq/trunk/activemq-pool/src/test/java/org/apache/activemq/pool/PooledConnectionFactoryTest.java
Wed Aug 31 21:07:28 2011
@@ -0,0 +1,147 @@
+package org.apache.activemq.pool;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import junit.framework.Assert;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Session;
+
+import org.apache.activemq.pool.PooledConnectionFactory;
+import org.apache.activemq.ActiveMQConnectionFactory;
+
+import org.apache.log4j.Logger;
+
+
+/**
+ * Checks the behavior of the PooledConnectionFactory when the maximum amount
+ * of sessions is being reached.
+ * Older versions simply block in the call to Connection.getSession(), which
isn't good.
+ * An exception being returned is the better option, so JMS clients don't
block.
+ * This test succeeds if an exception is returned and fails if the call to
getSession()
+ * blocks.
+ *
+ */
+public class PooledConnectionFactoryTest extends TestCase
+{
+ public final static Logger LOG =
Logger.getLogger(PooledConnectionFactoryTest.class);
+
+
+ /**
+ * Create the test case
+ *
+ * @param testName name of the test case
+ */
+ public PooledConnectionFactoryTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * @return the suite of tests being tested
+ */
+ public static Test suite()
+ {
+ return new TestSuite( PooledConnectionFactoryTest.class );
+ }
+
+ /**
+ * Tests the behavior of the sessionPool of the PooledConnectionFactory
+ * when maximum number of sessions are reached. In older versions the call
to
+ * Connection.createSession() would simply block indefinitely if the
maximum
+ * number of sessions got reached (controled by
+ * PooledConnectionFactory.setMaximumActive()).
+ * Rather than blocking the entire thread, it should raise an exception
+ * instead.
+ */
+ public void testApp() throws Exception
+ {
+ // using separate thread for testing so that we can interrupt the test
+ // if the call to get a new session blocks.
+
+ // start test runner thread
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<Boolean> result = (Future<Boolean>) executor.submit(new
TestRunner());
+
+ // test should not take > 5secs, so test fails i
+ Thread.sleep(5*1000);
+
+ if (!result.isDone() || !result.get().booleanValue()) {
+ PooledConnectionFactoryTest.LOG.error("2nd call to
createSession()" +
+ " is blocking but should have returned an error
instead.");
+
+ executor.shutdownNow();
+
+ Assert.fail("SessionPool inside PooledConnectionFactory is
blocking if " +
+ "limit is exceeded but should return an exception
instead.");
+ }
+ }
+}
+
+class TestRunner implements Callable<Boolean> {
+
+ public final static Logger LOG = Logger.getLogger(TestRunner.class);
+
+ /**
+ * @return true if test succeeded, false otherwise
+ */
+ public Boolean call() {
+
+ Connection conn = null;
+ Session one = null;
+
+ // wait at most 5 seconds for the call to createSession
+ try {
+ ActiveMQConnectionFactory amq = new
ActiveMQConnectionFactory("vm://broker1?marshal=false&broker.persistent=false");
+ PooledConnectionFactory cf = new PooledConnectionFactory(amq);
+ cf.setMaxConnections(3);
+ cf.setMaximumActive(1);
+
+ // default should be false already but lets make sure a change
to the default
+ // setting does not make this test fail.
+ cf.setBlockIfSessionPoolIsFull(false);
+
+ conn = cf.createConnection();
+ one = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ Session two = null;
+ try {
+ // this should raise an exception as we called
setMaximumActive(1)
+ two = conn.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ two.close();
+
+ LOG.error("Expected JMSException wasn't thrown.");
+ Assert.fail("seconds call to Connection.createSession()
was supposed" +
+ "to raise an JMSException as internal
session pool" +
+ "is exhausted. This did not happen and
indiates a problem");
+ return new Boolean(false);
+ } catch (JMSException ex) {
+ if (ex.getCause().getClass() ==
java.util.NoSuchElementException.class) {
+ //expected, ignore but log
+ LOG.info("Caught expected " + ex);
+ } else {
+ LOG.error(ex);
+ return new Boolean(false);
+ }
+ } finally {
+ if (one != null)
+ one.close();
+ if (conn != null)
+ conn.close();
+ }
+ } catch (Exception ex) {
+ LOG.error(ex.getMessage());
+ return new Boolean(false);
+ }
+
+ // all good, test succeeded
+ return new Boolean(true);
+ }
+}
Propchange:
activemq/trunk/activemq-pool/src/test/java/org/apache/activemq/pool/PooledConnectionFactoryTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: activemq/trunk/activemq-pool/src/test/resources/log4j.properties
URL:
http://svn.apache.org/viewvc/activemq/trunk/activemq-pool/src/test/resources/log4j.properties?rev=1163815&r1=1163814&r2=1163815&view=diff
==============================================================================
--- activemq/trunk/activemq-pool/src/test/resources/log4j.properties (original)
+++ activemq/trunk/activemq-pool/src/test/resources/log4j.properties Wed Aug 31
21:07:28 2011
@@ -23,6 +23,7 @@ log4j.rootLogger=INFO, out, stdout
log4j.logger.org.apache.activemq.spring=WARN
#log4j.logger.org.apache.activemq.usecases=DEBUG
#log4j.logger.org.apache.activemq.broker.region=DEBUG
+log4j.logger.org.apache.activemq.pool=DEBUG
# CONSOLE appender not used by default
log4j.appender.stdout=org.apache.log4j.ConsoleAppender