diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml index 6bd30f875a..5404d60bae 100644 --- a/spring-boot-samples/pom.xml +++ b/spring-boot-samples/pom.xml @@ -40,6 +40,7 @@ spring-boot-sample-jetty spring-boot-sample-jta-atomikos spring-boot-sample-jta-bitronix + spring-boot-sample-jta-jndi spring-boot-sample-liquibase spring-boot-sample-parent-context spring-boot-sample-profile diff --git a/spring-boot-samples/spring-boot-sample-jta-jndi/README.adoc b/spring-boot-samples/spring-boot-sample-jta-jndi/README.adoc new file mode 100644 index 0000000000..3e4addb82e --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-jta-jndi/README.adoc @@ -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] +---- + + + + + + + + + + +---- + +## 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"] +---- + + ... + + jdbc:postgresql://localhost:5432/crm + postgres + + 10 + 20 + true + + + springboot + springboot + + + + ... + + org.postgresql.xa.PGXADataSource + + + +---- + +### 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"] +---- + + + + + ... + +---- + + +## 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. diff --git a/spring-boot-samples/spring-boot-sample-jta-jndi/pom.xml b/spring-boot-samples/spring-boot-sample-jta-jndi/pom.xml new file mode 100644 index 0000000000..73a54e864e --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-jta-jndi/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-samples + 1.2.0.BUILD-SNAPSHOT + + spring-boot-sample-jta-jndi + Spring Boot JNDI JTA Sample + war + Spring Boot JNDI JTA Sample + http://projects.spring.io/spring-boot/ + + Pivotal Software, Inc. + http://www.spring.io + + + ${basedir}/../.. + + + + org.springframework + spring-jms + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + javax.servlet + javax.servlet-api + provided + + + javax.jms + jms-api + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + + spring-boot-sample-jta-jndi + + diff --git a/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/Account.java b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/Account.java new file mode 100644 index 0000000000..c55d0e30cf --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/Account.java @@ -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; + } + +} diff --git a/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/AccountRepository.java b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/AccountRepository.java new file mode 100644 index 0000000000..350e87af25 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/AccountRepository.java @@ -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 { + +} diff --git a/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/AccountService.java b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/AccountService.java new file mode 100644 index 0000000000..f297d1572a --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/AccountService.java @@ -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"); + } + } + +} diff --git a/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/Messages.java b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/Messages.java new file mode 100644 index 0000000000..59bb4e639d --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/Messages.java @@ -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); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/SampleJndiApplication.java b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/SampleJndiApplication.java new file mode 100644 index 0000000000..2f42628517 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/SampleJndiApplication.java @@ -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 { + +} diff --git a/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/SampleJndiInitializer.java b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/SampleJndiInitializer.java new file mode 100644 index 0000000000..3314d0e126 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/SampleJndiInitializer.java @@ -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); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/WebController.java b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/WebController.java new file mode 100644 index 0000000000..6b444578f6 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/java/sample/jndi/WebController.java @@ -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; + } + +} diff --git a/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/resources/application.properties new file mode 100644 index 0000000000..a4720b1e4d --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-jta-jndi/src/main/resources/application.properties @@ -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