You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rm...@apache.org on 2014/10/19 13:39:27 UTC
git commit: trying to use app loader and not API loader to define
proxies to avoid to leak as much as possible + Closeables helper to close
what needs in arquillian openejb embedded
Repository: tomee
Updated Branches:
refs/heads/develop 2a38e3346 -> 0937a91bd
trying to use app loader and not API loader to define proxies to avoid to leak as much as possible + Closeables helper to close what needs in arquillian openejb embedded
Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/0937a91b
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/0937a91b
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/0937a91b
Branch: refs/heads/develop
Commit: 0937a91bdc483fa5c2c0e874a3c68f5cb3dcde1e
Parents: 2a38e33
Author: Romain Manni-Bucau <rm...@apache.org>
Authored: Sun Oct 19 13:39:08 2014 +0200
Committer: Romain Manni-Bucau <rm...@apache.org>
Committed: Sun Oct 19 13:39:08 2014 +0200
----------------------------------------------------------------------
.../openejb/arquillian/openejb/Closeables.java | 38 +++++++++++++
.../openejb/OpenEJBArchiveProcessor.java | 38 ++++++++-----
.../openejb/OpenEJBDeployableContainer.java | 39 +++++++++----
.../arquillian/openejb/SWClassLoader.java | 5 +-
.../apache/openejb/dyni/DynamicSubclass.java | 2 +-
.../util/proxy/LocalBeanProxyFactory.java | 7 ++-
.../openejb/tck/cdi/embedded/GCListener.java | 59 ++++++++++++++++++++
tck/cdi-embedded/src/test/resources/passing.xml | 2 +
8 files changed, 159 insertions(+), 31 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tomee/blob/0937a91b/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/Closeables.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/Closeables.java b/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/Closeables.java
new file mode 100644
index 0000000..5d093da
--- /dev/null
+++ b/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/Closeables.java
@@ -0,0 +1,38 @@
+/*
+ * 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.arquillian.openejb;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.LinkedList;
+
+public class Closeables implements Closeable {
+ private final Collection<Closeable> closeables = new LinkedList<>();
+
+ public synchronized void add(final Closeable closeable) {
+ closeables.add(closeable);
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ for (final Closeable c : closeables) {
+ c.close();
+ }
+ closeables.clear();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tomee/blob/0937a91b/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/OpenEJBArchiveProcessor.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/OpenEJBArchiveProcessor.java b/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/OpenEJBArchiveProcessor.java
index 674a0dd..7982af7 100644
--- a/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/OpenEJBArchiveProcessor.java
+++ b/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/OpenEJBArchiveProcessor.java
@@ -91,7 +91,7 @@ public class OpenEJBArchiveProcessor {
private static final String ENV_ENTRIES_PROPERTIES = "env-entries.properties";
public static final String WEB_INF_CLASSES = "/WEB-INF/classes/";
- public static AppModule createModule(final Archive<?> archive, final TestClass testClass) {
+ public static AppModule createModule(final Archive<?> archive, final TestClass testClass, final Closeables closeables) {
final Class<?> javaClass;
if (testClass != null) {
javaClass = testClass.getJavaClass();
@@ -143,7 +143,7 @@ public class OpenEJBArchiveProcessor {
}
}
} else {
- if (isEar) { // mainly for CDi TCKs
+ if (isEar) { // mainly for CDI TCKs
earMap = new HashMap<>();
final Map<ArchivePath, Node> jars = archive.getContent(new IncludeRegExpPaths("/.*\\.jar"));
final List<org.apache.xbean.finder.archive.Archive> archives = new ArrayList<>(jars.size());
@@ -183,13 +183,19 @@ public class OpenEJBArchiveProcessor {
final URL[] urls = additionalPaths.toArray(new URL[additionalPaths.size()]);
- final ClassLoader loader;
+ final SWClassLoader loader;
if (!WEB_INF.equals(prefix)) {
- loader = new SWClassLoader("", new URLClassLoader(urls, parent), archive);
+ final URLClassLoader swParent = new URLClassLoader(urls, parent);
+ closeables.add(swParent);
+ loader = new SWClassLoader("", swParent, archive);
} else {
- loader = new SWClassLoader(WEB_INF_CLASSES, new URLClassLoaderFirst(urls, parent), archive);
+ final URLClassLoaderFirst swParent = new URLClassLoaderFirst(urls, parent);
+ closeables.add(swParent);
+ loader = new SWClassLoader(WEB_INF_CLASSES, swParent, archive);
}
+ closeables.add(loader);
final URLClassLoader tempClassLoader = ClassLoaderUtil.createTempClassLoader(loader);
+ closeables.add(tempClassLoader);
final AppModule appModule = new AppModule(loader, archive.getName());
if (WEB_INF.equals(prefix)) {
@@ -199,8 +205,8 @@ public class OpenEJBArchiveProcessor {
final WebModule webModule = new WebModule(new WebApp(), contextRoot(archive.getName()), loader, "", appModule.getModuleId());
webModule.setUrls(additionalPaths);
appModule.getWebModules().add(webModule);
- } else if (isEar) { // mainly for CDi TCKs
- final FinderFactory.OpenEJBAnnotationFinder earLibFinder = new FinderFactory.OpenEJBAnnotationFinder(new SimpleWebappAggregatedArchive(earArchive, earMap));
+ } else if (isEar) { // mainly for CDI TCKs
+ final FinderFactory.OpenEJBAnnotationFinder earLibFinder = new FinderFactory.OpenEJBAnnotationFinder(new SimpleWebappAggregatedArchive(tempClassLoader, earArchive, earMap));
appModule.setEarLibFinder(earLibFinder);
final EjbModule earCdiModule = new EjbModule(appModule.getClassLoader(), DeploymentLoader.EAR_SCOPED_CDI_BEANS + appModule.getModuleId(), new EjbJar(), new OpenejbJar());
@@ -218,9 +224,11 @@ public class OpenEJBArchiveProcessor {
final Map<ArchivePath, Node> libs = archive.getContent(new IncludeRegExpPaths("/WEB-INF/lib/.*\\.jar"));
*/
- final Map<String, Object> altDD = new HashMap<String, Object>();
+ final Map<String, Object> altDD = new HashMap<>();
final Node beansXml = findBeansXml(webArchive, new ArrayList<AssetSource>(), WEB_INF, altDD);
final SWClassLoader webLoader = new SWClassLoader(WEB_INF_CLASSES, parent, webArchive);
+ closeables.add(webLoader);
+
final FinderFactory.OpenEJBAnnotationFinder finder = new FinderFactory.OpenEJBAnnotationFinder(
finderArchive(beansXml, webArchive, webLoader, Collections.<URL>emptyList()));
@@ -442,11 +450,11 @@ public class OpenEJBArchiveProcessor {
}
}
- final Map<URL, List<String>> classesByUrl = new HashMap<URL, List<String>>();
+ final Map<URL, List<String>> classesByUrl = new HashMap<>();
- final List<org.apache.xbean.finder.archive.Archive> archives = new ArrayList<org.apache.xbean.finder.archive.Archive>();
+ final List<org.apache.xbean.finder.archive.Archive> archives = new ArrayList<>();
for (final URL url : DeploymentLoader.filterWebappUrls(additionalPaths.toArray(new URL[additionalPaths.size()]), null)) {
- final List<String> currentClasses = new ArrayList<String>();
+ final List<String> currentClasses = new ArrayList<>();
final org.apache.xbean.finder.archive.Archive newArchive = new FilteredArchive(new JarArchive(cl, url), new WebappAggregatedArchive.ScanXmlSaverFilter(false, null, currentClasses));
classesByUrl.put(url, currentClasses);
archives.add(newArchive);
@@ -454,7 +462,7 @@ public class OpenEJBArchiveProcessor {
archives.add(new ClassesArchive(classes));
if (beansXml != null) {
- final List<String> mainClasses = new ArrayList<String>();
+ final List<String> mainClasses = new ArrayList<>();
for (final Class<?> clazz : classes) {
mainClasses.add(clazz.getName());
}
@@ -467,7 +475,7 @@ public class OpenEJBArchiveProcessor {
}
}
- return new SimpleWebappAggregatedArchive(new CompositeArchive(archives), classesByUrl);
+ return new SimpleWebappAggregatedArchive(cl, new CompositeArchive(archives), classesByUrl);
}
private static boolean isExcluded(final String archiveName) {
@@ -503,8 +511,8 @@ public class OpenEJBArchiveProcessor {
private final CompositeArchive delegate;
private final Map<URL, List<String>> classesMap;
- public SimpleWebappAggregatedArchive(final CompositeArchive archive, final Map<URL, List<String>> map) {
- super(Thread.currentThread().getContextClassLoader(), new HashMap<String, Object>(), new ArrayList<URL>());
+ public SimpleWebappAggregatedArchive(final ClassLoader cl, final CompositeArchive archive, final Map<URL, List<String>> map) {
+ super(cl, new HashMap<String, Object>(), new ArrayList<URL>());
delegate = archive;
classesMap = map;
http://git-wip-us.apache.org/repos/asf/tomee/blob/0937a91b/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/OpenEJBDeployableContainer.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/OpenEJBDeployableContainer.java b/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/OpenEJBDeployableContainer.java
index 6665024..00d1125 100644
--- a/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/OpenEJBDeployableContainer.java
+++ b/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/OpenEJBDeployableContainer.java
@@ -113,10 +113,17 @@ public class OpenEJBDeployableContainer implements DeployableContainer<OpenEJBCo
private InstanceProducer<HttpSession> sessionProducer;
@Inject
+ @DeploymentScoped
+ private InstanceProducer<Closeables> closeablesProducer;
+
+ @Inject
@SuiteScoped
private InstanceProducer<ClassLoader> classLoader;
@Inject
+ private Instance<Closeables> closeables;
+
+ @Inject
private Instance<ServletContext> servletContext;
@Inject
@@ -178,9 +185,11 @@ public class OpenEJBDeployableContainer implements DeployableContainer<OpenEJBCo
contextProducer.set(initialContext);
containerArchives = ArquillianUtil.toDeploy(properties);
+ final Closeables globalScopeCloseables = new Closeables();
+ SystemInstance.get().setComponent(Closeables.class, globalScopeCloseables);
for (final Archive<?> archive : containerArchives) {
try {
- quickDeploy(archive, testClass.get());
+ quickDeploy(archive, testClass.get(), globalScopeCloseables);
} catch (final DeploymentException e) {
Logger.getLogger(OpenEJBDeployableContainer.class.getName()).log(Level.SEVERE, e.getMessage(), e);
}
@@ -190,13 +199,16 @@ public class OpenEJBDeployableContainer implements DeployableContainer<OpenEJBCo
@Override
public ProtocolMetaData deploy(final Archive<?> archive) throws DeploymentException {
try {
- final DeploymentInfo info = quickDeploy(archive, testClass.get());
+ final Closeables cl = new Closeables();
+ closeablesProducer.set(cl);
+ final DeploymentInfo info = quickDeploy(archive, testClass.get(), cl);
servletContextProducer.set(info.appServletContext);
sessionProducer.set(info.appSession);
appInfoProducer.set(info.appInfo);
appContextProducer.set(info.appCtx);
- classLoader.set(info.appCtx.getClassLoader());
+ final ClassLoader loader = info.appCtx.getWebContexts().isEmpty() ? info.appCtx.getClassLoader() : info.appCtx.getWebContexts().iterator().next().getClassLoader();
+ classLoader.set(loader == null ? info.appCtx.getClassLoader() : loader);
} catch (final Exception e) {
throw new DeploymentException("can't deploy " + archive.getName(), e);
}
@@ -211,9 +223,9 @@ public class OpenEJBDeployableContainer implements DeployableContainer<OpenEJBCo
return new ProtocolMetaData();
}
- private DeploymentInfo quickDeploy(final Archive<?> archive, final TestClass testClass) throws DeploymentException {
+ private DeploymentInfo quickDeploy(final Archive<?> archive, final TestClass testClass, final Closeables cls) throws DeploymentException {
try {
- final AppModule module = OpenEJBArchiveProcessor.createModule(archive, testClass);
+ final AppModule module = OpenEJBArchiveProcessor.createModule(archive, testClass, cls);
final AppInfo appInfo = configurationFactory.configureApplication(module);
final AppContext appCtx = assembler.createApplication(appInfo, module.getClassLoader());
@@ -230,6 +242,15 @@ public class OpenEJBDeployableContainer implements DeployableContainer<OpenEJBCo
@Override
public void undeploy(final Archive<?> archive) throws DeploymentException {
+ final Closeables cl = closeables.get();
+ if (cl != null) {
+ try {
+ cl.close();
+ } catch (final IOException e) {
+ // no-op
+ }
+ }
+
// reset classloader for next text
// otherwise if it was closed something can fail
classLoader.set(OpenEJBDeployableContainer.class.getClassLoader());
@@ -238,11 +259,6 @@ public class OpenEJBDeployableContainer implements DeployableContainer<OpenEJBCo
return;
}
- final ClassLoader cl = appContext.get().getClassLoader();
- if (SWClassLoader.class.isInstance(cl)) {
- SWClassLoader.class.cast(cl).close();
- }
-
try {
assembler.destroyApplication(info.get().path);
stopContexts(appContext.get().getWebBeansContext().getContextsService(), servletContext.get(), session.get());
@@ -259,8 +275,11 @@ public class OpenEJBDeployableContainer implements DeployableContainer<OpenEJBCo
if (initialContext != null) {
initialContext.close();
}
+ SystemInstance.get().getComponent(Closeables.class).close();
} catch (final NamingException e) {
throw new LifecycleException("can't close the OpenEJB container", e);
+ } catch (final IOException e) {
+ // no-op: close() of classloaders, not a big deal at this moment
} finally {
OpenEJB.destroy();
}
http://git-wip-us.apache.org/repos/asf/tomee/blob/0937a91b/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/SWClassLoader.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/SWClassLoader.java b/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/SWClassLoader.java
index 168ce79..4f35da8 100644
--- a/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/SWClassLoader.java
+++ b/arquillian/arquillian-openejb-embedded-5/src/main/java/org/apache/openejb/arquillian/openejb/SWClassLoader.java
@@ -44,7 +44,7 @@ import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
-public class SWClassLoader extends ClassLoader {
+public class SWClassLoader extends ClassLoader implements Closeable {
static {
try {
final Field handler = URL.class.getDeclaredField("handlers");
@@ -197,7 +197,8 @@ public class SWClassLoader extends ClassLoader {
}
}
- public void close() {
+ @Override
+ public void close() throws IOException {
ArchiveStreamHandler.reset(archive.getName());
for (final Closeable cl : closeables) {
try {
http://git-wip-us.apache.org/repos/asf/tomee/blob/0937a91b/container/openejb-core/src/main/java/org/apache/openejb/dyni/DynamicSubclass.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/dyni/DynamicSubclass.java b/container/openejb-core/src/main/java/org/apache/openejb/dyni/DynamicSubclass.java
index d231290..64b4a0a 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/dyni/DynamicSubclass.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/dyni/DynamicSubclass.java
@@ -79,7 +79,7 @@ public class DynamicSubclass implements Opcodes {
// no-op
}
- return LocalBeanProxyFactory.Unsafe.defineClass(abstractClass, proxyName, generateBytes(abstractClass));
+ return LocalBeanProxyFactory.Unsafe.defineClass(cl, abstractClass, proxyName, generateBytes(abstractClass));
} catch (final Exception e) {
throw new InternalError(DynamicSubclass.class.getSimpleName() + ".createSubclass: " + Debug.printStackTrace(e));
http://git-wip-us.apache.org/repos/asf/tomee/blob/0937a91b/container/openejb-core/src/main/java/org/apache/openejb/util/proxy/LocalBeanProxyFactory.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/util/proxy/LocalBeanProxyFactory.java b/container/openejb-core/src/main/java/org/apache/openejb/util/proxy/LocalBeanProxyFactory.java
index 37b63f4..cd9cb7e 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/util/proxy/LocalBeanProxyFactory.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/util/proxy/LocalBeanProxyFactory.java
@@ -134,7 +134,7 @@ public class LocalBeanProxyFactory implements Opcodes {
}
final byte[] proxyBytes = generateProxy(classToProxy, classFileName, interfaces);
- return Unsafe.defineClass(classToProxy, proxyName, proxyBytes);
+ return Unsafe.defineClass(cl, classToProxy, proxyName, proxyBytes);
} catch (final Exception e) {
throw new InternalError("LocalBeanProxyFactory.createProxy: " + Debug.printStackTrace(e));
@@ -814,8 +814,9 @@ public class LocalBeanProxyFactory implements Opcodes {
}
}
- public static Class defineClass(final Class<?> clsToProxy, final String proxyName, final byte[] proxyBytes) throws IllegalAccessException, InvocationTargetException {
- return (Class<?>) defineClass.invoke(unsafe, proxyName, proxyBytes, 0, proxyBytes.length, clsToProxy.getClassLoader(), clsToProxy.getProtectionDomain());
+ // it is super important to pass a classloader as first parameter otherwise if API class is in a "permanent" classloader then it will leak
+ public static Class defineClass(final ClassLoader loader, final Class<?> clsToProxy, final String proxyName, final byte[] proxyBytes) throws IllegalAccessException, InvocationTargetException {
+ return (Class<?>) defineClass.invoke(unsafe, proxyName, proxyBytes, 0, proxyBytes.length, loader, clsToProxy.getProtectionDomain());
}
}
http://git-wip-us.apache.org/repos/asf/tomee/blob/0937a91b/tck/cdi-embedded/src/test/java/org/apache/openejb/tck/cdi/embedded/GCListener.java
----------------------------------------------------------------------
diff --git a/tck/cdi-embedded/src/test/java/org/apache/openejb/tck/cdi/embedded/GCListener.java b/tck/cdi-embedded/src/test/java/org/apache/openejb/tck/cdi/embedded/GCListener.java
new file mode 100644
index 0000000..72a5680
--- /dev/null
+++ b/tck/cdi-embedded/src/test/java/org/apache/openejb/tck/cdi/embedded/GCListener.java
@@ -0,0 +1,59 @@
+/*
+ * 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.tck.cdi.embedded;
+
+import org.testng.IInvokedMethod;
+import org.testng.IInvokedMethodListener2;
+import org.testng.ITestContext;
+import org.testng.ITestResult;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+
+public class GCListener implements IInvokedMethodListener2 {
+ private final MemoryMXBean memory;
+
+ public GCListener() {
+ memory = ManagementFactory.getMemoryMXBean();
+ }
+
+ @Override
+ public void beforeInvocation(final IInvokedMethod iInvokedMethod, final ITestResult iTestResult, final ITestContext iTestContext) {
+ dump("b");
+ }
+
+ @Override
+ public void afterInvocation(final IInvokedMethod iInvokedMethod, final ITestResult iTestResult, final ITestContext iTestContext) {
+ dump("a");
+ }
+
+ private void dump(final String prefix) {
+ System.out.println(prefix + ">>> heap : " + memory.getHeapMemoryUsage().toString());
+ System.out.println(prefix + ">>> non heap : " + memory.getNonHeapMemoryUsage().toString());
+ System.out.println(prefix + ">>> pending instances: " + memory.getObjectPendingFinalizationCount());
+ }
+
+ @Override
+ public void beforeInvocation(final IInvokedMethod iInvokedMethod, final ITestResult iTestResult) {
+ // no-op
+ }
+
+ @Override
+ public void afterInvocation(final IInvokedMethod iInvokedMethod, final ITestResult iTestResult) {
+ // no-op
+ }
+}
http://git-wip-us.apache.org/repos/asf/tomee/blob/0937a91b/tck/cdi-embedded/src/test/resources/passing.xml
----------------------------------------------------------------------
diff --git a/tck/cdi-embedded/src/test/resources/passing.xml b/tck/cdi-embedded/src/test/resources/passing.xml
index edc63d2..00eb112 100644
--- a/tck/cdi-embedded/src/test/resources/passing.xml
+++ b/tck/cdi-embedded/src/test/resources/passing.xml
@@ -35,6 +35,8 @@
<!-- OWB one ATM, remove exclude groups to be openejb ;) -->
<suite name="JSR-346-TCK" verbose="2" configfailurepolicy="continue" >
<listeners>
+ <!-- debug -->
+ <listener class-name="org.apache.openejb.tck.cdi.embedded.GCListener"/>
<!-- Required - avoid randomly mixed test method execution -->
<listener class-name="org.jboss.cdi.tck.impl.testng.SingleTestClassMethodInterceptor"/>
<!-- Optional - intended for debug purpose only -->