Skip to content

Commit c018788

Browse files
committed
Test JTA auto-configured from JNDI
Closes gh-28594
1 parent 24c578e commit c018788

File tree

5 files changed

+135
-1
lines changed

5 files changed

+135
-1
lines changed

spring-boot-project/spring-boot-autoconfigure/build.gradle

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ dependencies {
7373
optional("org.aspectj:aspectjweaver")
7474
optional("org.eclipse.jetty:jetty-webapp")
7575
optional("org.eclipse.jetty:jetty-reactive-httpclient")
76-
optional("org.eclipse.jetty.websocket:javax-websocket-server-impl")
76+
optional("org.eclipse.jetty.websocket:javax-websocket-server-impl") {
77+
exclude(group: "org.eclipse.jetty", module: "jetty-jndi")
78+
}
7779
optional("org.ehcache:ehcache")
7880
optional("org.elasticsearch.client:elasticsearch-rest-client")
7981
optional("org.elasticsearch.client:elasticsearch-rest-high-level-client")
@@ -153,6 +155,7 @@ dependencies {
153155
testImplementation("ch.qos.logback:logback-classic")
154156
testImplementation("commons-fileupload:commons-fileupload")
155157
testImplementation("com.atomikos:transactions-jms")
158+
testImplementation("com.github.h-thurow:simple-jndi")
156159
testImplementation("com.ibm.db2:jcc")
157160
testImplementation("com.jayway.jsonpath:json-path")
158161
testImplementation("com.squareup.okhttp3:mockwebserver")

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/jta/JtaAutoConfigurationTests.java

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,18 @@
2121
import java.net.InetAddress;
2222
import java.net.UnknownHostException;
2323
import java.nio.file.Path;
24+
import java.util.Arrays;
25+
import java.util.List;
26+
import java.util.Properties;
2427

2528
import javax.jms.ConnectionFactory;
2629
import javax.jms.TemporaryQueue;
2730
import javax.jms.XAConnection;
2831
import javax.jms.XAConnectionFactory;
2932
import javax.jms.XASession;
33+
import javax.naming.Context;
34+
import javax.naming.InitialContext;
35+
import javax.naming.NamingException;
3036
import javax.sql.DataSource;
3137
import javax.sql.XADataSource;
3238
import javax.transaction.TransactionManager;
@@ -38,7 +44,19 @@
3844
import com.atomikos.jms.AtomikosConnectionFactoryBean;
3945
import org.junit.jupiter.api.AfterEach;
4046
import org.junit.jupiter.api.Test;
47+
import org.junit.jupiter.api.extension.AfterEachCallback;
48+
import org.junit.jupiter.api.extension.BeforeEachCallback;
49+
import org.junit.jupiter.api.extension.ExtendWith;
50+
import org.junit.jupiter.api.extension.ExtensionContext;
51+
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
52+
import org.junit.jupiter.api.extension.ParameterContext;
53+
import org.junit.jupiter.api.extension.ParameterResolutionException;
54+
import org.junit.jupiter.api.extension.ParameterResolver;
4155
import org.junit.jupiter.api.io.TempDir;
56+
import org.junit.jupiter.params.ParameterizedTest;
57+
import org.junit.jupiter.params.provider.Arguments;
58+
import org.junit.jupiter.params.provider.MethodSource;
59+
import org.osjava.sj.loader.JndiLoader;
4260

4361
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
4462
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
@@ -53,6 +71,7 @@
5371
import org.springframework.context.annotation.Bean;
5472
import org.springframework.context.annotation.Configuration;
5573
import org.springframework.transaction.jta.JtaTransactionManager;
74+
import org.springframework.transaction.jta.UserTransactionAdapter;
5675

5776
import static org.assertj.core.api.Assertions.assertThat;
5877
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -80,6 +99,31 @@ void closeContext() {
8099
if (this.context != null) {
81100
this.context.close();
82101
}
102+
103+
}
104+
105+
@ParameterizedTest
106+
@ExtendWith(JndiExtension.class)
107+
@MethodSource("transactionManagerJndiEntries")
108+
void transactionManagerFromJndi(JndiEntry jndiEntry, InitialContext initialContext) throws NamingException {
109+
jndiEntry.register(initialContext);
110+
this.context = new AnnotationConfigApplicationContext(JtaAutoConfiguration.class);
111+
JtaTransactionManager transactionManager = this.context.getBean(JtaTransactionManager.class);
112+
if (jndiEntry.value instanceof UserTransaction) {
113+
assertThat(transactionManager.getUserTransaction()).isEqualTo(jndiEntry.value);
114+
assertThat(transactionManager.getTransactionManager()).isNull();
115+
}
116+
else {
117+
assertThat(transactionManager.getUserTransaction()).isInstanceOf(UserTransactionAdapter.class);
118+
assertThat(transactionManager.getTransactionManager()).isEqualTo(jndiEntry.value);
119+
}
120+
}
121+
122+
static List<Arguments> transactionManagerJndiEntries() {
123+
return Arrays.asList(Arguments.of(new JndiEntry("java:comp/UserTransaction", UserTransaction.class)),
124+
Arguments.of(new JndiEntry("java:appserver/TransactionManager", TransactionManager.class)),
125+
Arguments.of(new JndiEntry("java:pm/TransactionManager", TransactionManager.class)),
126+
Arguments.of(new JndiEntry("java:/TransactionManager", TransactionManager.class)));
83127
}
84128

85129
@Test
@@ -292,4 +336,79 @@ DataSource pooledDataSource(XADataSourceWrapper wrapper) throws Exception {
292336

293337
}
294338

339+
private static final class JndiEntry {
340+
341+
private final String name;
342+
343+
private final Class<?> type;
344+
345+
private final Object value;
346+
347+
private JndiEntry(String name, Class<?> type) {
348+
this.name = name;
349+
this.type = type;
350+
this.value = mock(type);
351+
}
352+
353+
private void register(InitialContext initialContext) throws NamingException {
354+
String[] components = this.name.split("/");
355+
String subcontextName = components[0];
356+
String entryName = components[1];
357+
Context javaComp = initialContext.createSubcontext(subcontextName);
358+
JndiLoader loader = new JndiLoader(initialContext.getEnvironment());
359+
Properties properties = new Properties();
360+
properties.setProperty(entryName + "/type", this.type.getName());
361+
properties.put(entryName + "/valueToConvert", this.value);
362+
loader.load(properties, javaComp);
363+
}
364+
365+
@Override
366+
public String toString() {
367+
return this.name;
368+
}
369+
370+
}
371+
372+
private static final class JndiExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver {
373+
374+
@Override
375+
public void beforeEach(ExtensionContext context) throws Exception {
376+
Namespace namespace = Namespace.create(getClass(), context.getUniqueId());
377+
context.getStore(namespace).getOrComputeIfAbsent(InitialContext.class, (k) -> createInitialContext(),
378+
InitialContext.class);
379+
}
380+
381+
private InitialContext createInitialContext() {
382+
try {
383+
return new InitialContext();
384+
}
385+
catch (Exception ex) {
386+
throw new RuntimeException();
387+
}
388+
}
389+
390+
@Override
391+
public void afterEach(ExtensionContext context) throws Exception {
392+
Namespace namespace = Namespace.create(getClass(), context.getUniqueId());
393+
InitialContext initialContext = context.getStore(namespace).remove(InitialContext.class,
394+
InitialContext.class);
395+
initialContext.removeFromEnvironment("org.osjava.sj.jndi.ignoreClose");
396+
initialContext.close();
397+
}
398+
399+
@Override
400+
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
401+
throws ParameterResolutionException {
402+
return InitialContext.class.isAssignableFrom(parameterContext.getParameter().getType());
403+
}
404+
405+
@Override
406+
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
407+
throws ParameterResolutionException {
408+
Namespace namespace = Namespace.create(getClass(), extensionContext.getUniqueId());
409+
return extensionContext.getStore(namespace).get(InitialContext.class);
410+
}
411+
412+
}
413+
295414
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
java.naming.factory.initial = org.osjava.sj.SimpleJndiContextFactory
2+
org.osjava.sj.delimiter = /
3+
org.osjava.sj.jndi.shared = true
4+
org.osjava.sj.root = src/test/resources/simple-jndi
5+
org.osjava.sj.jndi.ignoreClose = true

spring-boot-project/spring-boot-autoconfigure/src/test/resources/simple-jndi

Whitespace-only changes.

spring-boot-project/spring-boot-parent/build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ bom {
126126
]
127127
}
128128
}
129+
library("Simple JNDI", "0.23.0") {
130+
group("com.github.h-thurow") {
131+
modules = [
132+
"simple-jndi"
133+
]
134+
}
135+
}
129136
library("Sisu", "2.6.0") {
130137
group("org.sonatype.sisu") {
131138
modules = [

0 commit comments

Comments
 (0)