/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.openejb.core.stateless;
import junit.framework.TestCase;
import org.apache.openejb.OpenEJB;
import org.apache.openejb.api.Monitor;
import org.apache.openejb.assembler.classic.Assembler;
import org.apache.openejb.assembler.classic.SecurityServiceInfo;
import org.apache.openejb.assembler.classic.StatelessSessionContainerInfo;
import org.apache.openejb.assembler.classic.TransactionServiceInfo;
import org.apache.openejb.config.ConfigurationFactory;
import org.apache.openejb.jee.EjbJar;
import org.apache.openejb.jee.StatelessBean;
import org.apache.openejb.monitoring.LocalMBeanServer;
import org.apache.openejb.test.util.Asserts;
import org.junit.AfterClass;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.ejb.ConcurrentAccessException;
import javax.ejb.SessionContext;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.naming.InitialContext;
import java.io.Flushable;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class StatelessPoolStatsTest extends TestCase {
private final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
private ObjectName objectName;
@Override
public void setUp() {
System.setProperty(LocalMBeanServer.OPENEJB_JMX_ACTIVE, Boolean.TRUE.toString());
}
@Override
public void tearDown() {
System.clearProperty(LocalMBeanServer.OPENEJB_JMX_ACTIVE);
}
@AfterClass
public static void afterClass() throws Exception {
OpenEJB.destroy();
}
/**
* @throws Exception On error
*/
public void testBasic() throws Exception {
final Properties properties = new Properties();
properties.setProperty("AccessTimeout", "100");
properties.setProperty("MaxSize", "15");
properties.setProperty("SweepInterval", "10 ms");
properties.setProperty("MinSize", "3");
properties.setProperty("StrictPooling", "true");
deploy("testBasic", properties);
// Grab the mbeanInfo and check the expected attributes exist and have the correct return types and parameters
final MBeanInfo poolMBeanInfo = server.getMBeanInfo(objectName);
/*
* Pool MBeanInfo
*
*/
final List<MBeanAttributeInfo> expectedAttributes = new ArrayList<MBeanAttributeInfo>();
expectedAttributes.add(new MBeanAttributeInfo("AccessTimeouts", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("AccessTimeouts.Latest", "java.lang.String", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("AccessTimeouts.LatestTime", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Aged", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Aged.Latest", "java.lang.String", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Aged.LatestTime", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("AvailablePermits", "int", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Flushed", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Flushed.Latest", "java.lang.String", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Flushed.LatestTime", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Flushes", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Flushes.Latest", "java.lang.String", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Flushes.LatestTime", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("GarbageCollected", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("GarbageCollected.Latest", "java.lang.String", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("GarbageCollected.LatestTime", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("GarbageCollection", "boolean", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("IdleTimeout", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("IdleTimeouts", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("IdleTimeouts.Latest", "java.lang.String", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("IdleTimeouts.LatestTime", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("InstancesActive", "int", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("InstancesIdle", "int", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("InstancesInitializing", "int", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("InstancesPooled", "int", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("MaxAge", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("MaxAgeOffset", "double", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("MaxSize", "int", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("MinSize", "int", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("MinimumInstances", "int", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Overdrafts", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Overdrafts.Latest", "java.lang.String", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Overdrafts.LatestTime", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("PoolVersion", "int", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("ReplaceAged", "boolean", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("ReplaceFlushed", "boolean", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Replaced", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Replaced.Latest", "java.lang.String", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Replaced.LatestTime", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("StrictPooling", "boolean", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("SweepInterval", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Sweeps", "long", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Sweeps.Latest", "java.lang.String", "", true, false, false));
expectedAttributes.add(new MBeanAttributeInfo("Sweeps.LatestTime", "long", "", true, false, false));
// The hardest part, check the values of each, PoolVersion is AtomicaInteger, *.Latest are time-sensitive, so not verified.
final Map<String, Object> expectedAttributesValue = new TreeMap<String, Object>();
expectedAttributesValue.put("AccessTimeouts", (long) 0);
expectedAttributesValue.put("Aged", (long) 0);
expectedAttributesValue.put("AvailablePermits", 15);
expectedAttributesValue.put("Flushed", (long) 0);
expectedAttributesValue.put("Flushes", (long) 0);
expectedAttributesValue.put("GarbageCollected", (long) 0);
expectedAttributesValue.put("GarbageCollection", false);
expectedAttributesValue.put("IdleTimeout", (long) 0);
expectedAttributesValue.put("IdleTimeouts", (long) 0);
expectedAttributesValue.put("InstancesPooled", 3);
expectedAttributesValue.put("InstancesActive", 0);
expectedAttributesValue.put("InstancesIdle", 3);
expectedAttributesValue.put("InstancesInitializing", 0);
expectedAttributesValue.put("MaxAge", (long) 0);
expectedAttributesValue.put("MaxAgeOffset", -1.0);
expectedAttributesValue.put("MaxSize", 15);
expectedAttributesValue.put("MinSize", 3);
expectedAttributesValue.put("MinimumInstances", 3);
expectedAttributesValue.put("Overdrafts", (long) 0);
expectedAttributesValue.put("PoolVersion", 0);
expectedAttributesValue.put("ReplaceAged", true);
expectedAttributesValue.put("ReplaceFlushed", false);
expectedAttributesValue.put("Replaced", (long) 0);
expectedAttributesValue.put("SweepInterval", (long) 10);
// expectedAttributesValue.put("Sweeps", (long) 1);
expectedAttributesValue.put("StrictPooling", true);
final List<MBeanAttributeInfo> actualAttributes = new ArrayList<MBeanAttributeInfo>();
final Map<String, Object> actualAttributesValue = new TreeMap<String, Object>();
for (final MBeanAttributeInfo info : poolMBeanInfo.getAttributes()) {
actualAttributes.add(info);
if (!info.getName().endsWith(".Latest") && !info.getName().endsWith(".LatestTime")
&& !info.getName().equals("Sweeps")) {
actualAttributesValue.put(info.getName(), server.getAttribute(objectName, info.getName()));
}
}
assertEquals(expectedAttributes, actualAttributes);
assertEquals(expectedAttributesValue, actualAttributesValue);
// Grab pool mbean operations
final MBeanParameterInfo[] operations = {
new MBeanParameterInfo("excludeRegex", "java.lang.String", "\"\""),
new MBeanParameterInfo("includeRegex", "java.lang.String", "\"\"")};
final List<MBeanOperationInfo> expectedOperations = new ArrayList<MBeanOperationInfo>();
expectedOperations.add(new MBeanOperationInfo(
"FilterAttributes",
"Filters the attributes that show up in the MBeanInfo. The exclude is applied first, then any attributes that match the include are re-added. It may be required to disconnect and reconnect the JMX console to force a refresh of the MBeanInfo",
operations, "void", MBeanOperationInfo.UNKNOWN));
expectedOperations.add(new MBeanOperationInfo("flush", "", new MBeanParameterInfo[0], "void", MBeanOperationInfo.UNKNOWN));
final List<MBeanOperationInfo> actualOperations = new ArrayList<MBeanOperationInfo>();
actualOperations.addAll(Arrays.asList(poolMBeanInfo.getOperations()));
assertEquals(expectedOperations, actualOperations);
}
public static void assertEquals(final List<?> expectedList, final List<?> actualList) {
Asserts.assertEquals(expectedList, actualList);
}
public static void assertEquals(final Map<?, ?> expectedMap, final Map<?, ?> actualMap) {
Asserts.assertEquals(expectedMap, actualMap, 1.1);
}
/**
* Attribute values that only need to be checked once (configuration constants):
* javax.management.MBeanAttributeInfo[description=, name=MaxAge, type=long, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=MaxAgeOffset, type=double, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=MaxSize, type=int, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=MinSize, type=int, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=SweepInterval, type=long, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=ReplaceAged, type=boolean, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=ReplaceFlushed, type=boolean, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=GarbageCollection, type=boolean, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=IdleTimeout, type=long, read-only, descriptor={}]
*
* @throws Exception On error
*/
public void testConfigOptions() throws Exception {
final Properties properties = new Properties();
properties.put("GarbageCollection", "false");
properties.put("IdleTimeout", "23 milliseconds");
properties.put("MaxAge", "12456789 milliseconds");
properties.put("MaxAgeOffset", "2");
properties.put("MaxSize", "55");
properties.put("MinSize", "22");
properties.put("ReplaceAged", "false");
properties.put("ReplaceFlushed", "true");
properties.put("SweepInterval", "999999 milliseconds");
deploy("testConfigOptions", properties);
assertAttribute("GarbageCollection", false);
assertAttribute("IdleTimeout", 23L);
assertAttribute("MaxAge", 12456789L);
assertAttribute("MaxAgeOffset", 2.0);
assertAttribute("MaxSize", 55);
assertAttribute("MinSize", 22);
assertAttribute("ReplaceAged", false);
assertAttribute("ReplaceFlushed", true);
assertAttribute("SweepInterval", 999999L);
}
/**
* Flusing related.
* javax.management.MBeanAttributeInfo[description=, name=Flushed, type=long, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=Flushes, type=long, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=PoolVersion, type=int, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=Replaced, type=long, read-only, descriptor={}]
*
* @throws Exception On error
*/
public void testFlushing() throws Exception {
final Properties properties = new Properties();
properties.put("MaxSize", "10");
properties.put("MinSize", "3");
properties.put("ReplaceFlushed", "false");
final CounterBean bean = deploy("testFlushing", properties);
checkout(bean, 8).release();
CounterBean.constructed = new CountDownLatch(3);
final Checkout checkout = checkout(bean, 7);
assertAttribute("PoolVersion", 0);
assertAttribute("Flushed", 0L);
assertAttribute("Flushes", 0L);
bean.flush();
checkout.release();
assertAttribute("PoolVersion", 1);
assertAttribute("Flushed", 8L);
assertAttribute("Flushes", 1L);
CounterBean.constructed.await(10, TimeUnit.SECONDS);
Thread.sleep(10);
assertAttribute("Replaced", 3L);
}
/**
* Flusing related.
* javax.management.MBeanAttributeInfo[description=, name=Flushed, type=long, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=Flushes, type=long, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=PoolVersion, type=int, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=Replaced, type=long, read-only, descriptor={}]
*
* @throws Exception On error
*/
public void testFlushingWithReplacement() throws Exception {
final Properties properties = new Properties();
properties.put("MaxSize", "10");
properties.put("MinSize", "3");
properties.put("ReplaceFlushed", "true");
final CounterBean bean = deploy("testFlushingWithReplacement", properties);
checkout(bean, 8).release();
CounterBean.constructed = new CountDownLatch(8);
final Checkout checkout = checkout(bean, 7);
assertAttribute("PoolVersion", 0);
assertAttribute("Flushed", 0L);
assertAttribute("Flushes", 0L);
bean.flush();
checkout.release();
assertAttribute("PoolVersion", 1);
assertAttribute("Flushed", 8L);
assertAttribute("Flushes", 1L);
CounterBean.constructed.await(10, TimeUnit.SECONDS);
Thread.sleep(10);
assertAttribute("Replaced", 8L);
}
/**
* Attribute values that should be checked with a new pool and again on a maxed pool:
* javax.management.MBeanAttributeInfo[description=, name=AvailablePermits, type=int, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=MinimumInstances, type=int, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=InstancesPooled, type=int, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=InstancesIdle, type=int, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=InstancesActive, type=int, read-only, descriptor={}]
*
* @throws Exception On error
*/
public void testInstances() throws Exception {
final Properties properties = new Properties();
properties.put("MaxSize", "10");
properties.put("MinSize", "4");
final CounterBean bean = deploy("testInstances", properties);
assertAttribute("AvailablePermits", 10);
assertAttribute("MinimumInstances", 4);
assertAttribute("InstancesPooled", 4);
assertAttribute("InstancesIdle", 4);
assertAttribute("InstancesActive", 0);
final Checkout checkout1 = checkout(bean, 3);
assertAttribute("AvailablePermits", 7);
assertAttribute("MinimumInstances", 4);
assertAttribute("InstancesPooled", 4);
assertAttribute("InstancesIdle", 1);
assertAttribute("InstancesActive", 3);
checkout1.release();
checkout(bean, 6).release();
final Checkout checkout2 = checkout(bean, 6);
assertAttribute("AvailablePermits", 4);
assertAttribute("MinimumInstances", 4);
assertAttribute("InstancesPooled", 6);
assertAttribute("InstancesIdle", 0);
assertAttribute("InstancesActive", 6);
checkout2.release();
}
/**
* javax.management.MBeanAttributeInfo[description=, name=Aged, type=long, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=Replaced, type=long, read-only, descriptor={}]
*
* @throws Exception On error
*/
public void testAging() throws Exception {
final Properties properties = new Properties();
properties.put("MaxSize", "10");
properties.put("MinSize", "3");
properties.put("MaxAge", "300 ms");
properties.put("ReplaceAged", "false");
properties.put("MaxAgeOffset", "0");
final CounterBean bean = deploy("testAging", properties);
assertAttribute("MaxAge", 300L);
checkout(bean, 5).release();
final Checkout checkout = checkout(bean, 5);
CounterBean.constructed = new CountDownLatch(3);
Thread.sleep(330);
checkout.release();
assertAttribute("Aged", 5L);
CounterBean.constructed.await(10, TimeUnit.SECONDS);
Thread.sleep(10);
assertAttribute("Replaced", 3L);
}
/**
* javax.management.MBeanAttributeInfo[description=, name=Aged, type=long, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=Replaced, type=long, read-only, descriptor={}]
*
* @throws Exception On error
*/
public void testAgingWithReplacement() throws Exception {
final Properties properties = new Properties();
properties.put("MaxSize", "10");
properties.put("MinSize", "3");
properties.put("MaxAge", "300 ms");
properties.put("ReplaceAged", "true");
properties.put("MaxAgeOffset", "0");
final CounterBean bean = deploy("testAgingWithReplacement", properties);
assertAttribute("MaxAge", 300L);
checkout(bean, 5).release();
final Checkout checkout = checkout(bean, 5);
CounterBean.constructed = new CountDownLatch(5);
Thread.sleep(330);
checkout.release();
assertAttribute("Aged", 5L);
CounterBean.constructed.await(10, TimeUnit.SECONDS);
Thread.sleep(10);
assertAttribute("Replaced", 5L);
}
/**
* Requires an invocation against a maxed pool with all instances checked out, must be a strict pool
* javax.management.MBeanAttributeInfo[description=, name=AccessTimeouts, type=long, read-only, descriptor={}]
*
* @throws Exception On error
*/
public void testAccessTimeouts() throws Exception {
final Properties properties = new Properties();
properties.put("MaxSize", "10");
properties.put("AccessTimeout", "0");
properties.put("StrictPooling", "true");
final CounterBean bean = deploy("testAccessTimeouts", properties);
assertAttribute("AccessTimeouts", 0l);
final Checkout checkout = checkout(bean, 10);
for (int i = 0; i < 7; i++) {
try {
bean.doSomething();
fail("ConcurrentAccessException should have been thrown");
} catch (final ConcurrentAccessException expected) {
}
}
checkout.release();
assertAttribute("AccessTimeouts", 7l);
}
/**
* Should be greater than 1 and 'Latest' should be no less than System.currentTimeMillis() - SweepInterval
* javax.management.MBeanAttributeInfo[description=, name=Sweeps, type=long, read-only, descriptor={}]
* javax.management.MBeanAttributeInfo[description=, name=Sweeps.Latest, type=java.lang.String, read-only, descriptor={}]
*
* @throws Exception On error
*/
public void testSweeps() throws Exception {
final Properties properties = new Properties();
properties.setProperty("SweepInterval", "100");
final Date expectedDate = new Date(); // now
deploy("testSweeps", properties);
Thread.sleep(200);
final Long sweeps = (Long) (server.getAttribute(objectName, "Sweeps"));
assertTrue("sweeps=" + sweeps, sweeps >= 1L);
final Object attribute = server.getAttribute(objectName, "Sweeps.LatestTime");
final Date actualDate = new Date((Long) attribute);
final String message = display("actual", actualDate) + " after " + display("expected", expectedDate);
assertTrue(message, actualDate.after(expectedDate));
}
private String display(final String name, final Date date) {
return name + "=" + date.getTime();
}
/**
* Fill a pool to the max, let the non-min instances timeout, check the IdleTimeouts
* javax.management.MBeanAttributeInfo[description=, name=IdleTimeouts, type=long, read-only, descriptor={}]
*
* @throws Exception On error
*/
public void testIdleTimeouts() throws Exception {
final Properties properties = new Properties();
properties.put("MaxSize", "10");
properties.put("MinSize", "3");
properties.put("IdleTimeout", "100 ms");
properties.put("SweepInterval", "50 ms");
final CounterBean bean = deploy("testIdleTimeouts", properties);
assertAttribute("SweepInterval", 50L);
assertAttribute("IdleTimeout", 100L);
CounterBean.discarded = new CountDownLatch(2);
checkout(bean, 5).release();
assertAttribute("InstancesPooled", 5);
assertAttribute("IdleTimeouts", 0L);
CounterBean.discarded.await(10, TimeUnit.SECONDS);
Thread.sleep(10);
assertAttribute("InstancesPooled", 3);
assertAttribute("IdleTimeouts", 2L);
}
/**
* Drain more than the max from a non-strict pool and test that Overdrafts
* reflects the number of instances beyond the max that were created
* javax.management.MBeanAttributeInfo[description=, name=Overdrafts, type=long, read-only, descriptor={}]
*
* @throws Exception On error
*/
public void testOverdrafts() throws Exception {
final Properties properties = new Properties();
properties.setProperty("MaxSize", "2");
properties.setProperty("MinSize", "0");
properties.setProperty("StrictPooling", "false");
final CounterBean bean = deploy("Overdrafts", properties);
assertAttribute("MaxSize", 2);
assertAttribute("MinSize", 0);
assertAttribute("StrictPooling", false);
assertAttribute("Overdrafts", 0L);
assertAttribute("AvailablePermits", 2);
final Checkout checkout = checkout(bean, 7);
assertAttribute("Overdrafts", 0L);
assertAttribute("AvailablePermits", -5);
checkout.release();
assertAttribute("AvailablePermits", 2);
assertAttribute("Overdrafts", 5L);
}
private void assertAttribute(final String name, final Object value) throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException {
if (Number.class.isInstance(value)) { // TODO: should be removed when we'll find why buildbot fails here
assertEquals(name, Number.class.cast(value).doubleValue(), Number.class.cast(server.getAttribute(objectName, name)).doubleValue(), 1.1);
} else {
assertEquals(name, value, server.getAttribute(objectName, name));
}
}
private CounterBean deploy(final String moduleId, final Properties properties) throws Exception {
objectName = new ObjectName("openejb.management:J2EEServer=openejb,J2EEApplication=<empty>,EJBModule=" + moduleId + ",StatelessSessionBean=CounterBean,j2eeType=Pool,name=CounterBean");
System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, org.apache.openejb.core.LocalInitialContextFactory.class.getName());
final ConfigurationFactory config = new ConfigurationFactory();
final Assembler assembler = new Assembler();
assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class));
assembler.createSecurityService(config.configureService(SecurityServiceInfo.class));
// containers
final StatelessSessionContainerInfo statelessContainerInfo = config.configureService(StatelessSessionContainerInfo.class);
statelessContainerInfo.properties.putAll(properties);
assembler.createContainer(statelessContainerInfo);
final EjbJar ejbJar = new EjbJar(moduleId);
ejbJar.addEnterpriseBean(new StatelessBean(CounterBean.class));
assembler.createApplication(config.configureApplication(ejbJar));
final javax.naming.Context context = new InitialContext();
return (CounterBean) context.lookup("CounterBeanLocalBean");
}
/**
* convenience method for checking out a specific number of instances.
* Can be used like so:
* <p/>
* // checkout some instances from the pool
* CountDownLatch startingPistol = checkout(bean, 7);
* <p/>
* // Look at pool stats
* ...
* <p/>
* // Release them all back into the pool
* startingPistol.countDown();
*
* @param bean CounterBean
* @param count int
* @return Checkout
* @throws InterruptedException On error
*/
private Checkout checkout(final CounterBean bean, final int count) throws InterruptedException {
final CountDownLatch startingLine = new CountDownLatch(count);
final Checkout checkout = new Checkout(count);
for (int i = 0; i < count; i++) {
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
bean.checkout(startingLine, checkout.startingPistol);
checkout.finishLine.countDown();
}
});
thread.setDaemon(true);
thread.start();
}
startingLine.await(60, TimeUnit.SECONDS);
return checkout;
}
public static class Checkout {
final CountDownLatch startingPistol = new CountDownLatch(1);
final CountDownLatch finishLine;
public Checkout(final int count) {
finishLine = new CountDownLatch(count);
}
public boolean release() {
try {
startingPistol.countDown();
return finishLine.await(60, TimeUnit.SECONDS);
} catch (final InterruptedException e) {
Thread.interrupted();
return false;
}
}
}
@Monitor
public static class CounterBean {
public static CountDownLatch discarded = new CountDownLatch(0);
public static CountDownLatch constructed = new CountDownLatch(0);
@Resource
private SessionContext sessionContext;
@PostConstruct
private void construct() {
constructed.countDown();
}
@PreDestroy
private void destroy() {
discarded.countDown();
}
public void doSomething() {
}
public void checkout(final CountDownLatch startingLine, final CountDownLatch startPistol) {
try {
startingLine.countDown();
startPistol.await(60, TimeUnit.SECONDS);
} catch (final InterruptedException e) {
Thread.interrupted();
throw new RuntimeException(e);
}
}
public void flush() throws IOException {
((Flushable) sessionContext).flush();
}
}
}