You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomee.apache.org by Thiago Veronezi <th...@veronezi.org> on 2015/11/20 21:23:18 UTC

Re: tomee git commit: better cleaning of our thread after execution

Hi Romain,
It looks like this commit breaks the build here...

https://github.com/apache/tomee/blob/master/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java#L736

Is that right?

Nov 19, 2015 4:34:40 PM org.apache.openejb.util.LogStreamAsync run
INFO: Undeploying app:
/home/buildslave18/slave18/tomee-trunk-ubuntu/build/container/openejb-core/target/AppTests
run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 1.397 sec
<<< FAILURE! - in
org.apache.openejb.junit.ContainerApplicationRuleTest
run(org.apache.openejb.junit.ContainerApplicationRuleTest)  Time
elapsed: 1.346 sec  <<< ERROR!
java.lang.NullPointerException: null
	at org.apache.openejb.testing.ApplicationComposers.deployApp(ApplicationComposers.java:736)
	at org.apache.openejb.junit.ApplicationRule$1.evaluate(ApplicationRule.java:45)
	at org.apache.openejb.junit.ContainerRule$1.evaluate(ContainerRule.java:45)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
	at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
	at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
	at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)




On Wed, Nov 18, 2015 at 6:30 PM, <rm...@apache.org> wrote:

> Repository: tomee
> Updated Branches:
>   refs/heads/master dd28c89b2 -> 456a16d56
>
>
> better cleaning of our thread after execution
>
>
> Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
> Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/456a16d5
> Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/456a16d5
> Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/456a16d5
>
> Branch: refs/heads/master
> Commit: 456a16d5610e79d3fb2ce57ec2362949bee41378
> Parents: dd28c89
> Author: Romain Manni-Bucau <rm...@gmail.com>
> Authored: Wed Nov 18 15:30:01 2015 -0800
> Committer: Romain Manni-Bucau <rm...@gmail.com>
> Committed: Wed Nov 18 15:30:01 2015 -0800
>
> ----------------------------------------------------------------------
>  .../openejb/assembler/classic/Assembler.java    |  14 ++
>  .../core/security/AbstractSecurityService.java  |   8 +-
>  .../core/stateless/StatelessContainer.java      |   8 +-
>  .../stateless/StatelessInstanceManager.java     |  26 +++
>  .../GeronimoTransactionManagerFactory.java      |  32 ++-
>  .../openejb/testing/ApplicationComposers.java   |  11 +-
>  .../activemq/ProperConnectionShutdownTest.java  | 227 +++++++++++++++++++
>  7 files changed, 321 insertions(+), 5 deletions(-)
> ----------------------------------------------------------------------
>
>
>
> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
> ----------------------------------------------------------------------
> diff --git
> a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
> b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
> index 69149ef..7064052 100644
> ---
> a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
> +++
> b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
> @@ -1808,6 +1808,20 @@ public class Assembler extends AssemblerTool
> implements org.apache.openejb.spi.A
>              systemInstance.removeComponent(EjbResolver.class);
>              systemInstance.fireEvent(new AssemblerDestroyed());
>              systemInstance.removeObservers();
> +
> +            if
> (DestroyableResource.class.isInstance(this.securityService)) {
> +
> DestroyableResource.class.cast(this.securityService).destroyResource();
> +            }
> +            if
> (DestroyableResource.class.isInstance(this.transactionManager)) {
> +
> DestroyableResource.class.cast(this.transactionManager).destroyResource();
> +            }
> +
> +            for (final Container c : this.containerSystem.containers()) {
> +                if (DestroyableResource.class.isInstance(c)) { // TODO:
> should we use auto closeable there?
> +                    DestroyableResource.class.cast(c).destroyResource();
> +                }
> +            }
> +
>              SystemInstance.reset();
>          } finally {
>              l.unlock();
>
>
> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
> ----------------------------------------------------------------------
> diff --git
> a/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
> b/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
> index c894adc..2c1a798 100644
> ---
> a/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
> +++
> b/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
> @@ -19,6 +19,7 @@ package org.apache.openejb.core.security;
>
>  import org.apache.openejb.BeanContext;
>  import org.apache.openejb.InterfaceType;
> +import org.apache.openejb.api.resource.DestroyableResource;
>  import org.apache.openejb.core.ThreadContext;
>  import org.apache.openejb.core.ThreadContextListener;
>  import org.apache.openejb.core.security.jaas.GroupPrincipal;
> @@ -58,7 +59,7 @@ import java.util.concurrent.ConcurrentHashMap;
>   * to clients, is mostly secure, and can be deserialized in a client vm
> without
>   * addition openejb-core classes.
>   */
> -public abstract class AbstractSecurityService implements
> SecurityService<UUID>, ThreadContextListener,
> BasicPolicyConfiguration.RoleResolver {
> +public abstract class AbstractSecurityService implements
> DestroyableResource, SecurityService<UUID>, ThreadContextListener,
> BasicPolicyConfiguration.RoleResolver {
>
>      private static final Map<Object, Identity> identities = new
> ConcurrentHashMap<Object, Identity>();
>      protected static final ThreadLocal<Identity> clientIdentity = new
> ThreadLocal<Identity>();
> @@ -84,6 +85,11 @@ public abstract class AbstractSecurityService
> implements SecurityService<UUID>,
>
>  SystemInstance.get().setComponent(BasicPolicyConfiguration.RoleResolver.class,
> this);
>      }
>
> +    @Override
> +    public void destroyResource() {
> +        // no-op
> +    }
> +
>      public String getRealmName() {
>          return realmName;
>      }
>
>
> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
> ----------------------------------------------------------------------
> diff --git
> a/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
> b/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
> index 62bee31..11f43e0 100644
> ---
> a/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
> +++
> b/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
> @@ -23,6 +23,7 @@ import org.apache.openejb.InterfaceType;
>  import org.apache.openejb.OpenEJBException;
>  import org.apache.openejb.ProxyInfo;
>  import org.apache.openejb.SystemException;
> +import org.apache.openejb.api.resource.DestroyableResource;
>  import org.apache.openejb.cdi.CurrentCreationalContext;
>  import org.apache.openejb.core.ExceptionType;
>  import org.apache.openejb.core.Operation;
> @@ -59,7 +60,7 @@ import static
> org.apache.openejb.core.transaction.EjbTransactionUtil.handleSyste
>  /**
>   * @org.apache.xbean.XBean element="statelessContainer"
>   */
> -public class StatelessContainer implements
> org.apache.openejb.RpcContainer {
> +public class StatelessContainer implements
> org.apache.openejb.RpcContainer, DestroyableResource {
>
>      private final ConcurrentMap<Class<?>, List<Method>> interceptorCache
> = new ConcurrentHashMap<Class<?>, List<Method>>();
>      private final StatelessInstanceManager instanceManager;
> @@ -325,4 +326,9 @@ public class StatelessContainer implements
> org.apache.openejb.RpcContainer {
>          }
>          return annotated;
>      }
> +
> +    @Override
> +    public void destroyResource() {
> +        this.instanceManager.destroy();
> +    }
>  }
>
>
> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
> ----------------------------------------------------------------------
> diff --git
> a/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
> b/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
> index aa6617c..c8986f7 100644
> ---
> a/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
> +++
> b/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
> @@ -70,6 +70,9 @@ import java.util.concurrent.ThreadFactory;
>  import java.util.concurrent.ThreadPoolExecutor;
>  import java.util.concurrent.TimeUnit;
>  import java.util.concurrent.TimeoutException;
> +import java.util.logging.Level;
> +
> +import static java.util.concurrent.TimeUnit.MILLISECONDS;
>
>  public class StatelessInstanceManager {
>      private static final Logger logger =
> Logger.getInstance(LogCategory.OPENEJB,
> "org.apache.openejb.util.resources");
> @@ -168,6 +171,29 @@ public class StatelessInstanceManager {
>          }
>      }
>
> +    public void destroy() {
> +        if (executor != null) {
> +            executor.shutdown();
> +            try {
> +                if (!executor.awaitTermination(10000, MILLISECONDS)) {
> +
> java.util.logging.Logger.getLogger(this.getClass().getName()).log(Level.WARNING,
> getClass().getSimpleName() + " pool  timeout expired");
> +                }
> +            } catch (final InterruptedException e) {
> +                Thread.interrupted();
> +            }
> +        }
> +        if (scheduledExecutor != null) {
> +            scheduledExecutor.shutdown();
> +            try {
> +                if (!scheduledExecutor.awaitTermination(10000,
> MILLISECONDS)) {
> +
> java.util.logging.Logger.getLogger(this.getClass().getName()).log(Level.WARNING,
> getClass().getSimpleName() + " pool  timeout expired");
> +                }
> +            } catch (final InterruptedException e) {
> +                Thread.interrupted();
> +            }
> +        }
> +    }
> +
>      /**
>       * Removes an instance from the pool and returns it for use
>       * by the container in business methods.
>
>
> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoTransactionManagerFactory.java
> ----------------------------------------------------------------------
> diff --git
> a/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoTransactionManagerFactory.java
> b/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoTransactionManagerFactory.java
> index 9681b92..5facdd4 100644
> ---
> a/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoTransactionManagerFactory.java
> +++
> b/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoTransactionManagerFactory.java
> @@ -19,8 +19,10 @@
>  package org.apache.openejb.resource;
>
>  import org.apache.geronimo.transaction.log.HOWLLog;
> +import
> org.apache.geronimo.transaction.manager.ExponentialtIntervalRetryScheduler;
>  import org.apache.geronimo.transaction.manager.GeronimoTransactionManager;
>  import org.apache.geronimo.transaction.manager.TransactionLog;
> +import org.apache.geronimo.transaction.manager.TransactionManagerImpl;
>  import org.apache.geronimo.transaction.manager.WrapperNamedXAResource;
>  import org.apache.geronimo.transaction.manager.XidFactory;
>  import org.apache.geronimo.transaction.manager.XidFactoryImpl;
> @@ -29,12 +31,16 @@ import org.apache.openejb.api.jmx.Description;
>  import org.apache.openejb.api.jmx.MBean;
>  import org.apache.openejb.api.jmx.ManagedAttribute;
>  import org.apache.openejb.api.jmx.ManagedOperation;
> +import org.apache.openejb.api.resource.DestroyableResource;
>  import org.apache.openejb.loader.SystemInstance;
>  import org.apache.openejb.monitoring.LocalMBeanServer;
>  import org.apache.openejb.monitoring.ObjectNameBuilder;
>  import org.apache.openejb.util.Duration;
>
> +import javax.transaction.xa.XAException;
>  import javax.transaction.xa.XAResource;
> +import java.lang.reflect.Field;
> +import java.util.Timer;
>  import java.util.concurrent.TimeUnit;
>
>  /**
> @@ -102,7 +108,7 @@ public class GeronimoTransactionManagerFactory {
>              ((HOWLLog) txLog).doStart();
>          }
>
> -        final GeronimoTransactionManager geronimoTransactionManager = new
> GeronimoTransactionManager(defaultTransactionTimeoutSeconds, xidFactory,
> txLog);
> +        final GeronimoTransactionManager geronimoTransactionManager = new
> DestroyableTransactionManager(defaultTransactionTimeoutSeconds, xidFactory,
> txLog);
>          final ObjectNameBuilder jmxName = new
> ObjectNameBuilder("openejb.management")
>              .set("j2eeType", "TransactionManager");
>          LocalMBeanServer.registerDynamicWrapperSilently(
> @@ -112,6 +118,30 @@ public class GeronimoTransactionManagerFactory {
>          return geronimoTransactionManager;
>      }
>
> +    public static class DestroyableTransactionManager extends
> GeronimoTransactionManager implements DestroyableResource {
> +        public DestroyableTransactionManager(final int
> defaultTransactionTimeoutSeconds, final XidFactory xidFactory, final
> TransactionLog transactionLog) throws XAException {
> +            super(defaultTransactionTimeoutSeconds, xidFactory,
> transactionLog);
> +        }
> +
> +        @Override
> +        public void destroyResource() {
> +            // try to clean up
> +            try {
> +                final Field f =
> TransactionManagerImpl.class.getDeclaredField("retryScheduler");
> +                f.setAccessible(true);
> +                final ExponentialtIntervalRetryScheduler rs =
> ExponentialtIntervalRetryScheduler.class.cast(f.get(this));
> +
> +                final Field t =
> ExponentialtIntervalRetryScheduler.class.getDeclaredField("timer");
> +                t.setAccessible(true);
> +
> +                final Timer timer = Timer.class.cast(t.get(rs));
> +                timer.cancel();
> +            } catch (final Throwable notImportant) {
> +                // no-op
> +            }
> +        }
> +    }
> +
>      public static class GeronimoXAResourceWrapper implements
> XAResourceWrapper {
>          public XAResource wrap(final XAResource xaResource, final String
> name) {
>              return new WrapperNamedXAResource(xaResource, name);
>
>
> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
> ----------------------------------------------------------------------
> diff --git
> a/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
> b/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
> index 4b83058..ef07bf9 100644
> ---
> a/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
> +++
> b/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
> @@ -182,7 +182,10 @@ public class ApplicationComposers {
>          testClassFinders.put(this, new ClassFinder(ancestors(klass))); //
> using this temporary since we don't have yet the instance
>          if (additionalModules != null) {
>              for (final Object o : additionalModules) {
> -                testClassFinders.put(o, new
> ClassFinder(ancestors(o.getClass())));
> +                final Class<?> aClass = o.getClass();
> +                if (aClass != klass) {
> +                    testClassFinders.put(o, new
> ClassFinder(ancestors(aClass)));
> +                }
>              }
>          }
>
> @@ -349,7 +352,11 @@ public class ApplicationComposers {
>                  annotatedMethods = newAnnotatedMethods;
>                  map.put(key, annotatedMethods);
>              } else {
> -                annotatedMethods.addAll(newAnnotatedMethods);
> +                for (final Method m : newAnnotatedMethods) {
> +                    if (!annotatedMethods.contains(m)) {
> +                        annotatedMethods.add(m);
> +                    }
> +                }
>              }
>          }
>          return map;
>
>
> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/test/java/org/apache/openejb/resource/activemq/ProperConnectionShutdownTest.java
> ----------------------------------------------------------------------
> diff --git
> a/container/openejb-core/src/test/java/org/apache/openejb/resource/activemq/ProperConnectionShutdownTest.java
> b/container/openejb-core/src/test/java/org/apache/openejb/resource/activemq/ProperConnectionShutdownTest.java
> new file mode 100644
> index 0000000..49d9a27
> --- /dev/null
> +++
> b/container/openejb-core/src/test/java/org/apache/openejb/resource/activemq/ProperConnectionShutdownTest.java
> @@ -0,0 +1,227 @@
> +/**
> + *
> + * 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.resource.activemq;
> +
> +import org.apache.openejb.jee.WebApp;
> +import org.apache.openejb.junit.DeployApplication;
> +import org.apache.openejb.testing.ApplicationComposers;
> +import org.apache.openejb.testing.Classes;
> +import org.apache.openejb.testing.Configuration;
> +import org.apache.openejb.testing.Module;
> +import org.apache.openejb.testng.PropertiesBuilder;
> +import org.apache.openejb.util.Join;
> +import org.apache.openejb.util.NetworkUtil;
> +import org.junit.Ignore;
> +import org.junit.Test;
> +import org.junit.runners.model.Statement;
> +
> +import javax.annotation.Resource;
> +import javax.ejb.EJB;
> +import javax.ejb.Stateless;
> +import javax.jms.Connection;
> +import javax.jms.ConnectionFactory;
> +import javax.jms.DeliveryMode;
> +import javax.jms.JMSException;
> +import javax.jms.MessageConsumer;
> +import javax.jms.MessageProducer;
> +import javax.jms.Queue;
> +import javax.jms.Session;
> +import javax.jms.TextMessage;
> +import java.util.Locale;
> +import java.util.Properties;
> +import java.util.concurrent.atomic.AtomicReference;
> +
> +import static org.junit.Assert.assertEquals;
> +import static org.junit.Assert.assertTrue;
> +
> +// inspired from MessagingBeanTest in examples
> +public class ProperConnectionShutdownTest {
> +    @Test
> +    @Ignore("https://issues.apache.org/jira/browse/AMQ-6051")
> +    public void run() throws Throwable {
> +        final Thread[] threadsBefore = listThreads();
> +        final AtomicReference<Thread[]> threadWhile = new
> AtomicReference<>();
> +
> +        // run test
> +        final Statement testInContainer = new Statement() {
> +            @Override
> +            public void evaluate() throws Throwable {
> +                messages.sendMessage("Hello World!");
> +                messages.sendMessage("How are you?");
> +
> +                threadWhile.set(listThreads());
> +
> +                messages.sendMessage("Still spinning?");
> +
> +                assertEquals(messages.receiveMessage(), "Hello World!");
> +                assertEquals(messages.receiveMessage(), "How are you?");
> +                assertEquals(messages.receiveMessage(), "Still
> spinning?");
> +
> +                /* TODO: activate it when AMQ-6051 is fixed
> +
> +                // all worked, now hold a connection
> +                new Thread(new Runnable() { // not daemon!
> +                    @Override
> +                    public void run() {
> +                        messages.blockConnection(); // oops, I forgot to
> close it
> +                    }
> +                }).start();
> +                 */
> +            }
> +        };
> +        new DeployApplication(this, testInContainer, new
> ApplicationComposers(this)).evaluate();
> +
> +        Thread.sleep(2250); // AMQ state (started) polling for transport
> thread is 1s
> +        while (Join.join("", listThreads()).contains("ActiveMQ Session
> Task")) { // let few sec to AMQ to leave the holding task
> +            Thread.sleep(1000);
> +        }
> +
> +        // ensure no connection are leaking
> +        final Thread[] threadsAfter = listThreads();
> +
> +        int countAMQ = 0;
> +        int countOthers = 0;
> +        for (final Thread t : threadsAfter) {
> +            if (!t.isAlive()) {
> +                continue;
> +            }
> +            if (t.getName().contains("AMQ") ||
> t.getName().toLowerCase(Locale.ENGLISH).contains("activemq")) {
> +                countAMQ++;
> +            } else {
> +                countOthers++;
> +            }
> +        }
> +
> +        final String debugMessage = Join.join(", ", threadsAfter);
> +
> +        assertEquals(debugMessage, 0, countAMQ);
> +
> +        // geronimo libs spawn 2 threads we know: PoolIdleReleaseTimer
> and CurrentTime so we can get initial + 2 threads there
> +        assertTrue(debugMessage, countOthers <= threadsBefore.length + 2);
> +    }
> +
> +    private Thread[] listThreads() {
> +        final Thread[] threads = new Thread[Thread.activeCount()];
> +        final int count = Thread.enumerate(threads);
> +        if (count < threads.length) {
> +            final Thread[] copy = new Thread[count];
> +            System.arraycopy(threads, 0, copy, 0, count);
> +            return copy;
> +        }
> +        return threads;
> +    }
> +
> +    @EJB
> +    private Messages messages;
> +
> +    @Configuration
> +    public Properties config() {
> +        return new PropertiesBuilder()
> +            .p("Default JMS Resource Adapter.BrokerXmlConfig",
> "broker:(tcp://localhost:" + NetworkUtil.getNextAvailablePort() +
> ")?useJmx=false")
> +            .build();
> +    }
> +
> +    @Module
> +    @Classes(innerClassesAsBean = true)
> +    public WebApp app() {
> +        return new WebApp();
> +    }
> +
> +    @Stateless
> +    public static class Messages {
> +
> +        @Resource
> +        private ConnectionFactory connectionFactory;
> +
> +        @Resource
> +        private Queue chatQueue;
> +
> +        public void sendMessage(String text) throws JMSException {
> +
> +            Connection connection = null;
> +            Session session = null;
> +
> +            try {
> +                connection = connectionFactory.createConnection();
> +                connection.start();
> +
> +                // Create a Session
> +                session = connection.createSession(false,
> Session.AUTO_ACKNOWLEDGE);
> +
> +                // Create a MessageProducer from the Session to the Topic
> or Queue
> +                MessageProducer producer =
> session.createProducer(chatQueue);
> +                producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
> +
> +                // Create a message
> +                TextMessage message = session.createTextMessage(text);
> +
> +                // Tell the producer to send the message
> +                producer.send(message);
> +            } finally {
> +                // Clean up
> +                if (session != null) {
> +                    session.close();
> +                }
> +                if (connection != null) {
> +                    connection.close();
> +                }
> +            }
> +        }
> +
> +        public String receiveMessage() throws JMSException {
> +
> +            Connection connection = null;
> +            Session session = null;
> +            MessageConsumer consumer = null;
> +            try {
> +                connection = connectionFactory.createConnection();
> +                connection.start();
> +
> +                // Create a Session
> +                session = connection.createSession(false,
> Session.AUTO_ACKNOWLEDGE);
> +
> +                // Create a MessageConsumer from the Session to the Topic
> or Queue
> +                consumer = session.createConsumer(chatQueue);
> +
> +                // Wait for a message
> +                TextMessage message = (TextMessage)
> consumer.receive(1000);
> +
> +                return message.getText();
> +            } finally {
> +                if (consumer != null) {
> +                    consumer.close();
> +                }
> +                if (session != null) {
> +                    session.close();
> +                }
> +                if (connection != null) {
> +                    connection.close();
> +                }
> +            }
> +
> +        }
> +
> +        public void blockConnection() {
> +            try {
> +                connectionFactory.createConnection();
> +            } catch (final JMSException e) {
> +                throw new IllegalStateException(e);
> +            }
> +        }
> +    }
> +}
>
>

Re: tomee git commit: better cleaning of our thread after execution

Posted by Romain Manni-Bucau <rm...@gmail.com>.
should be fine now, thanks for the heads up

Romain Manni-Bucau
@rmannibucau |  Blog | Github | LinkedIn | Tomitriber


2015-11-20 12:23 GMT-08:00 Thiago Veronezi <th...@veronezi.org>:
> Hi Romain,
> It looks like this commit breaks the build here...
>
> https://github.com/apache/tomee/blob/master/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java#L736
>
> Is that right?
>
> Nov 19, 2015 4:34:40 PM org.apache.openejb.util.LogStreamAsync run
> INFO: Undeploying app:
> /home/buildslave18/slave18/tomee-trunk-ubuntu/build/container/openejb-core/target/AppTests
> run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 1.397 sec
> <<< FAILURE! - in
> org.apache.openejb.junit.ContainerApplicationRuleTest
> run(org.apache.openejb.junit.ContainerApplicationRuleTest)  Time
> elapsed: 1.346 sec  <<< ERROR!
> java.lang.NullPointerException: null
>         at org.apache.openejb.testing.ApplicationComposers.deployApp(ApplicationComposers.java:736)
>         at org.apache.openejb.junit.ApplicationRule$1.evaluate(ApplicationRule.java:45)
>         at org.apache.openejb.junit.ContainerRule$1.evaluate(ContainerRule.java:45)
>         at org.junit.rules.RunRules.evaluate(RunRules.java:20)
>         at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
>         at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
>         at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
>         at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
>         at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
>         at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
>         at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
>         at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
>         at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
>         at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
>         at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
>         at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
>         at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
>         at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
>         at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
>
>
>
>
> On Wed, Nov 18, 2015 at 6:30 PM, <rm...@apache.org> wrote:
>
>> Repository: tomee
>> Updated Branches:
>>   refs/heads/master dd28c89b2 -> 456a16d56
>>
>>
>> better cleaning of our thread after execution
>>
>>
>> Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
>> Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/456a16d5
>> Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/456a16d5
>> Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/456a16d5
>>
>> Branch: refs/heads/master
>> Commit: 456a16d5610e79d3fb2ce57ec2362949bee41378
>> Parents: dd28c89
>> Author: Romain Manni-Bucau <rm...@gmail.com>
>> Authored: Wed Nov 18 15:30:01 2015 -0800
>> Committer: Romain Manni-Bucau <rm...@gmail.com>
>> Committed: Wed Nov 18 15:30:01 2015 -0800
>>
>> ----------------------------------------------------------------------
>>  .../openejb/assembler/classic/Assembler.java    |  14 ++
>>  .../core/security/AbstractSecurityService.java  |   8 +-
>>  .../core/stateless/StatelessContainer.java      |   8 +-
>>  .../stateless/StatelessInstanceManager.java     |  26 +++
>>  .../GeronimoTransactionManagerFactory.java      |  32 ++-
>>  .../openejb/testing/ApplicationComposers.java   |  11 +-
>>  .../activemq/ProperConnectionShutdownTest.java  | 227 +++++++++++++++++++
>>  7 files changed, 321 insertions(+), 5 deletions(-)
>> ----------------------------------------------------------------------
>>
>>
>>
>> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
>> b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
>> index 69149ef..7064052 100644
>> ---
>> a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
>> +++
>> b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
>> @@ -1808,6 +1808,20 @@ public class Assembler extends AssemblerTool
>> implements org.apache.openejb.spi.A
>>              systemInstance.removeComponent(EjbResolver.class);
>>              systemInstance.fireEvent(new AssemblerDestroyed());
>>              systemInstance.removeObservers();
>> +
>> +            if
>> (DestroyableResource.class.isInstance(this.securityService)) {
>> +
>> DestroyableResource.class.cast(this.securityService).destroyResource();
>> +            }
>> +            if
>> (DestroyableResource.class.isInstance(this.transactionManager)) {
>> +
>> DestroyableResource.class.cast(this.transactionManager).destroyResource();
>> +            }
>> +
>> +            for (final Container c : this.containerSystem.containers()) {
>> +                if (DestroyableResource.class.isInstance(c)) { // TODO:
>> should we use auto closeable there?
>> +                    DestroyableResource.class.cast(c).destroyResource();
>> +                }
>> +            }
>> +
>>              SystemInstance.reset();
>>          } finally {
>>              l.unlock();
>>
>>
>> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
>> b/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
>> index c894adc..2c1a798 100644
>> ---
>> a/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
>> +++
>> b/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
>> @@ -19,6 +19,7 @@ package org.apache.openejb.core.security;
>>
>>  import org.apache.openejb.BeanContext;
>>  import org.apache.openejb.InterfaceType;
>> +import org.apache.openejb.api.resource.DestroyableResource;
>>  import org.apache.openejb.core.ThreadContext;
>>  import org.apache.openejb.core.ThreadContextListener;
>>  import org.apache.openejb.core.security.jaas.GroupPrincipal;
>> @@ -58,7 +59,7 @@ import java.util.concurrent.ConcurrentHashMap;
>>   * to clients, is mostly secure, and can be deserialized in a client vm
>> without
>>   * addition openejb-core classes.
>>   */
>> -public abstract class AbstractSecurityService implements
>> SecurityService<UUID>, ThreadContextListener,
>> BasicPolicyConfiguration.RoleResolver {
>> +public abstract class AbstractSecurityService implements
>> DestroyableResource, SecurityService<UUID>, ThreadContextListener,
>> BasicPolicyConfiguration.RoleResolver {
>>
>>      private static final Map<Object, Identity> identities = new
>> ConcurrentHashMap<Object, Identity>();
>>      protected static final ThreadLocal<Identity> clientIdentity = new
>> ThreadLocal<Identity>();
>> @@ -84,6 +85,11 @@ public abstract class AbstractSecurityService
>> implements SecurityService<UUID>,
>>
>>  SystemInstance.get().setComponent(BasicPolicyConfiguration.RoleResolver.class,
>> this);
>>      }
>>
>> +    @Override
>> +    public void destroyResource() {
>> +        // no-op
>> +    }
>> +
>>      public String getRealmName() {
>>          return realmName;
>>      }
>>
>>
>> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
>> b/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
>> index 62bee31..11f43e0 100644
>> ---
>> a/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
>> +++
>> b/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
>> @@ -23,6 +23,7 @@ import org.apache.openejb.InterfaceType;
>>  import org.apache.openejb.OpenEJBException;
>>  import org.apache.openejb.ProxyInfo;
>>  import org.apache.openejb.SystemException;
>> +import org.apache.openejb.api.resource.DestroyableResource;
>>  import org.apache.openejb.cdi.CurrentCreationalContext;
>>  import org.apache.openejb.core.ExceptionType;
>>  import org.apache.openejb.core.Operation;
>> @@ -59,7 +60,7 @@ import static
>> org.apache.openejb.core.transaction.EjbTransactionUtil.handleSyste
>>  /**
>>   * @org.apache.xbean.XBean element="statelessContainer"
>>   */
>> -public class StatelessContainer implements
>> org.apache.openejb.RpcContainer {
>> +public class StatelessContainer implements
>> org.apache.openejb.RpcContainer, DestroyableResource {
>>
>>      private final ConcurrentMap<Class<?>, List<Method>> interceptorCache
>> = new ConcurrentHashMap<Class<?>, List<Method>>();
>>      private final StatelessInstanceManager instanceManager;
>> @@ -325,4 +326,9 @@ public class StatelessContainer implements
>> org.apache.openejb.RpcContainer {
>>          }
>>          return annotated;
>>      }
>> +
>> +    @Override
>> +    public void destroyResource() {
>> +        this.instanceManager.destroy();
>> +    }
>>  }
>>
>>
>> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
>> b/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
>> index aa6617c..c8986f7 100644
>> ---
>> a/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
>> +++
>> b/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
>> @@ -70,6 +70,9 @@ import java.util.concurrent.ThreadFactory;
>>  import java.util.concurrent.ThreadPoolExecutor;
>>  import java.util.concurrent.TimeUnit;
>>  import java.util.concurrent.TimeoutException;
>> +import java.util.logging.Level;
>> +
>> +import static java.util.concurrent.TimeUnit.MILLISECONDS;
>>
>>  public class StatelessInstanceManager {
>>      private static final Logger logger =
>> Logger.getInstance(LogCategory.OPENEJB,
>> "org.apache.openejb.util.resources");
>> @@ -168,6 +171,29 @@ public class StatelessInstanceManager {
>>          }
>>      }
>>
>> +    public void destroy() {
>> +        if (executor != null) {
>> +            executor.shutdown();
>> +            try {
>> +                if (!executor.awaitTermination(10000, MILLISECONDS)) {
>> +
>> java.util.logging.Logger.getLogger(this.getClass().getName()).log(Level.WARNING,
>> getClass().getSimpleName() + " pool  timeout expired");
>> +                }
>> +            } catch (final InterruptedException e) {
>> +                Thread.interrupted();
>> +            }
>> +        }
>> +        if (scheduledExecutor != null) {
>> +            scheduledExecutor.shutdown();
>> +            try {
>> +                if (!scheduledExecutor.awaitTermination(10000,
>> MILLISECONDS)) {
>> +
>> java.util.logging.Logger.getLogger(this.getClass().getName()).log(Level.WARNING,
>> getClass().getSimpleName() + " pool  timeout expired");
>> +                }
>> +            } catch (final InterruptedException e) {
>> +                Thread.interrupted();
>> +            }
>> +        }
>> +    }
>> +
>>      /**
>>       * Removes an instance from the pool and returns it for use
>>       * by the container in business methods.
>>
>>
>> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoTransactionManagerFactory.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoTransactionManagerFactory.java
>> b/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoTransactionManagerFactory.java
>> index 9681b92..5facdd4 100644
>> ---
>> a/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoTransactionManagerFactory.java
>> +++
>> b/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoTransactionManagerFactory.java
>> @@ -19,8 +19,10 @@
>>  package org.apache.openejb.resource;
>>
>>  import org.apache.geronimo.transaction.log.HOWLLog;
>> +import
>> org.apache.geronimo.transaction.manager.ExponentialtIntervalRetryScheduler;
>>  import org.apache.geronimo.transaction.manager.GeronimoTransactionManager;
>>  import org.apache.geronimo.transaction.manager.TransactionLog;
>> +import org.apache.geronimo.transaction.manager.TransactionManagerImpl;
>>  import org.apache.geronimo.transaction.manager.WrapperNamedXAResource;
>>  import org.apache.geronimo.transaction.manager.XidFactory;
>>  import org.apache.geronimo.transaction.manager.XidFactoryImpl;
>> @@ -29,12 +31,16 @@ import org.apache.openejb.api.jmx.Description;
>>  import org.apache.openejb.api.jmx.MBean;
>>  import org.apache.openejb.api.jmx.ManagedAttribute;
>>  import org.apache.openejb.api.jmx.ManagedOperation;
>> +import org.apache.openejb.api.resource.DestroyableResource;
>>  import org.apache.openejb.loader.SystemInstance;
>>  import org.apache.openejb.monitoring.LocalMBeanServer;
>>  import org.apache.openejb.monitoring.ObjectNameBuilder;
>>  import org.apache.openejb.util.Duration;
>>
>> +import javax.transaction.xa.XAException;
>>  import javax.transaction.xa.XAResource;
>> +import java.lang.reflect.Field;
>> +import java.util.Timer;
>>  import java.util.concurrent.TimeUnit;
>>
>>  /**
>> @@ -102,7 +108,7 @@ public class GeronimoTransactionManagerFactory {
>>              ((HOWLLog) txLog).doStart();
>>          }
>>
>> -        final GeronimoTransactionManager geronimoTransactionManager = new
>> GeronimoTransactionManager(defaultTransactionTimeoutSeconds, xidFactory,
>> txLog);
>> +        final GeronimoTransactionManager geronimoTransactionManager = new
>> DestroyableTransactionManager(defaultTransactionTimeoutSeconds, xidFactory,
>> txLog);
>>          final ObjectNameBuilder jmxName = new
>> ObjectNameBuilder("openejb.management")
>>              .set("j2eeType", "TransactionManager");
>>          LocalMBeanServer.registerDynamicWrapperSilently(
>> @@ -112,6 +118,30 @@ public class GeronimoTransactionManagerFactory {
>>          return geronimoTransactionManager;
>>      }
>>
>> +    public static class DestroyableTransactionManager extends
>> GeronimoTransactionManager implements DestroyableResource {
>> +        public DestroyableTransactionManager(final int
>> defaultTransactionTimeoutSeconds, final XidFactory xidFactory, final
>> TransactionLog transactionLog) throws XAException {
>> +            super(defaultTransactionTimeoutSeconds, xidFactory,
>> transactionLog);
>> +        }
>> +
>> +        @Override
>> +        public void destroyResource() {
>> +            // try to clean up
>> +            try {
>> +                final Field f =
>> TransactionManagerImpl.class.getDeclaredField("retryScheduler");
>> +                f.setAccessible(true);
>> +                final ExponentialtIntervalRetryScheduler rs =
>> ExponentialtIntervalRetryScheduler.class.cast(f.get(this));
>> +
>> +                final Field t =
>> ExponentialtIntervalRetryScheduler.class.getDeclaredField("timer");
>> +                t.setAccessible(true);
>> +
>> +                final Timer timer = Timer.class.cast(t.get(rs));
>> +                timer.cancel();
>> +            } catch (final Throwable notImportant) {
>> +                // no-op
>> +            }
>> +        }
>> +    }
>> +
>>      public static class GeronimoXAResourceWrapper implements
>> XAResourceWrapper {
>>          public XAResource wrap(final XAResource xaResource, final String
>> name) {
>>              return new WrapperNamedXAResource(xaResource, name);
>>
>>
>> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
>> b/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
>> index 4b83058..ef07bf9 100644
>> ---
>> a/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
>> +++
>> b/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
>> @@ -182,7 +182,10 @@ public class ApplicationComposers {
>>          testClassFinders.put(this, new ClassFinder(ancestors(klass))); //
>> using this temporary since we don't have yet the instance
>>          if (additionalModules != null) {
>>              for (final Object o : additionalModules) {
>> -                testClassFinders.put(o, new
>> ClassFinder(ancestors(o.getClass())));
>> +                final Class<?> aClass = o.getClass();
>> +                if (aClass != klass) {
>> +                    testClassFinders.put(o, new
>> ClassFinder(ancestors(aClass)));
>> +                }
>>              }
>>          }
>>
>> @@ -349,7 +352,11 @@ public class ApplicationComposers {
>>                  annotatedMethods = newAnnotatedMethods;
>>                  map.put(key, annotatedMethods);
>>              } else {
>> -                annotatedMethods.addAll(newAnnotatedMethods);
>> +                for (final Method m : newAnnotatedMethods) {
>> +                    if (!annotatedMethods.contains(m)) {
>> +                        annotatedMethods.add(m);
>> +                    }
>> +                }
>>              }
>>          }
>>          return map;
>>
>>
>> http://git-wip-us.apache.org/repos/asf/tomee/blob/456a16d5/container/openejb-core/src/test/java/org/apache/openejb/resource/activemq/ProperConnectionShutdownTest.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/container/openejb-core/src/test/java/org/apache/openejb/resource/activemq/ProperConnectionShutdownTest.java
>> b/container/openejb-core/src/test/java/org/apache/openejb/resource/activemq/ProperConnectionShutdownTest.java
>> new file mode 100644
>> index 0000000..49d9a27
>> --- /dev/null
>> +++
>> b/container/openejb-core/src/test/java/org/apache/openejb/resource/activemq/ProperConnectionShutdownTest.java
>> @@ -0,0 +1,227 @@
>> +/**
>> + *
>> + * 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.resource.activemq;
>> +
>> +import org.apache.openejb.jee.WebApp;
>> +import org.apache.openejb.junit.DeployApplication;
>> +import org.apache.openejb.testing.ApplicationComposers;
>> +import org.apache.openejb.testing.Classes;
>> +import org.apache.openejb.testing.Configuration;
>> +import org.apache.openejb.testing.Module;
>> +import org.apache.openejb.testng.PropertiesBuilder;
>> +import org.apache.openejb.util.Join;
>> +import org.apache.openejb.util.NetworkUtil;
>> +import org.junit.Ignore;
>> +import org.junit.Test;
>> +import org.junit.runners.model.Statement;
>> +
>> +import javax.annotation.Resource;
>> +import javax.ejb.EJB;
>> +import javax.ejb.Stateless;
>> +import javax.jms.Connection;
>> +import javax.jms.ConnectionFactory;
>> +import javax.jms.DeliveryMode;
>> +import javax.jms.JMSException;
>> +import javax.jms.MessageConsumer;
>> +import javax.jms.MessageProducer;
>> +import javax.jms.Queue;
>> +import javax.jms.Session;
>> +import javax.jms.TextMessage;
>> +import java.util.Locale;
>> +import java.util.Properties;
>> +import java.util.concurrent.atomic.AtomicReference;
>> +
>> +import static org.junit.Assert.assertEquals;
>> +import static org.junit.Assert.assertTrue;
>> +
>> +// inspired from MessagingBeanTest in examples
>> +public class ProperConnectionShutdownTest {
>> +    @Test
>> +    @Ignore("https://issues.apache.org/jira/browse/AMQ-6051")
>> +    public void run() throws Throwable {
>> +        final Thread[] threadsBefore = listThreads();
>> +        final AtomicReference<Thread[]> threadWhile = new
>> AtomicReference<>();
>> +
>> +        // run test
>> +        final Statement testInContainer = new Statement() {
>> +            @Override
>> +            public void evaluate() throws Throwable {
>> +                messages.sendMessage("Hello World!");
>> +                messages.sendMessage("How are you?");
>> +
>> +                threadWhile.set(listThreads());
>> +
>> +                messages.sendMessage("Still spinning?");
>> +
>> +                assertEquals(messages.receiveMessage(), "Hello World!");
>> +                assertEquals(messages.receiveMessage(), "How are you?");
>> +                assertEquals(messages.receiveMessage(), "Still
>> spinning?");
>> +
>> +                /* TODO: activate it when AMQ-6051 is fixed
>> +
>> +                // all worked, now hold a connection
>> +                new Thread(new Runnable() { // not daemon!
>> +                    @Override
>> +                    public void run() {
>> +                        messages.blockConnection(); // oops, I forgot to
>> close it
>> +                    }
>> +                }).start();
>> +                 */
>> +            }
>> +        };
>> +        new DeployApplication(this, testInContainer, new
>> ApplicationComposers(this)).evaluate();
>> +
>> +        Thread.sleep(2250); // AMQ state (started) polling for transport
>> thread is 1s
>> +        while (Join.join("", listThreads()).contains("ActiveMQ Session
>> Task")) { // let few sec to AMQ to leave the holding task
>> +            Thread.sleep(1000);
>> +        }
>> +
>> +        // ensure no connection are leaking
>> +        final Thread[] threadsAfter = listThreads();
>> +
>> +        int countAMQ = 0;
>> +        int countOthers = 0;
>> +        for (final Thread t : threadsAfter) {
>> +            if (!t.isAlive()) {
>> +                continue;
>> +            }
>> +            if (t.getName().contains("AMQ") ||
>> t.getName().toLowerCase(Locale.ENGLISH).contains("activemq")) {
>> +                countAMQ++;
>> +            } else {
>> +                countOthers++;
>> +            }
>> +        }
>> +
>> +        final String debugMessage = Join.join(", ", threadsAfter);
>> +
>> +        assertEquals(debugMessage, 0, countAMQ);
>> +
>> +        // geronimo libs spawn 2 threads we know: PoolIdleReleaseTimer
>> and CurrentTime so we can get initial + 2 threads there
>> +        assertTrue(debugMessage, countOthers <= threadsBefore.length + 2);
>> +    }
>> +
>> +    private Thread[] listThreads() {
>> +        final Thread[] threads = new Thread[Thread.activeCount()];
>> +        final int count = Thread.enumerate(threads);
>> +        if (count < threads.length) {
>> +            final Thread[] copy = new Thread[count];
>> +            System.arraycopy(threads, 0, copy, 0, count);
>> +            return copy;
>> +        }
>> +        return threads;
>> +    }
>> +
>> +    @EJB
>> +    private Messages messages;
>> +
>> +    @Configuration
>> +    public Properties config() {
>> +        return new PropertiesBuilder()
>> +            .p("Default JMS Resource Adapter.BrokerXmlConfig",
>> "broker:(tcp://localhost:" + NetworkUtil.getNextAvailablePort() +
>> ")?useJmx=false")
>> +            .build();
>> +    }
>> +
>> +    @Module
>> +    @Classes(innerClassesAsBean = true)
>> +    public WebApp app() {
>> +        return new WebApp();
>> +    }
>> +
>> +    @Stateless
>> +    public static class Messages {
>> +
>> +        @Resource
>> +        private ConnectionFactory connectionFactory;
>> +
>> +        @Resource
>> +        private Queue chatQueue;
>> +
>> +        public void sendMessage(String text) throws JMSException {
>> +
>> +            Connection connection = null;
>> +            Session session = null;
>> +
>> +            try {
>> +                connection = connectionFactory.createConnection();
>> +                connection.start();
>> +
>> +                // Create a Session
>> +                session = connection.createSession(false,
>> Session.AUTO_ACKNOWLEDGE);
>> +
>> +                // Create a MessageProducer from the Session to the Topic
>> or Queue
>> +                MessageProducer producer =
>> session.createProducer(chatQueue);
>> +                producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
>> +
>> +                // Create a message
>> +                TextMessage message = session.createTextMessage(text);
>> +
>> +                // Tell the producer to send the message
>> +                producer.send(message);
>> +            } finally {
>> +                // Clean up
>> +                if (session != null) {
>> +                    session.close();
>> +                }
>> +                if (connection != null) {
>> +                    connection.close();
>> +                }
>> +            }
>> +        }
>> +
>> +        public String receiveMessage() throws JMSException {
>> +
>> +            Connection connection = null;
>> +            Session session = null;
>> +            MessageConsumer consumer = null;
>> +            try {
>> +                connection = connectionFactory.createConnection();
>> +                connection.start();
>> +
>> +                // Create a Session
>> +                session = connection.createSession(false,
>> Session.AUTO_ACKNOWLEDGE);
>> +
>> +                // Create a MessageConsumer from the Session to the Topic
>> or Queue
>> +                consumer = session.createConsumer(chatQueue);
>> +
>> +                // Wait for a message
>> +                TextMessage message = (TextMessage)
>> consumer.receive(1000);
>> +
>> +                return message.getText();
>> +            } finally {
>> +                if (consumer != null) {
>> +                    consumer.close();
>> +                }
>> +                if (session != null) {
>> +                    session.close();
>> +                }
>> +                if (connection != null) {
>> +                    connection.close();
>> +                }
>> +            }
>> +
>> +        }
>> +
>> +        public void blockConnection() {
>> +            try {
>> +                connectionFactory.createConnection();
>> +            } catch (final JMSException e) {
>> +                throw new IllegalStateException(e);
>> +            }
>> +        }
>> +    }
>> +}
>>
>>