buildbot success in on tomee-trunk-ubuntu
The Buildbot has detected a restored build on builder tomee-trunk-ubuntu while building tomee. Full details are available at: https://ci.apache.org/builders/tomee-trunk-ubuntu/builds/742 Buildbot URL: https://ci.apache.org/ Buildslave for this Build: bb_qnode5_ubuntu Build Reason: The SingleBranchScheduler scheduler named 'on-tomee-trunk-ubuntu-commit' triggered this build Build Source Stamp: [branch master] 2be715d0d698e234f9886b450fb3643c0fb89f16 Blamelist: rmannibucauBuild succeeded! Sincerely, -The Buildbot
buildbot failure in on tomee-trunk-ubuntu-jvm8
The Buildbot has detected a new failure on builder tomee-trunk-ubuntu-jvm8 while building tomee. Full details are available at: https://ci.apache.org/builders/tomee-trunk-ubuntu-jvm8/builds/647 Buildbot URL: https://ci.apache.org/ Buildslave for this Build: bb_qnode5_ubuntu Build Reason: The SingleBranchScheduler scheduler named 'on-tomee-trunk-ubuntu-jvm8-commit' triggered this build Build Source Stamp: [branch master] 2be715d0d698e234f9886b450fb3643c0fb89f16 Blamelist: rmannibucauBUILD FAILED: failed test Sincerely, -The Buildbot
[jira] [Resolved] (TOMEE-2045) TomEE tries to register a provider as a resource
[ https://issues.apache.org/jira/browse/TOMEE-2045?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Romain Manni-Bucau resolved TOMEE-2045. --- Resolution: Fixed Assignee: Romain Manni-Bucau Fix Version/s: 7.0.4 > TomEE tries to register a provider as a resource > > > Key: TOMEE-2045 > URL: https://issues.apache.org/jira/browse/TOMEE-2045 > Project: TomEE > Issue Type: Bug > Components: TomEE Core Server >Affects Versions: 7.0.3 >Reporter: TURPIN Michel >Assignee: Romain Manni-Bucau > Fix For: 7.0.4 > > > When an Application subclass declares a class ( through the > Application#getClasses() method ) which implements one or more provider > interfaces but is not annotated with the Provider annotation, the provider is > not registred as a provider. > From chapter 4 of the Jax-RS spec : > ??A provider is a class that implements one or more JAX-RS interfaces > introduced in this specification and that *may* be annotated with @Provider > for automatic discovery.?? -- This message was sent by Atlassian JIRA (v6.3.15#6346)
tomee git commit: TOMEE-2045 ensure @Provider is not mandatory when explicitly registered
Repository: tomee Updated Branches: refs/heads/master 022d8fa45 -> 2be715d0d TOMEE-2045 ensure @Provider is not mandatory when explicitly registered Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/2be715d0 Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/2be715d0 Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/2be715d0 Branch: refs/heads/master Commit: 2be715d0d698e234f9886b450fb3643c0fb89f16 Parents: 022d8fa Author: rmannibucauAuthored: Thu Jun 1 23:21:48 2017 +0200 Committer: rmannibucau Committed: Thu Jun 1 23:21:48 2017 +0200 -- .../cxf/rs/ProviderWithoutAnnotationTest.java | 103 +++ .../apache/openejb/server/rest/RESTService.java | 21 +++- 2 files changed, 123 insertions(+), 1 deletion(-) -- http://git-wip-us.apache.org/repos/asf/tomee/blob/2be715d0/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/ProviderWithoutAnnotationTest.java -- diff --git a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/ProviderWithoutAnnotationTest.java b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/ProviderWithoutAnnotationTest.java new file mode 100644 index 000..d1e6c03 --- /dev/null +++ b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/ProviderWithoutAnnotationTest.java @@ -0,0 +1,103 @@ +/* + * 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.server.cxf.rs; + +import org.apache.openejb.junit.ApplicationComposer; +import org.apache.openejb.testing.Classes; +import org.apache.openejb.testing.EnableServices; +import org.apache.openejb.testing.RandomPort; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Set; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; + +@EnableServices("jax-rs") +@RunWith(ApplicationComposer.class) +@Classes(innerClassesAsBean = true) +public class ProviderWithoutAnnotationTest { +@RandomPort("http") +private URL base; + +@Test +public void run() { +final Client client = ClientBuilder.newClient(); +try { +assertEquals("foo", client.target(base.toExternalForm() + "openejb/api/ProviderWithoutAnnotationTest") +.request("foo/bar") +.get(String.class)); +} finally { +client.close(); +} +} + +@ApplicationPath("api") +public static class App extends Application { +@Override +public Set getClasses() { +return new HashSet<>(asList(Endpoint.class, FooWriter.class)); +} +} + +@Path("ProviderWithoutAnnotationTest") +public static class Endpoint { +@GET +@Produces("foo/bar") +public Endpoint get() { +return this; +} +} + +@Produces("foo/*") +public static class FooWriter implements MessageBodyWriter { +@Override +public boolean isWriteable(final Class type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) { +return type == Endpoint.class && mediaType.getType().equals("foo"); +} + +@Override +public long getSize(final Endpoint s, final Class type, final Type genericType, final
[jira] [Created] (TOMEE-2045) TomEE tries to register a provider as a resource
TURPIN Michel created TOMEE-2045: Summary: TomEE tries to register a provider as a resource Key: TOMEE-2045 URL: https://issues.apache.org/jira/browse/TOMEE-2045 Project: TomEE Issue Type: Bug Components: TomEE Core Server Affects Versions: 7.0.3 Reporter: TURPIN Michel When an Application subclass declares a class ( through the Application#getClasses() method ) which implements one or more provider interfaces but is not annotated with the Provider annotation, the provider is not registred as a provider. >From chapter 4 of the Jax-RS spec : ??A provider is a class that implements one or more JAX-RS interfaces introduced in this specification and that *may* be annotated with @Provider for automatic discovery.?? -- This message was sent by Atlassian JIRA (v6.3.15#6346)
buildbot failure in on tomee-trunk-ubuntu
The Buildbot has detected a new failure on builder tomee-trunk-ubuntu while building tomee. Full details are available at: https://ci.apache.org/builders/tomee-trunk-ubuntu/builds/741 Buildbot URL: https://ci.apache.org/ Buildslave for this Build: bb_qnode5_ubuntu Build Reason: The SingleBranchScheduler scheduler named 'on-tomee-trunk-ubuntu-commit' triggered this build Build Source Stamp: [branch master] 022d8fa45ae849db5832777ebc3857969db30cba Blamelist: rmannibucauBUILD FAILED: failed test Sincerely, -The Buildbot
buildbot success in on tomee-trunk-ubuntu-jvm8
The Buildbot has detected a restored build on builder tomee-trunk-ubuntu-jvm8 while building tomee. Full details are available at: https://ci.apache.org/builders/tomee-trunk-ubuntu-jvm8/builds/646 Buildbot URL: https://ci.apache.org/ Buildslave for this Build: bb_qnode5_ubuntu Build Reason: The SingleBranchScheduler scheduler named 'on-tomee-trunk-ubuntu-jvm8-commit' triggered this build Build Source Stamp: [branch master] 022d8fa45ae849db5832777ebc3857969db30cba Blamelist: rmannibucauBuild succeeded! Sincerely, -The Buildbot
[jira] [Commented] (TOMEE-2044) threadPool-queue (in ServicePool) from ejbd-Service is never processed
[ https://issues.apache.org/jira/browse/TOMEE-2044?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16033263#comment-16033263 ] Romain Manni-Bucau commented on TOMEE-2044: --- Hi Lars, very good analyzis! master has some refactoring around it, is it possible to give it a try? > threadPool-queue (in ServicePool) from ejbd-Service is never processed > --- > > Key: TOMEE-2044 > URL: https://issues.apache.org/jira/browse/TOMEE-2044 > Project: TomEE > Issue Type: Bug > Components: TomEE Core Server >Affects Versions: 1.7.4 > Environment: FreeBSD 10.3-STABLE amd64 > openjdk8-8.131.11 >Reporter: Lars Herschke > Fix For: 7.0.4 > > > If you have many requests to your ejbd-service the queue from the threadPool > in ServicePool.java is filled. This queue is never processed depending on > your server config. If you have only ejbd-service enabled and the services > admin, ejbds and httpejbd are disabled all is fine. If you have two or more > of these services enabled the issue could occur. The reason is the following. > KeepAliveServer.java has the following line to get the queue. > final ServicePool incoming = > SystemInstance.get().getComponent(ServicePool.class); > SystemInstance.java hold components in a HahMap with the class type as key. > On server-startup the above named services are initalized in > ServiceManager.manage(...). This method instances new ServicePool for this > services. Each ServicePool-instance calls in his constructor > SystemInstance.get().setComponent(ServicePool.class, this);. > Every other call of setComponent replace the old entry in the components > HashMap. So KeepAliveServer gets always the queue of the last initalized > service. > Workaround: > Use only one of the four above named services > or > set threadsCore for your services at least as high, that the queue is never > used. -- This message was sent by Atlassian JIRA (v6.3.15#6346)
[jira] [Updated] (TOMEE-2044) threadPool-queue (in ServicePool) from ejbd-Service is never processed
[ https://issues.apache.org/jira/browse/TOMEE-2044?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Romain Manni-Bucau updated TOMEE-2044: -- Fix Version/s: 7.0.4 > threadPool-queue (in ServicePool) from ejbd-Service is never processed > --- > > Key: TOMEE-2044 > URL: https://issues.apache.org/jira/browse/TOMEE-2044 > Project: TomEE > Issue Type: Bug > Components: TomEE Core Server >Affects Versions: 1.7.4 > Environment: FreeBSD 10.3-STABLE amd64 > openjdk8-8.131.11 >Reporter: Lars Herschke > Fix For: 7.0.4 > > > If you have many requests to your ejbd-service the queue from the threadPool > in ServicePool.java is filled. This queue is never processed depending on > your server config. If you have only ejbd-service enabled and the services > admin, ejbds and httpejbd are disabled all is fine. If you have two or more > of these services enabled the issue could occur. The reason is the following. > KeepAliveServer.java has the following line to get the queue. > final ServicePool incoming = > SystemInstance.get().getComponent(ServicePool.class); > SystemInstance.java hold components in a HahMap with the class type as key. > On server-startup the above named services are initalized in > ServiceManager.manage(...). This method instances new ServicePool for this > services. Each ServicePool-instance calls in his constructor > SystemInstance.get().setComponent(ServicePool.class, this);. > Every other call of setComponent replace the old entry in the components > HashMap. So KeepAliveServer gets always the queue of the last initalized > service. > Workaround: > Use only one of the four above named services > or > set threadsCore for your services at least as high, that the queue is never > used. -- This message was sent by Atlassian JIRA (v6.3.15#6346)
tomee git commit: TOMEE-2044 avoid singleton when we dont need it
Repository: tomee Updated Branches: refs/heads/master 85635cd8c -> 022d8fa45 TOMEE-2044 avoid singleton when we dont need it Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/022d8fa4 Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/022d8fa4 Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/022d8fa4 Branch: refs/heads/master Commit: 022d8fa45ae849db5832777ebc3857969db30cba Parents: 85635cd Author: rmannibucauAuthored: Thu Jun 1 18:34:04 2017 +0200 Committer: rmannibucau Committed: Thu Jun 1 18:34:04 2017 +0200 -- .../openejb/server/ejbd/KeepAliveServer.java| 4 +-- .../openejb/server/ServerServiceFilter.java | 7 - .../openejb/server/ServiceAccessController.java | 2 +- .../apache/openejb/server/ServiceDaemon.java| 13 ++--- .../org/apache/openejb/server/ServicePool.java | 16 ++- .../org/apache/openejb/server/Unwrappable.java | 21 ++ .../openejb/server/UnwrappbleServerService.java | 29 7 files changed, 83 insertions(+), 9 deletions(-) -- http://git-wip-us.apache.org/repos/asf/tomee/blob/022d8fa4/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/KeepAliveServer.java -- diff --git a/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/KeepAliveServer.java b/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/KeepAliveServer.java index c25b988..d41d36f 100644 --- a/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/KeepAliveServer.java +++ b/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/KeepAliveServer.java @@ -18,10 +18,10 @@ package org.apache.openejb.server.ejbd; import org.apache.openejb.client.FlushableGZIPOutputStream; import org.apache.openejb.client.KeepAliveStyle; -import org.apache.openejb.loader.SystemInstance; import org.apache.openejb.server.ServerService; import org.apache.openejb.server.ServiceException; import org.apache.openejb.server.ServicePool; +import org.apache.openejb.server.Unwrappable; import org.apache.openejb.server.context.RequestInfos; import org.apache.openejb.util.LogCategory; import org.apache.openejb.util.Logger; @@ -161,7 +161,7 @@ public class KeepAliveServer implements ServerService { private BlockingQueue getQueue() { if (this.threadQueue == null) { // this can be null if timer fires before service is fully initialized -final ServicePool incoming = SystemInstance.get().getComponent(ServicePool.class); +final ServicePool incoming = Unwrappable.class.isInstance(service) ? Unwrappable.class.cast(service).unwrap(ServicePool.class) : null; if (incoming == null) { return null; } http://git-wip-us.apache.org/repos/asf/tomee/blob/022d8fa4/server/openejb-server/src/main/java/org/apache/openejb/server/ServerServiceFilter.java -- diff --git a/server/openejb-server/src/main/java/org/apache/openejb/server/ServerServiceFilter.java b/server/openejb-server/src/main/java/org/apache/openejb/server/ServerServiceFilter.java index 66d74f9..0835696 100644 --- a/server/openejb-server/src/main/java/org/apache/openejb/server/ServerServiceFilter.java +++ b/server/openejb-server/src/main/java/org/apache/openejb/server/ServerServiceFilter.java @@ -29,7 +29,7 @@ import java.util.Properties; * * @version $Rev$ $Date$ */ -public class ServerServiceFilter implements ServerService { +public class ServerServiceFilter extends UnwrappbleServerService { @Managed private final ServerService service; @@ -77,4 +77,9 @@ public class ServerServiceFilter implements ServerService { public void init(final Properties props) throws Exception { service.init(props); } + +@Override +protected Object getDelegate() { +return service; +} } http://git-wip-us.apache.org/repos/asf/tomee/blob/022d8fa4/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceAccessController.java -- diff --git a/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceAccessController.java b/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceAccessController.java index 037ddce..da6e0d7 100644 --- a/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceAccessController.java +++ b/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceAccessController.java @@ -38,7 +38,7 @@ import java.util.Properties; import java.util.StringTokenizer; @Managed -public class ServiceAccessController
[jira] [Created] (TOMEE-2044) threadPool-queue (in ServicePool) from ejbd-Service is never processed
Lars Herschke created TOMEE-2044: Summary: threadPool-queue (in ServicePool) from ejbd-Service is never processed Key: TOMEE-2044 URL: https://issues.apache.org/jira/browse/TOMEE-2044 Project: TomEE Issue Type: Bug Components: TomEE Core Server Affects Versions: 1.7.4 Environment: FreeBSD 10.3-STABLE amd64 openjdk8-8.131.11 Reporter: Lars Herschke If you have many requests to your ejbd-service the queue from the threadPool in ServicePool.java is filled. This queue is never processed depending on your server config. If you have only ejbd-service enabled and the services admin, ejbds and httpejbd are disabled all is fine. If you have two or more of these services enabled the issue could occur. The reason is the following. KeepAliveServer.java has the following line to get the queue. final ServicePool incoming = SystemInstance.get().getComponent(ServicePool.class); SystemInstance.java hold components in a HahMap with the class type as key. On server-startup the above named services are initalized in ServiceManager.manage(...). This method instances new ServicePool for this services. Each ServicePool-instance calls in his constructor SystemInstance.get().setComponent(ServicePool.class, this);. Every other call of setComponent replace the old entry in the components HashMap. So KeepAliveServer gets always the queue of the last initalized service. Workaround: Use only one of the four above named services or set threadsCore for your services at least as high, that the queue is never used. -- This message was sent by Atlassian JIRA (v6.3.15#6346)
buildbot failure in on tomee-trunk-ubuntu
The Buildbot has detected a new failure on builder tomee-trunk-ubuntu while building tomee. Full details are available at: https://ci.apache.org/builders/tomee-trunk-ubuntu/builds/738 Buildbot URL: https://ci.apache.org/ Buildslave for this Build: bb_qnode5_ubuntu Build Reason: The SingleBranchScheduler scheduler named 'on-tomee-trunk-ubuntu-commit' triggered this build Build Source Stamp: [branch master] 85635cd8ca5e7256d3295bbaa5cc88674eebcfca Blamelist: rmannibucauBUILD FAILED: failed test Sincerely, -The Buildbot
[jira] [Resolved] (TOMEE-2043) Thread local transactions are left open across requests
[ https://issues.apache.org/jira/browse/TOMEE-2043?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Svetlin Zarev resolved TOMEE-2043. -- Resolution: Not A Problem > Thread local transactions are left open across requests > --- > > Key: TOMEE-2043 > URL: https://issues.apache.org/jira/browse/TOMEE-2043 > Project: TomEE > Issue Type: Bug > Components: TomEE Core Server >Affects Versions: 7.0.3 >Reporter: Svetlin Zarev > Attachments: sample.zip > > > @Transactional CDI bean methods annotated with > @Transactional(dontRollbackOn = SomeException.class) do not commit the > transaction at the end of the request/response cycle when the SomeException > exception is thrown. As a result the thread local transaction object is > preserved across requests which makes unrelated requests to fail with "Nested > transactions are not supported". > Sample application that reproduces the issue is attached to the ticket. Just > request the application several times and observe how the output is changing. > Sample valve that can be used to demonstrate the issue: > {code} > public final class LeakedTransactionDetectionValve extends ValveBase { > private static final Logger logger = > Logger.getLogger(LeakedTransactionDetectionValve.class.getName()); > @Override > public void invoke(Request request, Response response) throws > IOException, ServletException { > boolean hasActiveTransaction = false; > try { > final Collection transactionsBeforeRequest = > getTransactions(); > for (Transaction transaction : transactionsBeforeRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > hasActiveTransaction = true; > break; > } > } > } catch (Exception ex) { > //no-op > } > getNext().invoke(request, response); > if (!hasActiveTransaction) { > try { > final Collection transactionsAfterRequest = > getTransactions(); > for (Transaction transaction : transactionsAfterRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > logger.log(Level.SEVERE, "Found active transaction: " > + request.getRequestURI() > + "?" > + request.getQueryString() > ); > } > } > } catch (Exception ex) { > logger.log(Level.SEVERE, "Failed to determine thread local > transaction status.", ex); > } > } > } > Collection getTransactions() throws NoSuchFieldException, > IllegalAccessException { > final Field threadLocalsField = > Thread.class.getDeclaredField("threadLocals"); > threadLocalsField.setAccessible(true); > final Object threadLocals = > threadLocalsField.get(Thread.currentThread()); > final Field tableField = > threadLocals.getClass().getDeclaredField("table"); > tableField.setAccessible(true); > final Object table = tableField.get(threadLocals); > final Collection transactions = new LinkedList<>(); > for (int i = 0; i < Array.getLength(table); i++) { > final Object entry = Array.get(table, i); > if (null != entry) { > final Field valueField = > entry.getClass().getDeclaredField("value"); > valueField.setAccessible(true); > final Object value = valueField.get(entry); > if (value instanceof Transaction) { > transactions.add((Transaction) value); > } > } > } > return transactions; > } > {code} > PS: in addition to the issue above, the > org.apache.openejb.cdi.transactional.InterceptorBase must not wrap the > exception specified in the "donotRollbackOn" attribute inside > TransactionalException -- This message was sent by Atlassian JIRA (v6.3.15#6346)
[jira] [Commented] (TOMEE-2043) Thread local transactions are left open across requests
[ https://issues.apache.org/jira/browse/TOMEE-2043?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16032902#comment-16032902 ] Romain Manni-Bucau commented on TOMEE-2043: --- [~SvetlinZarev] sadly the bug is on your side so you should fix it on your side. From the interceptor we don't know if it is intended or not when we exit the method and what's the handling outside so we would likely log more false positive than real issues IMHO. > Thread local transactions are left open across requests > --- > > Key: TOMEE-2043 > URL: https://issues.apache.org/jira/browse/TOMEE-2043 > Project: TomEE > Issue Type: Bug > Components: TomEE Core Server >Affects Versions: 7.0.3 >Reporter: Svetlin Zarev > Attachments: sample.zip > > > @Transactional CDI bean methods annotated with > @Transactional(dontRollbackOn = SomeException.class) do not commit the > transaction at the end of the request/response cycle when the SomeException > exception is thrown. As a result the thread local transaction object is > preserved across requests which makes unrelated requests to fail with "Nested > transactions are not supported". > Sample application that reproduces the issue is attached to the ticket. Just > request the application several times and observe how the output is changing. > Sample valve that can be used to demonstrate the issue: > {code} > public final class LeakedTransactionDetectionValve extends ValveBase { > private static final Logger logger = > Logger.getLogger(LeakedTransactionDetectionValve.class.getName()); > @Override > public void invoke(Request request, Response response) throws > IOException, ServletException { > boolean hasActiveTransaction = false; > try { > final Collection transactionsBeforeRequest = > getTransactions(); > for (Transaction transaction : transactionsBeforeRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > hasActiveTransaction = true; > break; > } > } > } catch (Exception ex) { > //no-op > } > getNext().invoke(request, response); > if (!hasActiveTransaction) { > try { > final Collection transactionsAfterRequest = > getTransactions(); > for (Transaction transaction : transactionsAfterRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > logger.log(Level.SEVERE, "Found active transaction: " > + request.getRequestURI() > + "?" > + request.getQueryString() > ); > } > } > } catch (Exception ex) { > logger.log(Level.SEVERE, "Failed to determine thread local > transaction status.", ex); > } > } > } > Collection getTransactions() throws NoSuchFieldException, > IllegalAccessException { > final Field threadLocalsField = > Thread.class.getDeclaredField("threadLocals"); > threadLocalsField.setAccessible(true); > final Object threadLocals = > threadLocalsField.get(Thread.currentThread()); > final Field tableField = > threadLocals.getClass().getDeclaredField("table"); > tableField.setAccessible(true); > final Object table = tableField.get(threadLocals); > final Collection transactions = new LinkedList<>(); > for (int i = 0; i < Array.getLength(table); i++) { > final Object entry = Array.get(table, i); > if (null != entry) { > final Field valueField = > entry.getClass().getDeclaredField("value"); > valueField.setAccessible(true); > final Object value = valueField.get(entry); > if (value instanceof Transaction) { > transactions.add((Transaction) value); > } > } > } > return transactions; > } > {code} > PS: in addition to the issue above, the > org.apache.openejb.cdi.transactional.InterceptorBase must not wrap the > exception specified in the "donotRollbackOn" attribute inside > TransactionalException -- This message was sent by Atlassian JIRA (v6.3.15#6346)
[jira] [Commented] (TOMEE-2043) Thread local transactions are left open across requests
[ https://issues.apache.org/jira/browse/TOMEE-2043?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16032900#comment-16032900 ] Svetlin Zarev commented on TOMEE-2043: -- I agree. Do you think that clearing the thread local (and not committing the transaction) and logging an error is OK ? My point is that such state should not be randomly carried across requests - a bug in one request should not make other requests to fail. > Thread local transactions are left open across requests > --- > > Key: TOMEE-2043 > URL: https://issues.apache.org/jira/browse/TOMEE-2043 > Project: TomEE > Issue Type: Bug > Components: TomEE Core Server >Affects Versions: 7.0.3 >Reporter: Svetlin Zarev > Attachments: sample.zip > > > @Transactional CDI bean methods annotated with > @Transactional(dontRollbackOn = SomeException.class) do not commit the > transaction at the end of the request/response cycle when the SomeException > exception is thrown. As a result the thread local transaction object is > preserved across requests which makes unrelated requests to fail with "Nested > transactions are not supported". > Sample application that reproduces the issue is attached to the ticket. Just > request the application several times and observe how the output is changing. > Sample valve that can be used to demonstrate the issue: > {code} > public final class LeakedTransactionDetectionValve extends ValveBase { > private static final Logger logger = > Logger.getLogger(LeakedTransactionDetectionValve.class.getName()); > @Override > public void invoke(Request request, Response response) throws > IOException, ServletException { > boolean hasActiveTransaction = false; > try { > final Collection transactionsBeforeRequest = > getTransactions(); > for (Transaction transaction : transactionsBeforeRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > hasActiveTransaction = true; > break; > } > } > } catch (Exception ex) { > //no-op > } > getNext().invoke(request, response); > if (!hasActiveTransaction) { > try { > final Collection transactionsAfterRequest = > getTransactions(); > for (Transaction transaction : transactionsAfterRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > logger.log(Level.SEVERE, "Found active transaction: " > + request.getRequestURI() > + "?" > + request.getQueryString() > ); > } > } > } catch (Exception ex) { > logger.log(Level.SEVERE, "Failed to determine thread local > transaction status.", ex); > } > } > } > Collection getTransactions() throws NoSuchFieldException, > IllegalAccessException { > final Field threadLocalsField = > Thread.class.getDeclaredField("threadLocals"); > threadLocalsField.setAccessible(true); > final Object threadLocals = > threadLocalsField.get(Thread.currentThread()); > final Field tableField = > threadLocals.getClass().getDeclaredField("table"); > tableField.setAccessible(true); > final Object table = tableField.get(threadLocals); > final Collection transactions = new LinkedList<>(); > for (int i = 0; i < Array.getLength(table); i++) { > final Object entry = Array.get(table, i); > if (null != entry) { > final Field valueField = > entry.getClass().getDeclaredField("value"); > valueField.setAccessible(true); > final Object value = valueField.get(entry); > if (value instanceof Transaction) { > transactions.add((Transaction) value); > } > } > } > return transactions; > } > {code} > PS: in addition to the issue above, the > org.apache.openejb.cdi.transactional.InterceptorBase must not wrap the > exception specified in the "donotRollbackOn" attribute inside > TransactionalException -- This message was sent by Atlassian JIRA (v6.3.15#6346)
[jira] [Commented] (TOMEE-2043) Thread local transactions are left open across requests
[ https://issues.apache.org/jira/browse/TOMEE-2043?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16032855#comment-16032855 ] Romain Manni-Bucau commented on TOMEE-2043: --- if you start the transaction and use propagation then you are the one responsible of finishing it. So it sounds like tomee impl is good. > Thread local transactions are left open across requests > --- > > Key: TOMEE-2043 > URL: https://issues.apache.org/jira/browse/TOMEE-2043 > Project: TomEE > Issue Type: Bug > Components: TomEE Core Server >Affects Versions: 7.0.3 >Reporter: Svetlin Zarev > Attachments: sample.zip > > > @Transactional CDI bean methods annotated with > @Transactional(dontRollbackOn = SomeException.class) do not commit the > transaction at the end of the request/response cycle when the SomeException > exception is thrown. As a result the thread local transaction object is > preserved across requests which makes unrelated requests to fail with "Nested > transactions are not supported". > Sample application that reproduces the issue is attached to the ticket. Just > request the application several times and observe how the output is changing. > Sample valve that can be used to demonstrate the issue: > {code} > public final class LeakedTransactionDetectionValve extends ValveBase { > private static final Logger logger = > Logger.getLogger(LeakedTransactionDetectionValve.class.getName()); > @Override > public void invoke(Request request, Response response) throws > IOException, ServletException { > boolean hasActiveTransaction = false; > try { > final Collection transactionsBeforeRequest = > getTransactions(); > for (Transaction transaction : transactionsBeforeRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > hasActiveTransaction = true; > break; > } > } > } catch (Exception ex) { > //no-op > } > getNext().invoke(request, response); > if (!hasActiveTransaction) { > try { > final Collection transactionsAfterRequest = > getTransactions(); > for (Transaction transaction : transactionsAfterRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > logger.log(Level.SEVERE, "Found active transaction: " > + request.getRequestURI() > + "?" > + request.getQueryString() > ); > } > } > } catch (Exception ex) { > logger.log(Level.SEVERE, "Failed to determine thread local > transaction status.", ex); > } > } > } > Collection getTransactions() throws NoSuchFieldException, > IllegalAccessException { > final Field threadLocalsField = > Thread.class.getDeclaredField("threadLocals"); > threadLocalsField.setAccessible(true); > final Object threadLocals = > threadLocalsField.get(Thread.currentThread()); > final Field tableField = > threadLocals.getClass().getDeclaredField("table"); > tableField.setAccessible(true); > final Object table = tableField.get(threadLocals); > final Collection transactions = new LinkedList<>(); > for (int i = 0; i < Array.getLength(table); i++) { > final Object entry = Array.get(table, i); > if (null != entry) { > final Field valueField = > entry.getClass().getDeclaredField("value"); > valueField.setAccessible(true); > final Object value = valueField.get(entry); > if (value instanceof Transaction) { > transactions.add((Transaction) value); > } > } > } > return transactions; > } > {code} > PS: in addition to the issue above, the > org.apache.openejb.cdi.transactional.InterceptorBase must not wrap the > exception specified in the "donotRollbackOn" attribute inside > TransactionalException -- This message was sent by Atlassian JIRA (v6.3.15#6346)
[jira] [Comment Edited] (TOMEE-2043) Thread local transactions are left open across requests
[ https://issues.apache.org/jira/browse/TOMEE-2043?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16032853#comment-16032853 ] Svetlin Zarev edited comment on TOMEE-2043 at 6/1/17 11:53 AM: --- Your test case passes because the transaction is started in the TxRequired policy. While my sample app fails, because the transaction is ".begin()"ed manually in the servlet: {code} transaction.begin(); transactionalBean.withDontRollbackOn(); transaction.commit(); {code} ThRequired policy: {code} public void commit() throws ApplicationException, SystemException { // only commit if we started the transaction if (clientTx == null) { completeTransaction(currentTx); } else { fireNonTransactionalCompletion(); } } {code} So in the junit test case, the execution goes to the "clientTx == null" branch, while in my case it goes to " fireNonTransactionalCompletion();" IMO that's fine in all cases except for if this is the outermost interceptor, because in that case there is no one to complete the transaction. What do you think ? was (Author: svetlinzarev): Your test case passes because the transaction is started in the TxRequired policy. While may sample app fails, because the transaction is ".begin()"ed manually in the servlet: {code} transaction.begin(); transactionalBean.withDontRollbackOn(); transaction.commit(); {code} ThRequired policy: {code} public void commit() throws ApplicationException, SystemException { // only commit if we started the transaction if (clientTx == null) { completeTransaction(currentTx); } else { fireNonTransactionalCompletion(); } } {code} So in the junit test case, the execution goes to the "clientTx == null" branch, while in my case it goes to " fireNonTransactionalCompletion();" IMO that's fine in all cases except for if this is the outermost interceptor, because in that case there is no one to complete the transaction. > Thread local transactions are left open across requests > --- > > Key: TOMEE-2043 > URL: https://issues.apache.org/jira/browse/TOMEE-2043 > Project: TomEE > Issue Type: Bug > Components: TomEE Core Server >Affects Versions: 7.0.3 >Reporter: Svetlin Zarev > Attachments: sample.zip > > > @Transactional CDI bean methods annotated with > @Transactional(dontRollbackOn = SomeException.class) do not commit the > transaction at the end of the request/response cycle when the SomeException > exception is thrown. As a result the thread local transaction object is > preserved across requests which makes unrelated requests to fail with "Nested > transactions are not supported". > Sample application that reproduces the issue is attached to the ticket. Just > request the application several times and observe how the output is changing. > Sample valve that can be used to demonstrate the issue: > {code} > public final class LeakedTransactionDetectionValve extends ValveBase { > private static final Logger logger = > Logger.getLogger(LeakedTransactionDetectionValve.class.getName()); > @Override > public void invoke(Request request, Response response) throws > IOException, ServletException { > boolean hasActiveTransaction = false; > try { > final Collection transactionsBeforeRequest = > getTransactions(); > for (Transaction transaction : transactionsBeforeRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > hasActiveTransaction = true; > break; > } > } > } catch (Exception ex) { > //no-op > } > getNext().invoke(request, response); > if (!hasActiveTransaction) { > try { > final Collection transactionsAfterRequest = > getTransactions(); > for (Transaction transaction : transactionsAfterRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > logger.log(Level.SEVERE, "Found active transaction: " > + request.getRequestURI() > + "?" > + request.getQueryString() > ); > } > } > } catch (Exception ex) { > logger.log(Level.SEVERE, "Failed to determine thread local > transaction status.", ex); > } > } > } > Collection getTransactions() throws NoSuchFieldException, > IllegalAccessException { > final Field threadLocalsField = > Thread.class.getDeclaredField("threadLocals"); >
[jira] [Commented] (TOMEE-2043) Thread local transactions are left open across requests
[ https://issues.apache.org/jira/browse/TOMEE-2043?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16032853#comment-16032853 ] Svetlin Zarev commented on TOMEE-2043: -- Your test case passes because the transaction is started in the TxRequired policy. While may sample app fails, because the transaction is ".begin()"ed manually in the servlet: {code} transaction.begin(); transactionalBean.withDontRollbackOn(); transaction.commit(); {code} ThRequired policy: {code} public void commit() throws ApplicationException, SystemException { // only commit if we started the transaction if (clientTx == null) { completeTransaction(currentTx); } else { fireNonTransactionalCompletion(); } } {code} So in the junit test case, the execution goes to the "clientTx == null" branch, while in my case it goes to " fireNonTransactionalCompletion();" IMO that's fine in all cases except for if this is the outermost interceptor, because in that case there is no one to complete the transaction. > Thread local transactions are left open across requests > --- > > Key: TOMEE-2043 > URL: https://issues.apache.org/jira/browse/TOMEE-2043 > Project: TomEE > Issue Type: Bug > Components: TomEE Core Server >Affects Versions: 7.0.3 >Reporter: Svetlin Zarev > Attachments: sample.zip > > > @Transactional CDI bean methods annotated with > @Transactional(dontRollbackOn = SomeException.class) do not commit the > transaction at the end of the request/response cycle when the SomeException > exception is thrown. As a result the thread local transaction object is > preserved across requests which makes unrelated requests to fail with "Nested > transactions are not supported". > Sample application that reproduces the issue is attached to the ticket. Just > request the application several times and observe how the output is changing. > Sample valve that can be used to demonstrate the issue: > {code} > public final class LeakedTransactionDetectionValve extends ValveBase { > private static final Logger logger = > Logger.getLogger(LeakedTransactionDetectionValve.class.getName()); > @Override > public void invoke(Request request, Response response) throws > IOException, ServletException { > boolean hasActiveTransaction = false; > try { > final Collection transactionsBeforeRequest = > getTransactions(); > for (Transaction transaction : transactionsBeforeRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > hasActiveTransaction = true; > break; > } > } > } catch (Exception ex) { > //no-op > } > getNext().invoke(request, response); > if (!hasActiveTransaction) { > try { > final Collection transactionsAfterRequest = > getTransactions(); > for (Transaction transaction : transactionsAfterRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > logger.log(Level.SEVERE, "Found active transaction: " > + request.getRequestURI() > + "?" > + request.getQueryString() > ); > } > } > } catch (Exception ex) { > logger.log(Level.SEVERE, "Failed to determine thread local > transaction status.", ex); > } > } > } > Collection getTransactions() throws NoSuchFieldException, > IllegalAccessException { > final Field threadLocalsField = > Thread.class.getDeclaredField("threadLocals"); > threadLocalsField.setAccessible(true); > final Object threadLocals = > threadLocalsField.get(Thread.currentThread()); > final Field tableField = > threadLocals.getClass().getDeclaredField("table"); > tableField.setAccessible(true); > final Object table = tableField.get(threadLocals); > final Collection transactions = new LinkedList<>(); > for (int i = 0; i < Array.getLength(table); i++) { > final Object entry = Array.get(table, i); > if (null != entry) { > final Field valueField = > entry.getClass().getDeclaredField("value"); > valueField.setAccessible(true); > final Object value = valueField.get(entry); > if (value instanceof Transaction) { > transactions.add((Transaction) value); > } > } > } > return transactions; > } > {code} > PS: in addition to the issue above, the >
[jira] [Commented] (TOMEE-2043) Thread local transactions are left open across requests
[ https://issues.apache.org/jira/browse/TOMEE-2043?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16032699#comment-16032699 ] Svetlin Zarev commented on TOMEE-2043: -- Sure, I'll try to update the test > Thread local transactions are left open across requests > --- > > Key: TOMEE-2043 > URL: https://issues.apache.org/jira/browse/TOMEE-2043 > Project: TomEE > Issue Type: Bug > Components: TomEE Core Server >Affects Versions: 7.0.3 >Reporter: Svetlin Zarev > Attachments: sample.zip > > > @Transactional CDI bean methods annotated with > @Transactional(dontRollbackOn = SomeException.class) do not commit the > transaction at the end of the request/response cycle when the SomeException > exception is thrown. As a result the thread local transaction object is > preserved across requests which makes unrelated requests to fail with "Nested > transactions are not supported". > Sample application that reproduces the issue is attached to the ticket. Just > request the application several times and observe how the output is changing. > Sample valve that can be used to demonstrate the issue: > {code} > public final class LeakedTransactionDetectionValve extends ValveBase { > private static final Logger logger = > Logger.getLogger(LeakedTransactionDetectionValve.class.getName()); > @Override > public void invoke(Request request, Response response) throws > IOException, ServletException { > boolean hasActiveTransaction = false; > try { > final Collection transactionsBeforeRequest = > getTransactions(); > for (Transaction transaction : transactionsBeforeRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > hasActiveTransaction = true; > break; > } > } > } catch (Exception ex) { > //no-op > } > getNext().invoke(request, response); > if (!hasActiveTransaction) { > try { > final Collection transactionsAfterRequest = > getTransactions(); > for (Transaction transaction : transactionsAfterRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > logger.log(Level.SEVERE, "Found active transaction: " > + request.getRequestURI() > + "?" > + request.getQueryString() > ); > } > } > } catch (Exception ex) { > logger.log(Level.SEVERE, "Failed to determine thread local > transaction status.", ex); > } > } > } > Collection getTransactions() throws NoSuchFieldException, > IllegalAccessException { > final Field threadLocalsField = > Thread.class.getDeclaredField("threadLocals"); > threadLocalsField.setAccessible(true); > final Object threadLocals = > threadLocalsField.get(Thread.currentThread()); > final Field tableField = > threadLocals.getClass().getDeclaredField("table"); > tableField.setAccessible(true); > final Object table = tableField.get(threadLocals); > final Collection transactions = new LinkedList<>(); > for (int i = 0; i < Array.getLength(table); i++) { > final Object entry = Array.get(table, i); > if (null != entry) { > final Field valueField = > entry.getClass().getDeclaredField("value"); > valueField.setAccessible(true); > final Object value = valueField.get(entry); > if (value instanceof Transaction) { > transactions.add((Transaction) value); > } > } > } > return transactions; > } > {code} > PS: in addition to the issue above, the > org.apache.openejb.cdi.transactional.InterceptorBase must not wrap the > exception specified in the "donotRollbackOn" attribute inside > TransactionalException -- This message was sent by Atlassian JIRA (v6.3.15#6346)
[jira] [Commented] (TOMEE-2043) Thread local transactions are left open across requests
[ https://issues.apache.org/jira/browse/TOMEE-2043?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16032687#comment-16032687 ] Romain Manni-Bucau commented on TOMEE-2043: --- Hi Svetlin, added this test https://github.com/apache/tomee/commit/85635cd8ca5e7256d3295bbaa5cc88674eebcfca#diff-a4abce7d91e66d06fa3fcc3106da9fb7R65 and it seems it is committed properly. Do you want to try to enhance this test class with a test reproducing your use case? > Thread local transactions are left open across requests > --- > > Key: TOMEE-2043 > URL: https://issues.apache.org/jira/browse/TOMEE-2043 > Project: TomEE > Issue Type: Bug > Components: TomEE Core Server >Affects Versions: 7.0.3 >Reporter: Svetlin Zarev > Attachments: sample.zip > > > @Transactional CDI bean methods annotated with > @Transactional(dontRollbackOn = SomeException.class) do not commit the > transaction at the end of the request/response cycle when the SomeException > exception is thrown. As a result the thread local transaction object is > preserved across requests which makes unrelated requests to fail with "Nested > transactions are not supported". > Sample application that reproduces the issue is attached to the ticket. Just > request the application several times and observe how the output is changing. > Sample valve that can be used to demonstrate the issue: > {code} > public final class LeakedTransactionDetectionValve extends ValveBase { > private static final Logger logger = > Logger.getLogger(LeakedTransactionDetectionValve.class.getName()); > @Override > public void invoke(Request request, Response response) throws > IOException, ServletException { > boolean hasActiveTransaction = false; > try { > final Collection transactionsBeforeRequest = > getTransactions(); > for (Transaction transaction : transactionsBeforeRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > hasActiveTransaction = true; > break; > } > } > } catch (Exception ex) { > //no-op > } > getNext().invoke(request, response); > if (!hasActiveTransaction) { > try { > final Collection transactionsAfterRequest = > getTransactions(); > for (Transaction transaction : transactionsAfterRequest) { > if (transaction.getStatus() == Status.STATUS_ACTIVE) { > logger.log(Level.SEVERE, "Found active transaction: " > + request.getRequestURI() > + "?" > + request.getQueryString() > ); > } > } > } catch (Exception ex) { > logger.log(Level.SEVERE, "Failed to determine thread local > transaction status.", ex); > } > } > } > Collection getTransactions() throws NoSuchFieldException, > IllegalAccessException { > final Field threadLocalsField = > Thread.class.getDeclaredField("threadLocals"); > threadLocalsField.setAccessible(true); > final Object threadLocals = > threadLocalsField.get(Thread.currentThread()); > final Field tableField = > threadLocals.getClass().getDeclaredField("table"); > tableField.setAccessible(true); > final Object table = tableField.get(threadLocals); > final Collection transactions = new LinkedList<>(); > for (int i = 0; i < Array.getLength(table); i++) { > final Object entry = Array.get(table, i); > if (null != entry) { > final Field valueField = > entry.getClass().getDeclaredField("value"); > valueField.setAccessible(true); > final Object value = valueField.get(entry); > if (value instanceof Transaction) { > transactions.add((Transaction) value); > } > } > } > return transactions; > } > {code} > PS: in addition to the issue above, the > org.apache.openejb.cdi.transactional.InterceptorBase must not wrap the > exception specified in the "donotRollbackOn" attribute inside > TransactionalException -- This message was sent by Atlassian JIRA (v6.3.15#6346)
[jira] [Updated] (TOMEE-2043) Thread local transactions are left open across requests
[ https://issues.apache.org/jira/browse/TOMEE-2043?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Svetlin Zarev updated TOMEE-2043: - Description: @Transactional CDI bean methods annotated with @Transactional(dontRollbackOn = SomeException.class) do not commit the transaction at the end of the request/response cycle when the SomeException exception is thrown. As a result the thread local transaction object is preserved across requests which makes unrelated requests to fail with "Nested transactions are not supported". Sample application that reproduces the issue is attached to the ticket. Just request the application several times and observe how the output is changing. Sample valve that can be used to demonstrate the issue: {code} public final class LeakedTransactionDetectionValve extends ValveBase { private static final Logger logger = Logger.getLogger(LeakedTransactionDetectionValve.class.getName()); @Override public void invoke(Request request, Response response) throws IOException, ServletException { boolean hasActiveTransaction = false; try { final Collection transactionsBeforeRequest = getTransactions(); for (Transaction transaction : transactionsBeforeRequest) { if (transaction.getStatus() == Status.STATUS_ACTIVE) { hasActiveTransaction = true; break; } } } catch (Exception ex) { //no-op } getNext().invoke(request, response); if (!hasActiveTransaction) { try { final Collection transactionsAfterRequest = getTransactions(); for (Transaction transaction : transactionsAfterRequest) { if (transaction.getStatus() == Status.STATUS_ACTIVE) { logger.log(Level.SEVERE, "Found active transaction: " + request.getRequestURI() + "?" + request.getQueryString() ); } } } catch (Exception ex) { logger.log(Level.SEVERE, "Failed to determine thread local transaction status.", ex); } } } Collection getTransactions() throws NoSuchFieldException, IllegalAccessException { final Field threadLocalsField = Thread.class.getDeclaredField("threadLocals"); threadLocalsField.setAccessible(true); final Object threadLocals = threadLocalsField.get(Thread.currentThread()); final Field tableField = threadLocals.getClass().getDeclaredField("table"); tableField.setAccessible(true); final Object table = tableField.get(threadLocals); final Collection transactions = new LinkedList<>(); for (int i = 0; i < Array.getLength(table); i++) { final Object entry = Array.get(table, i); if (null != entry) { final Field valueField = entry.getClass().getDeclaredField("value"); valueField.setAccessible(true); final Object value = valueField.get(entry); if (value instanceof Transaction) { transactions.add((Transaction) value); } } } return transactions; } {code} PS: in addition to the issue above, the org.apache.openejb.cdi.transactional.InterceptorBase must not wrap the exception specified in the "donotRollbackOn" attribute inside TransactionalException was: @Transactional CDI bean methods annotated with @Transactional(dontRollbackOn = SomeException.class) do not commit the transaction at the end of the request/response cycle when the SomeException exception is thrown. As a result the thread local transaction object is preserved across requests which makes unrelated requests to fail with "Nested transactions are not supported". Sample application that reproduces the issue is attached to the ticket. Sample valve that can be used to demonstrate the issue: {code} public final class LeakedTransactionDetectionValve extends ValveBase { private static final Logger logger = Logger.getLogger(LeakedTransactionDetectionValve.class.getName()); @Override public void invoke(Request request, Response response) throws IOException, ServletException { boolean hasActiveTransaction = false; try { final Collection transactionsBeforeRequest = getTransactions(); for (Transaction transaction : transactionsBeforeRequest) { if (transaction.getStatus() == Status.STATUS_ACTIVE) { hasActiveTransaction = true; break; } } } catch (Exception ex) { //no-op } getNext().invoke(request, response); if
tomee git commit: TOMEE-2043 test dontRollbackOn @Transactional config
Repository: tomee Updated Branches: refs/heads/master 4e4311162 -> 85635cd8c TOMEE-2043 test dontRollbackOn @Transactional config Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/85635cd8 Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/85635cd8 Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/85635cd8 Branch: refs/heads/master Commit: 85635cd8ca5e7256d3295bbaa5cc88674eebcfca Parents: 4e43111 Author: rmannibucauAuthored: Thu Jun 1 11:23:35 2017 +0200 Committer: rmannibucau Committed: Thu Jun 1 11:23:35 2017 +0200 -- .../cdi/transactional/TransactionalTest.java | 17 + 1 file changed, 17 insertions(+) -- http://git-wip-us.apache.org/repos/asf/tomee/blob/85635cd8/container/openejb-core/src/test/java/org/apache/openejb/cdi/transactional/TransactionalTest.java -- diff --git a/container/openejb-core/src/test/java/org/apache/openejb/cdi/transactional/TransactionalTest.java b/container/openejb-core/src/test/java/org/apache/openejb/cdi/transactional/TransactionalTest.java index d63b7af..265e5b2 100644 --- a/container/openejb-core/src/test/java/org/apache/openejb/cdi/transactional/TransactionalTest.java +++ b/container/openejb-core/src/test/java/org/apache/openejb/cdi/transactional/TransactionalTest.java @@ -47,6 +47,7 @@ import static javax.transaction.Transactional.TxType.REQUIRES_NEW; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -61,6 +62,17 @@ public class TransactionalTest { @Inject private TxBean bean; +@Test +public void dontRollbackCommits() throws SystemException { +assertNull(OpenEJB.getTransactionManager().getTransaction()); +try { +bean.dontRollback(); +} catch (final TransactionalException e) { +// expected +} +assertNull(OpenEJB.getTransactionManager().getTransaction()); +} + @Test(expected = TransactionalException.class) public void mandatoryKO() { for (int i = 0; i < 2; i++) { @@ -361,6 +373,11 @@ public class TransactionalTest { } } +@Transactional(dontRollbackOn = AnException.class) +public void dontRollback() { +throw new AnException(); +} + @Transactional(value = MANDATORY, rollbackOn = AnException.class) public void anException() { throw new AnException();
[jira] [Created] (TOMEE-2043) Thread local transactions are left open across requests
Svetlin Zarev created TOMEE-2043: Summary: Thread local transactions are left open across requests Key: TOMEE-2043 URL: https://issues.apache.org/jira/browse/TOMEE-2043 Project: TomEE Issue Type: Bug Components: TomEE Core Server Affects Versions: 7.0.3 Reporter: Svetlin Zarev Attachments: sample.zip @Transactional CDI bean methods annotated with @Transactional(dontRollbackOn = SomeException.class) do not commit the transaction at the end of the request/response cycle when the SomeException exception is thrown. As a result the thread local transaction object is preserved across requests which makes unrelated requests to fail with "Nested transactions are not supported". Sample application that reproduces the issue is attached to the ticket. Sample valve that can be used to demonstrate the issue: {code} public final class LeakedTransactionDetectionValve extends ValveBase { private static final Logger logger = Logger.getLogger(LeakedTransactionDetectionValve.class.getName()); @Override public void invoke(Request request, Response response) throws IOException, ServletException { boolean hasActiveTransaction = false; try { final Collection transactionsBeforeRequest = getTransactions(); for (Transaction transaction : transactionsBeforeRequest) { if (transaction.getStatus() == Status.STATUS_ACTIVE) { hasActiveTransaction = true; break; } } } catch (Exception ex) { //no-op } getNext().invoke(request, response); if (!hasActiveTransaction) { try { final Collection transactionsAfterRequest = getTransactions(); for (Transaction transaction : transactionsAfterRequest) { if (transaction.getStatus() == Status.STATUS_ACTIVE) { logger.log(Level.SEVERE, "Found active transaction: " + request.getRequestURI() + "?" + request.getQueryString() ); } } } catch (Exception ex) { logger.log(Level.SEVERE, "Failed to determine thread local transaction status.", ex); } } } Collection getTransactions() throws NoSuchFieldException, IllegalAccessException { final Field threadLocalsField = Thread.class.getDeclaredField("threadLocals"); threadLocalsField.setAccessible(true); final Object threadLocals = threadLocalsField.get(Thread.currentThread()); final Field tableField = threadLocals.getClass().getDeclaredField("table"); tableField.setAccessible(true); final Object table = tableField.get(threadLocals); final Collection transactions = new LinkedList<>(); for (int i = 0; i < Array.getLength(table); i++) { final Object entry = Array.get(table, i); if (null != entry) { final Field valueField = entry.getClass().getDeclaredField("value"); valueField.setAccessible(true); final Object value = valueField.get(entry); if (value instanceof Transaction) { transactions.add((Transaction) value); } } } return transactions; } {code} PS: in addition to the issue above, the org.apache.openejb.cdi.transactional.InterceptorBase must not wrap the exception specified in the "donotRollbackOn" attribute inside TransactionalException -- This message was sent by Atlassian JIRA (v6.3.15#6346)