diff --git a/atomikos/README.md b/atomikos/README.md
new file mode 100644
index 0000000000..19f2e871d4
--- /dev/null
+++ b/atomikos/README.md
@@ -0,0 +1,7 @@
+## Atomikos
+
+This module contains articles about Atomikos
+
+### Relevant Articles:
+
+- [Guide Transactions Using Atomikos]()
diff --git a/atomikos/pom.xml b/atomikos/pom.xml
new file mode 100644
index 0000000000..881adae074
--- /dev/null
+++ b/atomikos/pom.xml
@@ -0,0 +1,119 @@
+
+
+ 4.0.0
+ atomikos
+ atomikos
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+ com.atomikos
+ transactions-jdbc
+ ${atomikos-version}
+
+
+ com.atomikos
+ transactions-jms
+ ${atomikos-version}
+
+
+ com.atomikos
+ transactions-hibernate4
+ ${atomikos-version}
+
+
+ org.springframework
+ spring-context
+ ${spring-version}
+
+
+ org.springframework
+ spring-tx
+ ${spring-version}
+
+
+ org.springframework.data
+ spring-data-jpa
+ 1.11.23.RELEASE
+
+
+ org.springframework
+ spring-test
+ ${spring-version}
+ test
+
+
+ org.hibernate
+ hibernate-entitymanager
+ ${hibernate.version}
+ provided
+
+
+ javax.transaction
+ jta
+
+
+
+
+ org.apache.activemq
+ activemq-core
+ 5.7.0
+
+
+ org.apache.derby
+ derby
+ 10.8.1.2
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+
+ javax.transaction
+ jta
+ 1.1
+
+
+ org.apache.geronimo.specs
+ geronimo-jta_1.0.1B_spec
+ 1.0
+
+
+ javax.validation
+ validation-api
+ 2.0.1.Final
+
+
+ org.hibernate.validator
+ hibernate-validator
+ 6.1.2.Final
+
+
+ javax.el
+ javax.el-api
+ 3.0.0
+
+
+ org.glassfish.web
+ javax.el
+ 2.2.4
+
+
+
+
+ 5.0.6
+ 5.1.6.RELEASE
+ 5.4.3.Final
+
+
+
\ No newline at end of file
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/direct/Application.java b/atomikos/src/main/java/com/baeldung/atomikos/direct/Application.java
new file mode 100644
index 0000000000..c51ce70dde
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/direct/Application.java
@@ -0,0 +1,53 @@
+package com.baeldung.atomikos.direct;
+
+import java.sql.Connection;
+import java.sql.Statement;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+
+import com.atomikos.icatch.jta.UserTransactionImp;
+
+public class Application {
+
+ private DataSource inventoryDataSource;
+ private DataSource orderDataSource;
+
+ public Application(DataSource inventoryDataSource, DataSource orderDataSource) {
+ this.inventoryDataSource = inventoryDataSource;
+ this.orderDataSource = orderDataSource;
+ }
+
+ public void placeOrder(String productId, int amount) throws Exception {
+
+ UserTransactionImp utx = new UserTransactionImp();
+ String orderId = UUID.randomUUID()
+ .toString();
+ boolean rollback = false;
+ try {
+ utx.begin();
+ Connection inventoryConnection = inventoryDataSource.getConnection();
+ Connection orderConnection = orderDataSource.getConnection();
+ Statement s1 = inventoryConnection.createStatement();
+ String q1 = "update Inventory set balance = balance - " + amount + " where productId ='" + productId + "'";
+ s1.executeUpdate(q1);
+ s1.close();
+ Statement s2 = orderConnection.createStatement();
+ String q2 = "insert into Orders values ( '" + orderId + "', '" + productId + "', " + amount + " )";
+ s2.executeUpdate(q2);
+ s2.close();
+ inventoryConnection.close();
+ orderConnection.close();
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ rollback = true;
+ } finally {
+ if (!rollback)
+ utx.commit();
+ else
+ utx.rollback();
+ }
+
+ }
+
+}
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/Application.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/Application.java
new file mode 100644
index 0000000000..b480e68d8d
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/Application.java
@@ -0,0 +1,41 @@
+package com.baeldung.atomikos.spring;
+
+import java.sql.Connection;
+import java.sql.Statement;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+
+import org.springframework.transaction.annotation.Transactional;
+
+public class Application {
+
+ private DataSource inventoryDataSource;
+ private DataSource orderDataSource;
+
+ public Application(DataSource inventoryDataSource, DataSource orderDataSource) {
+ this.inventoryDataSource = inventoryDataSource;
+ this.orderDataSource = orderDataSource;
+ }
+
+ @Transactional(rollbackFor = Exception.class)
+ public void placeOrder(String productId, int amount) throws Exception {
+
+ String orderId = UUID.randomUUID()
+ .toString();
+ Connection inventoryConnection = inventoryDataSource.getConnection();
+ Connection orderConnection = orderDataSource.getConnection();
+ Statement s1 = inventoryConnection.createStatement();
+ String q1 = "update Inventory set balance = balance - " + amount + " where productId ='" + productId + "'";
+ s1.executeUpdate(q1);
+ s1.close();
+ Statement s2 = orderConnection.createStatement();
+ String q2 = "insert into Orders values ( '" + orderId + "', '" + productId + "', " + amount + " )";
+ s2.executeUpdate(q2);
+ s2.close();
+ inventoryConnection.close();
+ orderConnection.close();
+
+ }
+
+}
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/config/Config.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/config/Config.java
new file mode 100644
index 0000000000..c6ef83c4ca
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/config/Config.java
@@ -0,0 +1,68 @@
+package com.baeldung.atomikos.spring.config;
+
+import java.util.Properties;
+
+import javax.transaction.SystemException;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import org.springframework.transaction.jta.JtaTransactionManager;
+
+import com.atomikos.icatch.jta.UserTransactionManager;
+import com.atomikos.jdbc.AtomikosDataSourceBean;
+import com.baeldung.atomikos.spring.Application;
+
+@Configuration
+@EnableTransactionManagement
+public class Config {
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public AtomikosDataSourceBean inventoryDataSource() {
+ AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
+ dataSource.setLocalTransactionMode(true);
+ dataSource.setUniqueResourceName("db1");
+ dataSource.setXaDataSourceClassName("org.apache.derby.jdbc.EmbeddedXADataSource");
+ Properties xaProperties = new Properties();
+ xaProperties.put("databaseName", "db1");
+ xaProperties.put("createDatabase", "create");
+ dataSource.setXaProperties(xaProperties);
+ dataSource.setPoolSize(10);
+ return dataSource;
+ }
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public AtomikosDataSourceBean orderDataSource() {
+ AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
+ dataSource.setLocalTransactionMode(true);
+ dataSource.setUniqueResourceName("db2");
+ dataSource.setXaDataSourceClassName("org.apache.derby.jdbc.EmbeddedXADataSource");
+ Properties xaProperties = new Properties();
+ xaProperties.put("databaseName", "db2");
+ xaProperties.put("createDatabase", "create");
+ dataSource.setXaProperties(xaProperties);
+ dataSource.setPoolSize(10);
+ return dataSource;
+ }
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public UserTransactionManager userTransactionManager() throws SystemException {
+ UserTransactionManager userTransactionManager = new UserTransactionManager();
+ userTransactionManager.setTransactionTimeout(300);
+ userTransactionManager.setForceShutdown(true);
+ return userTransactionManager;
+ }
+
+ @Bean
+ public JtaTransactionManager jtaTransactionManager() throws SystemException {
+ JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
+ jtaTransactionManager.setTransactionManager(userTransactionManager());
+ jtaTransactionManager.setUserTransaction(userTransactionManager());
+ return jtaTransactionManager;
+ }
+
+ @Bean
+ public Application application() {
+ return new Application(inventoryDataSource(), orderDataSource());
+ }
+}
\ No newline at end of file
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/Application.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/Application.java
new file mode 100644
index 0000000000..cf1fef2cd8
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/Application.java
@@ -0,0 +1,48 @@
+package com.baeldung.atomikos.spring.jpa;
+
+import java.util.Set;
+import java.util.UUID;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baeldung.atomikos.spring.jpa.inventory.Inventory;
+import com.baeldung.atomikos.spring.jpa.inventory.InventoryRepository;
+import com.baeldung.atomikos.spring.jpa.order.Order;
+import com.baeldung.atomikos.spring.jpa.order.OrderRepository;
+
+public class Application {
+
+ @Autowired
+ private InventoryRepository inventoryRepository;
+
+ @Autowired
+ private OrderRepository orderRepository;
+
+ @Transactional(rollbackFor = Exception.class)
+ public void placeOrder(String productId, int amount) throws Exception {
+
+ String orderId = UUID.randomUUID()
+ .toString();
+ Inventory inventory = inventoryRepository.findOne(productId);
+ inventory.setBalance(inventory.getBalance() - amount);
+ inventoryRepository.save(inventory);
+ Order order = new Order();
+ order.setOrderId(orderId);
+ order.setProductId(productId);
+ order.setAmount(new Long(amount));
+ ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+ Validator validator = factory.getValidator();
+ Set> violations = validator.validate(order);
+ if (violations.size() > 0)
+ throw new Exception("Invalid instance of an order.");
+ orderRepository.save(order);
+
+ }
+
+}
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/config/Config.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/config/Config.java
new file mode 100644
index 0000000000..6716f19576
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/config/Config.java
@@ -0,0 +1,38 @@
+package com.baeldung.atomikos.spring.jpa.config;
+
+import javax.transaction.SystemException;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import org.springframework.transaction.jta.JtaTransactionManager;
+
+import com.atomikos.icatch.jta.UserTransactionManager;
+import com.baeldung.atomikos.spring.jpa.Application;
+
+@Configuration
+@EnableTransactionManagement
+public class Config {
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public UserTransactionManager userTransactionManager() throws SystemException {
+ UserTransactionManager userTransactionManager = new UserTransactionManager();
+ userTransactionManager.setTransactionTimeout(300);
+ userTransactionManager.setForceShutdown(true);
+ return userTransactionManager;
+ }
+
+ @Bean
+ public JtaTransactionManager transactionManager() throws SystemException {
+ JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
+ jtaTransactionManager.setTransactionManager(userTransactionManager());
+ jtaTransactionManager.setUserTransaction(userTransactionManager());
+ return jtaTransactionManager;
+ }
+
+ @Bean
+ public Application application() {
+ return new Application();
+ }
+
+}
\ No newline at end of file
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/Inventory.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/Inventory.java
new file mode 100644
index 0000000000..999879218c
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/Inventory.java
@@ -0,0 +1,31 @@
+package com.baeldung.atomikos.spring.jpa.inventory;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "INVENTORY")
+public class Inventory {
+
+ @Id
+ private String productId;
+ private Long balance;
+
+ public String getProductId() {
+ return productId;
+ }
+
+ public void setProductId(String productId) {
+ this.productId = productId;
+ }
+
+ public Long getBalance() {
+ return balance;
+ }
+
+ public void setBalance(Long balance) {
+ this.balance = balance;
+ }
+
+}
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/InventoryConfig.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/InventoryConfig.java
new file mode 100644
index 0000000000..5301ad6ff2
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/InventoryConfig.java
@@ -0,0 +1,53 @@
+package com.baeldung.atomikos.spring.jpa.inventory;
+
+import java.util.Properties;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+
+import com.atomikos.jdbc.AtomikosDataSourceBean;
+
+@Configuration
+@EnableJpaRepositories(basePackages = "com.baeldung.atomikos.spring.jpa.inventory", entityManagerFactoryRef = "inventoryEntityManager", transactionManagerRef = "transactionManager")
+public class InventoryConfig {
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public AtomikosDataSourceBean inventoryDataSource() {
+ AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
+ dataSource.setLocalTransactionMode(true);
+ dataSource.setUniqueResourceName("db1");
+ dataSource.setXaDataSourceClassName("org.apache.derby.jdbc.EmbeddedXADataSource");
+ Properties xaProperties = new Properties();
+ xaProperties.put("databaseName", "db1");
+ xaProperties.put("createDatabase", "create");
+ dataSource.setXaProperties(xaProperties);
+ dataSource.setPoolSize(10);
+ return dataSource;
+ }
+
+ @Bean
+ public EntityManagerFactory inventoryEntityManager() {
+ HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
+ LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
+ factory.setJpaVendorAdapter(vendorAdapter);
+ factory.setPackagesToScan("com.baeldung.atomikos.spring.jpa.inventory");
+ factory.setDataSource(inventoryDataSource());
+ Properties jpaProperties = new Properties();
+ //jpaProperties.put("hibernate.show_sql", "true");
+ //jpaProperties.put("hibernate.format_sql", "true");
+ jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyDialect");
+ jpaProperties.put("hibernate.current_session_context_class", "jta");
+ jpaProperties.put("javax.persistence.transactionType", "jta");
+ jpaProperties.put("hibernate.transaction.manager_lookup_class", "com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup");
+ jpaProperties.put("hibernate.hbm2ddl.auto", "create-drop");
+ factory.setJpaProperties(jpaProperties);
+ factory.afterPropertiesSet();
+ return factory.getObject();
+ }
+
+}
\ No newline at end of file
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/InventoryRepository.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/InventoryRepository.java
new file mode 100644
index 0000000000..c3868e51bf
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/InventoryRepository.java
@@ -0,0 +1,9 @@
+package com.baeldung.atomikos.spring.jpa.inventory;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface InventoryRepository extends JpaRepository {
+
+}
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/Order.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/Order.java
new file mode 100644
index 0000000000..4b9ae2dd1d
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/Order.java
@@ -0,0 +1,42 @@
+package com.baeldung.atomikos.spring.jpa.order;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.validation.constraints.Max;
+
+@Entity
+@Table(name = "ORDERS")
+public class Order {
+
+ @Id
+ private String orderId;
+ private String productId;
+ @Max(5)
+ private Long amount;
+
+ public String getOrderId() {
+ return orderId;
+ }
+
+ public void setOrderId(String orderId) {
+ this.orderId = orderId;
+ }
+
+ public String getProductId() {
+ return productId;
+ }
+
+ public void setProductId(String productId) {
+ this.productId = productId;
+ }
+
+ public Long getAmount() {
+ return amount;
+ }
+
+ public void setAmount(Long amount) {
+ this.amount = amount;
+ }
+
+}
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/OrderConfig.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/OrderConfig.java
new file mode 100644
index 0000000000..b4274bb64c
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/OrderConfig.java
@@ -0,0 +1,53 @@
+package com.baeldung.atomikos.spring.jpa.order;
+
+import java.util.Properties;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+
+import com.atomikos.jdbc.AtomikosDataSourceBean;
+
+@Configuration
+@EnableJpaRepositories(basePackages = "com.baeldung.atomikos.spring.jpa.order", entityManagerFactoryRef = "orderEntityManager", transactionManagerRef = "transactionManager")
+public class OrderConfig {
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public AtomikosDataSourceBean orderDataSource() {
+ AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
+ dataSource.setLocalTransactionMode(true);
+ dataSource.setUniqueResourceName("db2");
+ dataSource.setXaDataSourceClassName("org.apache.derby.jdbc.EmbeddedXADataSource");
+ Properties xaProperties = new Properties();
+ xaProperties.put("databaseName", "db2");
+ xaProperties.put("createDatabase", "create");
+ dataSource.setXaProperties(xaProperties);
+ dataSource.setPoolSize(10);
+ return dataSource;
+ }
+
+ @Bean
+ public EntityManagerFactory orderEntityManager() {
+ HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
+ LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
+ factory.setJpaVendorAdapter(vendorAdapter);
+ factory.setPackagesToScan("com.baeldung.atomikos.spring.jpa.order");
+ factory.setDataSource(orderDataSource());
+ Properties jpaProperties = new Properties();
+ //jpaProperties.put("hibernate.show_sql", "true");
+ //jpaProperties.put("hibernate.format_sql", "true");
+ jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyDialect");
+ jpaProperties.put("hibernate.current_session_context_class", "jta");
+ jpaProperties.put("javax.persistence.transactionType", "jta");
+ jpaProperties.put("hibernate.transaction.manager_lookup_class", "com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup");
+ jpaProperties.put("hibernate.hbm2ddl.auto", "create-drop");
+ factory.setJpaProperties(jpaProperties);
+ factory.afterPropertiesSet();
+ return factory.getObject();
+ }
+
+}
\ No newline at end of file
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/OrderRepository.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/OrderRepository.java
new file mode 100644
index 0000000000..2d5610ebca
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/OrderRepository.java
@@ -0,0 +1,9 @@
+package com.baeldung.atomikos.spring.jpa.order;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface OrderRepository extends JpaRepository {
+
+}
diff --git a/atomikos/src/main/resources/logback.xml b/atomikos/src/main/resources/logback.xml
new file mode 100644
index 0000000000..7d900d8ea8
--- /dev/null
+++ b/atomikos/src/main/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/atomikos/src/main/resources/schema.sql b/atomikos/src/main/resources/schema.sql
new file mode 100644
index 0000000000..5136ad1284
--- /dev/null
+++ b/atomikos/src/main/resources/schema.sql
@@ -0,0 +1,10 @@
+CREATE TABLE INVENTORY (
+ productId VARCHAR PRIMARY KEY,
+ balance INT
+);
+
+CREATE TABLE ORDERS (
+ orderId VARCHAR PRIMARY KEY,
+ productId VARCHAR,
+ amount INT NOT NULL CHECK (amount <= 5)
+);
\ No newline at end of file
diff --git a/atomikos/src/main/resources/transactions.properties b/atomikos/src/main/resources/transactions.properties
new file mode 100644
index 0000000000..8e027032fa
--- /dev/null
+++ b/atomikos/src/main/resources/transactions.properties
@@ -0,0 +1 @@
+com.atomikos.icatch.file=logs
\ No newline at end of file
diff --git a/atomikos/src/test/java/com/baeldung/atomikos/direct/ApplicationUnitTest.java b/atomikos/src/test/java/com/baeldung/atomikos/direct/ApplicationUnitTest.java
new file mode 100644
index 0000000000..1a467807ba
--- /dev/null
+++ b/atomikos/src/test/java/com/baeldung/atomikos/direct/ApplicationUnitTest.java
@@ -0,0 +1,118 @@
+package com.baeldung.atomikos.direct;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.atomikos.icatch.jta.UserTransactionImp;
+import com.atomikos.jdbc.AtomikosDataSourceBean;
+
+public class ApplicationUnitTest {
+
+ private static DataSource inventoryDataSource;
+ private static DataSource orderDataSource;
+
+ private static String productId = UUID.randomUUID()
+ .toString();
+
+ @Test
+ @Ignore
+ public void testPlaceOrderSuccess() throws Exception {
+ int amount = 1;
+ long initialBalance = getBalance(inventoryDataSource, productId);
+ Application application = new Application(inventoryDataSource, orderDataSource);
+ application.placeOrder(productId, amount);
+ long finalBalance = getBalance(inventoryDataSource, productId);
+ assertEquals(initialBalance - amount, finalBalance);
+ }
+
+ @Test
+ @Ignore
+ public void testPlaceOrderFailure() throws Exception {
+ int amount = 10;
+ long initialBalance = getBalance(inventoryDataSource, productId);
+ Application application = new Application(inventoryDataSource, orderDataSource);
+ application.placeOrder(productId, amount);
+ long finalBalance = getBalance(inventoryDataSource, productId);
+ assertEquals(initialBalance, finalBalance);
+ }
+
+ @BeforeClass
+ public static void setUp() throws SQLException {
+
+ inventoryDataSource = getDataSource("db1");
+ orderDataSource = getDataSource("db2");
+ Connection inventoryConnection = inventoryDataSource.getConnection();
+ Connection orderConnection = orderDataSource.getConnection();
+ String createInventoryTable = "create table Inventory ( " + " productId VARCHAR ( 100 ) PRIMARY KEY, balance INT )";
+ String createInventoryRow = "insert into Inventory values ( '" + productId + "', 10000 )";
+ Statement s1 = inventoryConnection.createStatement();
+ try {
+ s1.executeUpdate(createInventoryTable);
+ } catch (Exception e) {
+ System.out.println("Inventory table exists");
+ }
+ try {
+ s1.executeUpdate(createInventoryRow);
+ } catch (Exception e) {
+ System.out.println("Product row exists");
+ }
+ s1.close();
+ String createOrderTable = "create table Orders ( orderId VARCHAR ( 100 ) PRIMARY KEY, productId VARCHAR ( 100 ), amount INT NOT NULL CHECK (amount <= 5) )";
+ Statement s2 = orderConnection.createStatement();
+ try {
+ s2.executeUpdate(createOrderTable);
+ } catch (Exception e) {
+ System.out.println("Orders table exists");
+ }
+ s2.close();
+ inventoryConnection.close();
+ orderConnection.close();
+ }
+
+ private static DataSource getDataSource(String db) {
+
+ DataSource ds;
+ AtomikosDataSourceBean ads = new AtomikosDataSourceBean();
+ ads.setXaDataSourceClassName("org.apache.derby.jdbc.EmbeddedXADataSource");
+ Properties properties = new Properties();
+ properties.put("databaseName", db);
+ properties.put("createDatabase", "create");
+ ads.setXaProperties(properties);
+ ads.setUniqueResourceName(db);
+ ads.setPoolSize(10); // optional
+ ads.setBorrowConnectionTimeout(10); // optional
+ ds = ads;
+ return ds;
+
+ }
+
+ private static long getBalance(DataSource inventoryDataSource, String productId) throws Exception {
+
+ UserTransactionImp utx = new UserTransactionImp();
+ utx.begin();
+ Connection inventoryConnection = inventoryDataSource.getConnection();
+ Statement s1 = inventoryConnection.createStatement();
+ String q1 = "select balance from Inventory where productId='" + productId + "'";
+ ResultSet rs1 = s1.executeQuery(q1);
+ if (rs1 == null || !rs1.next())
+ throw new Exception("Product not found: " + productId);
+ long balance = rs1.getLong(1);
+ inventoryConnection.close();
+ utx.commit();
+ return balance;
+
+ }
+
+}
diff --git a/atomikos/src/test/java/com/baeldung/atomikos/spring/ApplicationUnitTest.java b/atomikos/src/test/java/com/baeldung/atomikos/spring/ApplicationUnitTest.java
new file mode 100644
index 0000000000..0c9392eac4
--- /dev/null
+++ b/atomikos/src/test/java/com/baeldung/atomikos/spring/ApplicationUnitTest.java
@@ -0,0 +1,108 @@
+package com.baeldung.atomikos.spring;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import com.baeldung.atomikos.spring.config.Config;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = { Config.class })
+public class ApplicationUnitTest {
+
+ private static String productId = UUID.randomUUID()
+ .toString();
+
+ @Autowired
+ Application application;
+
+ @Autowired
+ DataSource inventoryDataSource;
+
+ @Autowired
+ DataSource orderDataSource;
+
+ @Test
+ @Ignore
+ public void testPlaceOrderSuccess() throws Exception {
+ int amount = 1;
+ long initialBalance = getBalance(inventoryDataSource, productId);
+ application.placeOrder(productId, amount);
+ long finalBalance = getBalance(inventoryDataSource, productId);
+ assertEquals(initialBalance - amount, finalBalance);
+ }
+
+ @Test
+ @Ignore
+ public void testPlaceOrderFailure() throws Exception {
+ int amount = 10;
+ long initialBalance = getBalance(inventoryDataSource, productId);
+ try {
+ application.placeOrder(productId, amount);
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+ long finalBalance = getBalance(inventoryDataSource, productId);
+ assertEquals(initialBalance, finalBalance);
+ }
+
+ @Before
+ public void setUp() throws SQLException {
+
+ Connection inventoryConnection = inventoryDataSource.getConnection();
+ Connection orderConnection = orderDataSource.getConnection();
+ String createInventoryTable = "create table Inventory ( " + " productId VARCHAR ( 100 ) PRIMARY KEY, balance INT )";
+ String createInventoryRow = "insert into Inventory values ( '" + productId + "', 10000 )";
+ Statement s1 = inventoryConnection.createStatement();
+ try {
+ s1.executeUpdate(createInventoryTable);
+ } catch (Exception e) {
+ System.out.println("Inventory table exists");
+ }
+ try {
+ s1.executeUpdate(createInventoryRow);
+ } catch (Exception e) {
+ System.out.println("Product row exists");
+ }
+ s1.close();
+ String createOrderTable = "create table Orders ( orderId VARCHAR ( 100 ) PRIMARY KEY, productId VARCHAR ( 100 ), amount INT NOT NULL CHECK (amount <= 5) )";
+ Statement s2 = orderConnection.createStatement();
+ try {
+ s2.executeUpdate(createOrderTable);
+ } catch (Exception e) {
+ System.out.println("Orders table exists");
+ }
+ s2.close();
+ inventoryConnection.close();
+ orderConnection.close();
+ }
+
+ private static long getBalance(DataSource inventoryDataSource, String productId) throws Exception {
+
+ Connection inventoryConnection = inventoryDataSource.getConnection();
+ Statement s1 = inventoryConnection.createStatement();
+ String q1 = "select balance from Inventory where productId='" + productId + "'";
+ ResultSet rs1 = s1.executeQuery(q1);
+ if (rs1 == null || !rs1.next())
+ throw new Exception("Product not found: " + productId);
+ long balance = rs1.getLong(1);
+ inventoryConnection.close();
+ return balance;
+
+ }
+
+}
diff --git a/atomikos/src/test/java/com/baeldung/atomikos/spring/jpa/ApplicationUnitTest.java b/atomikos/src/test/java/com/baeldung/atomikos/spring/jpa/ApplicationUnitTest.java
new file mode 100644
index 0000000000..e6a3c1982c
--- /dev/null
+++ b/atomikos/src/test/java/com/baeldung/atomikos/spring/jpa/ApplicationUnitTest.java
@@ -0,0 +1,80 @@
+package com.baeldung.atomikos.spring.jpa;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.sql.SQLException;
+import java.util.UUID;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import com.baeldung.atomikos.spring.jpa.config.Config;
+import com.baeldung.atomikos.spring.jpa.inventory.Inventory;
+import com.baeldung.atomikos.spring.jpa.inventory.InventoryConfig;
+import com.baeldung.atomikos.spring.jpa.inventory.InventoryRepository;
+import com.baeldung.atomikos.spring.jpa.order.OrderConfig;
+import com.baeldung.atomikos.spring.jpa.order.OrderRepository;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = { Config.class, InventoryConfig.class, OrderConfig.class })
+public class ApplicationUnitTest {
+
+ private static String productId = UUID.randomUUID()
+ .toString();
+
+ @Autowired
+ Application application;
+
+ @Autowired
+ InventoryRepository inventoryRepository;
+
+ @Autowired
+ OrderRepository orderRepository;
+
+ @Test
+ @Ignore
+ public void testPlaceOrderSuccess() throws Exception {
+ int amount = 1;
+ long initialBalance = getBalance(inventoryRepository, productId);
+ application.placeOrder(productId, amount);
+ long finalBalance = getBalance(inventoryRepository, productId);
+ assertEquals(initialBalance - amount, finalBalance);
+ }
+
+ @Test
+ @Ignore
+ public void testPlaceOrderFailure() throws Exception {
+ int amount = 10;
+ long initialBalance = getBalance(inventoryRepository, productId);
+ try {
+ application.placeOrder(productId, amount);
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+ long finalBalance = getBalance(inventoryRepository, productId);
+ assertEquals(initialBalance, finalBalance);
+ }
+
+ @Before
+ public void setUp() throws SQLException {
+
+ Inventory inventory = new Inventory();
+ inventory.setProductId(productId);
+ inventory.setBalance(new Long(10000));
+ inventoryRepository.save(inventory);
+
+ }
+
+ private static long getBalance(InventoryRepository inventoryRepository, String productId) throws Exception {
+
+ return inventoryRepository.findOne(productId)
+ .getBalance();
+
+ }
+
+}
diff --git a/atomikos/src/test/resources/logback.xml b/atomikos/src/test/resources/logback.xml
new file mode 100644
index 0000000000..7d900d8ea8
--- /dev/null
+++ b/atomikos/src/test/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/atomikos/src/test/resources/transactions.properties b/atomikos/src/test/resources/transactions.properties
new file mode 100644
index 0000000000..8e027032fa
--- /dev/null
+++ b/atomikos/src/test/resources/transactions.properties
@@ -0,0 +1 @@
+com.atomikos.icatch.file=logs
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 8d4632fb3e..8a8b8e1b55 100644
--- a/pom.xml
+++ b/pom.xml
@@ -564,6 +564,8 @@
rxjava-libraries
rxjava-observables
rxjava-operators
+
+ atomikos
@@ -1073,6 +1075,8 @@
rxjava-libraries
rxjava-observables
rxjava-operators
+
+ atomikos