Add JNDI Sample
Add a sample application that can be deployed to WildFly to demonstrate how JTA can be used when running in a application server. See gh-947pull/1323/merge
parent
239d19d38c
commit
85cfd016a6
@ -0,0 +1,148 @@
|
||||
## Introduction
|
||||
|
||||
This application is intended to run inside of a Java EE application server such as
|
||||
JBoss Wildfly. It demonstrates Spring Boot's auto-configuration defaulting for a
|
||||
container-managed `TransactionManager` and `DataSource`. This example unfortunately
|
||||
requires a fully configured Wildfly installation. You'll need to configure a PostgreSQL
|
||||
XA `DataSource` and an XA `ConnectionFactory` in the Java EE application server's
|
||||
JNDI machinery.
|
||||
|
||||
## Setup
|
||||
|
||||
### Postgres
|
||||
We will use postgres as the underlying database, v9.3.5 or above is recommend. Follow
|
||||
the installation instructions from http://www.postgresql.org/[postgresql.org] or use
|
||||
a package manager to install the appropriate binaries.
|
||||
|
||||
Once installed you will need to initialize and start the server.
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
$ initdb /usr/local/var/postgres -E utf8
|
||||
$ pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start
|
||||
----
|
||||
|
||||
With the server running you can create a user and a database:
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
$ createuser springboot
|
||||
$ createdb bootdemo
|
||||
----
|
||||
|
||||
Finally you can type `psql bootdemo` to configure a password:
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
ALTER USER springboot WITH PASSWORD 'springboot';
|
||||
\q
|
||||
----
|
||||
|
||||
|
||||
### WildFly 8.1
|
||||
Download an install WildFly 8.1 from http://wildfly.org/downloads/[wildfly.org]. Once
|
||||
installed you will need to add a management user by running `$JBOSS_HOME/bin/add-user.sh`
|
||||
(see the WildFly documentation for details).
|
||||
|
||||
You will also need to add a postgresql module. The following commands setup the basic
|
||||
structure:
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
$ cd $JBOSS_HOME
|
||||
mkdir -p modules/org/postgresql/main
|
||||
wget http://jdbc.postgresql.org/download/postgresql-9.3-1102.jdbc41.jar
|
||||
mv postgresql-9.3-1102.jdbc41.jar modules/org/postgresql/main
|
||||
----
|
||||
|
||||
You can then add the following to `$JBOSS_HOME/modules/org/postgresql/main/module.xml`:
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module xmlns="urn:jboss:module:1.0" name="org.postgresql">
|
||||
<resources>
|
||||
<resource-root path="postgresql-9.3-1102.jdbc41.jar"/>
|
||||
</resources>
|
||||
<dependencies>
|
||||
<module name="javax.api"/>
|
||||
<module name="javax.transaction.api"/>
|
||||
</dependencies>
|
||||
</module>
|
||||
----
|
||||
|
||||
## Configuration
|
||||
A custom WildFly configuration is required for the XA `DataSource` and `ConnectionFactory`
|
||||
elements. The `$JBOSS_HOME/standalone/configuration/standalone-full.xml` is a good
|
||||
starting point, copy this file to
|
||||
`$JBOSS_HOME/standalone/configuration/standalone-boot-demo.xml` then make the following
|
||||
changes.
|
||||
|
||||
### DataSource
|
||||
You need to register a PostgreSQL XA `Driver` and then configure an `xa-datasource`.
|
||||
|
||||
Here's a complete listing of the `xa-datasource` contribution to the `datasources`
|
||||
element, and the `driver` contribution to the `drivers` element to configure a PostgreSQL
|
||||
DB connection to localhost.
|
||||
https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6/html-single/Administration_and_Configuration_Guide/index.html#Install_a_JDBC_Driver_with_the_Management_Console[You can learn more from the documentation].
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,attributes"]
|
||||
----
|
||||
<datasources>
|
||||
...
|
||||
<xa-datasource
|
||||
jndi-name="java:jboss/datasources/bootdemo"
|
||||
pool-name="CrmXADS"
|
||||
enabled="true">
|
||||
<xa-datasource-property name="url">jdbc:postgresql://localhost:5432/crm</xa-datasource-property>
|
||||
<driver>postgres</driver>
|
||||
<xa-pool>
|
||||
<min-pool-size>10</min-pool-size>
|
||||
<max-pool-size>20</max-pool-size>
|
||||
<prefill>true</prefill>
|
||||
</xa-pool>
|
||||
<security>
|
||||
<user-name>springboot</user-name>
|
||||
<password>springboot</password>
|
||||
</security>
|
||||
</xa-datasource>
|
||||
<drivers>
|
||||
...
|
||||
<driver name="postgres" module="org.postgresql">
|
||||
<xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
|
||||
</driver>
|
||||
</drivers>
|
||||
</datasources>
|
||||
----
|
||||
|
||||
### JMS Destination
|
||||
You will also need to configure a `javax.jms.Destination` by contributing the following to
|
||||
the `hornetq-server` element:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,attributes"]
|
||||
----
|
||||
<jms-destinations>
|
||||
<jms-queue name="accounts">
|
||||
<entry name="java:/jms/queue/bootdemo"/>
|
||||
</jms-queue>
|
||||
...
|
||||
</jms-destinations>
|
||||
----
|
||||
|
||||
|
||||
## Running and deploying the sample
|
||||
Run Wildfly with the following command:
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
$JBOSS_HOME/bin/standalone.sh -c standalone-boot-demo.xml
|
||||
----
|
||||
|
||||
Once running you can deploy the application by copying
|
||||
`target/spring-boot-sample-jta-jndi.war` to `$JBOSS_HOME/standalone/deployments`.
|
||||
|
||||
Open a browser to http://localhost:8080/spring-boot-sample-jta-jndi to trigger the
|
||||
sample. You should see the current count (it will increment by one on each refresh). If
|
||||
you check the logs you should see a `----> Josh` message and some counts. Notice how the
|
||||
`error` message triggers an exception with causes both the database insert and the JMS
|
||||
message to be rolled back.
|
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<!-- Your own application should inherit from spring-boot-starter-parent -->
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-samples</artifactId>
|
||||
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-sample-jta-jndi</artifactId>
|
||||
<name>Spring Boot JNDI JTA Sample</name>
|
||||
<packaging>war</packaging>
|
||||
<description>Spring Boot JNDI JTA Sample</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jms</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.jms</groupId>
|
||||
<artifactId>jms-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<finalName>spring-boot-sample-jta-jndi</finalName>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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 sample.jndi;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Account {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String username;
|
||||
|
||||
Account() {
|
||||
}
|
||||
|
||||
public Account(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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 sample.jndi;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface AccountRepository extends CrudRepository<Account, Long> {
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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 sample.jndi;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jms.core.JmsTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class AccountService {
|
||||
|
||||
private final JmsTemplate jmsTemplate;
|
||||
|
||||
private final AccountRepository accountRepository;
|
||||
|
||||
@Autowired
|
||||
public AccountService(JmsTemplate jmsTemplate, AccountRepository accountRepository) {
|
||||
this.jmsTemplate = jmsTemplate;
|
||||
this.accountRepository = accountRepository;
|
||||
}
|
||||
|
||||
public void createAccountAndNotify(String username) {
|
||||
this.jmsTemplate.convertAndSend("java:/jms/queue/bootdemo", username);
|
||||
Account entity = new Account(username);
|
||||
this.accountRepository.save(entity);
|
||||
if ("error".equals(username)) {
|
||||
throw new RuntimeException("Simulated error");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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 sample.jndi;
|
||||
|
||||
import org.springframework.jms.annotation.JmsListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class Messages {
|
||||
|
||||
@JmsListener(destination = "java:/jms/queue/bootdemo")
|
||||
public void onMessage(String content) {
|
||||
System.out.println("----> " + content);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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 sample.jndi;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan
|
||||
public class SampleJndiApplication {
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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 sample.jndi;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.context.web.SpringBootServletInitializer;
|
||||
|
||||
public class SampleJndiInitializer extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
return application.sources(SampleJndiApplication.class);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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 sample.jndi;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class WebController {
|
||||
|
||||
private final AccountService service;
|
||||
|
||||
private final AccountRepository repository;
|
||||
|
||||
@Autowired
|
||||
public WebController(AccountService service, AccountRepository repository) {
|
||||
this.service = service;
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@RequestMapping("/")
|
||||
public String hello() {
|
||||
System.out.println("Count is " + this.repository.count());
|
||||
this.service.createAccountAndNotify("josh");
|
||||
try {
|
||||
this.service.createAccountAndNotify("error");
|
||||
}
|
||||
catch (Exception ex) {
|
||||
System.out.println(ex.getMessage());
|
||||
}
|
||||
long count = this.repository.count();
|
||||
System.out.println("Count is " + count);
|
||||
return "Count is " + count;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
spring.jpa.generate-ddl=true
|
||||
spring.datasource.jndi-name=java:jboss/datasources/bootdemo
|
||||
|
||||
# Workaround SPR-12118
|
||||
spring.jpa.open-in-view=false
|
Loading…
Reference in New Issue