Merge branch 'master' of https://github.com/eugenp/tutorials into BAEL-3860

This commit is contained in:
mthomas
2020-04-14 06:44:48 -05:00
491 changed files with 9408 additions and 2307 deletions
-1
View File
@@ -13,6 +13,5 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
- [Checking if a Java Graph has a Cycle](https://www.baeldung.com/java-graph-has-a-cycle)
- [A Guide to the Folding Technique in Java](https://www.baeldung.com/folding-hashing-technique)
- [Creating a Triangle with for Loops in Java](https://www.baeldung.com/java-print-triangle)
- [Efficient Word Frequency Calculator in Java](https://www.baeldung.com/java-word-frequency)
- [The K-Means Clustering Algorithm in Java](https://www.baeldung.com/java-k-means-clustering-algorithm)
- More articles: [[<-- prev]](/algorithms-miscellaneous-2) [[next -->]](/algorithms-miscellaneous-4)
+4
View File
@@ -0,0 +1,4 @@
### Relevant Articles:
- [Boruvka’s Algorithm for Minimum Spanning Trees](https://www.baeldung.com/java-boruvka-algorithm)
- [Gradient Descent in Java](https://www.baeldung.com/java-gradient-descent)
-3
View File
@@ -1,3 +0,0 @@
### Relevant Articles:
- [Intro to OData with Olingo](https://www.baeldung.com/olingo)
+7
View File
@@ -0,0 +1,7 @@
## Atomikos
This module contains articles about Atomikos
### Relevant Articles:
- [Guide Transactions Using Atomikos]()
+119
View File
@@ -0,0 +1,119 @@
<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>atomikos</artifactId>
<name>atomikos</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<version>${atomikos-version}</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jms</artifactId>
<version>${atomikos-version}</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-hibernate4</artifactId>
<version>${atomikos-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.11.23.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>5.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.8.1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- the JTA API -->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jta_1.0.1B_spec</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.2.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
</dependency>
</dependencies>
<properties>
<atomikos-version>5.0.6</atomikos-version>
<spring-version>5.1.6.RELEASE</spring-version>
<hibernate.version>5.4.3.Final</hibernate.version>
</properties>
</project>
@@ -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();
}
}
}
@@ -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();
}
}
@@ -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());
}
}
@@ -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<ConstraintViolation<Order>> violations = validator.validate(order);
if (violations.size() > 0)
throw new Exception("Invalid instance of an order.");
orderRepository.save(order);
}
}
@@ -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();
}
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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<Inventory, String> {
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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<Order, String> {
}
+10
View File
@@ -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)
);
@@ -0,0 +1 @@
com.atomikos.icatch.file=logs
@@ -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;
}
}
@@ -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;
}
}
@@ -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();
}
}
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@@ -0,0 +1 @@
com.atomikos.icatch.file=logs
+6 -2
View File
@@ -11,11 +11,15 @@
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-1</artifactId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-1</relativePath>
<relativePath>../../parent-boot-2</relativePath>
</parent>
<properties>
<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
@@ -1,91 +0,0 @@
package com.baeldung.cassecuredapp;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
import org.jasig.cas.client.validation.Cas30ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.context.event.EventListener;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import javax.servlet.http.HttpSessionEvent;
@SpringBootApplication
public class CasSecuredAppApplication {
public static void main(String[] args) {
SpringApplication.run(CasSecuredAppApplication.class, args);
}
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService("http://localhost:9000/login/cas");
serviceProperties.setSendRenew(false);
return serviceProperties;
}
@Bean
@Primary
public AuthenticationEntryPoint authenticationEntryPoint(ServiceProperties sP) {
CasAuthenticationEntryPoint entryPoint = new CasAuthenticationEntryPoint();
entryPoint.setLoginUrl("https://localhost:6443/cas/login");
entryPoint.setServiceProperties(sP);
return entryPoint;
}
@Bean
public TicketValidator ticketValidator() {
return new Cas30ServiceTicketValidator("https://localhost:6443/cas");
}
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider provider = new CasAuthenticationProvider();
provider.setServiceProperties(serviceProperties());
provider.setTicketValidator(ticketValidator());
provider.setUserDetailsService((s) -> new User("[email protected]", "smatt",
true, true, true, true,
AuthorityUtils.createAuthorityList("ROLE_ADMIN")));
provider.setKey("CAS_PROVIDER_LOCALHOST_9000");
return provider;
}
@Bean
public SecurityContextLogoutHandler securityContextLogoutHandler() {
return new SecurityContextLogoutHandler();
}
@Bean
public LogoutFilter logoutFilter() {
LogoutFilter logoutFilter = new LogoutFilter(
"https://localhost:6443/cas/logout", securityContextLogoutHandler());
logoutFilter.setFilterProcessesUrl("/logout/cas");
return logoutFilter;
}
@Bean
public SingleSignOutFilter singleSignOutFilter() {
SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
singleSignOutFilter.setCasServerUrlPrefix("https://localhost:6443/cas");
singleSignOutFilter.setIgnoreInitConfiguration(true);
return singleSignOutFilter;
}
@EventListener
public SingleSignOutHttpSessionListener singleSignOutHttpSessionListener(HttpSessionEvent event) {
return new SingleSignOutHttpSessionListener();
}
}
@@ -0,0 +1,97 @@
package com.baeldung.cassecuredapp;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
import org.jasig.cas.client.validation.Cas30ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import javax.servlet.http.HttpSessionEvent;
@SpringBootApplication
public class CasSecuredApplication {
private static final Logger logger = LoggerFactory.getLogger(CasSecuredApplication.class);
public static void main(String... args) {
SpringApplication.run(CasSecuredApplication.class, args);
}
@Bean
public CasAuthenticationFilter casAuthenticationFilter(
AuthenticationManager authenticationManager,
ServiceProperties serviceProperties) throws Exception {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager);
filter.setServiceProperties(serviceProperties);
return filter;
}
@Bean
public ServiceProperties serviceProperties() {
logger.info("service properties");
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService("http://cas-client:8900/login/cas");
serviceProperties.setSendRenew(false);
return serviceProperties;
}
@Bean
public TicketValidator ticketValidator() {
return new Cas30ServiceTicketValidator("https://localhost:8443");
}
@Bean
public CasAuthenticationProvider casAuthenticationProvider(
TicketValidator ticketValidator,
ServiceProperties serviceProperties) {
CasAuthenticationProvider provider = new CasAuthenticationProvider();
provider.setServiceProperties(serviceProperties);
provider.setTicketValidator(ticketValidator);
provider.setUserDetailsService(
s -> new User("[email protected]", "Mellon", true, true, true, true,
AuthorityUtils.createAuthorityList("ROLE_ADMIN")));
provider.setKey("CAS_PROVIDER_LOCALHOST_8900");
return provider;
}
@Bean
public SecurityContextLogoutHandler securityContextLogoutHandler() {
return new SecurityContextLogoutHandler();
}
@Bean
public LogoutFilter logoutFilter() {
LogoutFilter logoutFilter = new LogoutFilter("https://localhost:8443/logout", securityContextLogoutHandler());
logoutFilter.setFilterProcessesUrl("/logout/cas");
return logoutFilter;
}
@Bean
public SingleSignOutFilter singleSignOutFilter() {
SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
singleSignOutFilter.setCasServerUrlPrefix("https://localhost:8443");
singleSignOutFilter.setLogoutCallbackPath("/exit/cas");
singleSignOutFilter.setIgnoreInitConfiguration(true);
return singleSignOutFilter;
}
}
@@ -1,83 +0,0 @@
package com.baeldung.cassecuredapp.config;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import java.util.Arrays;
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private AuthenticationProvider authenticationProvider;
private AuthenticationEntryPoint authenticationEntryPoint;
private SingleSignOutFilter singleSignOutFilter;
private LogoutFilter logoutFilter;
@Autowired
public SecurityConfig(CasAuthenticationProvider casAuthenticationProvider, AuthenticationEntryPoint eP,
LogoutFilter lF
, SingleSignOutFilter ssF
) {
this.authenticationProvider = casAuthenticationProvider;
this.authenticationEntryPoint = eP;
this.logoutFilter = lF;
this.singleSignOutFilter = ssF;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.regexMatchers("/secured.*", "/login")
.authenticated()
.and()
.authorizeRequests()
.regexMatchers("/")
.permitAll()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.logout().logoutSuccessUrl("/logout")
.and()
.addFilterBefore(singleSignOutFilter, CasAuthenticationFilter.class)
.addFilterBefore(logoutFilter, LogoutFilter.class);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return new ProviderManager(Arrays.asList(authenticationProvider));
}
@Bean
public CasAuthenticationFilter casAuthenticationFilter(ServiceProperties sP) throws Exception {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setServiceProperties(sP);
filter.setAuthenticationManager(authenticationManager());
return filter;
}
}
@@ -0,0 +1,79 @@
package com.baeldung.cassecuredapp.config;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.validation.Cas30ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import java.util.Collections;
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class);
private SingleSignOutFilter singleSignOutFilter;
private LogoutFilter logoutFilter;
private CasAuthenticationProvider casAuthenticationProvider;
private ServiceProperties serviceProperties;
@Autowired
public WebSecurityConfig(SingleSignOutFilter singleSignOutFilter, LogoutFilter logoutFilter,
CasAuthenticationProvider casAuthenticationProvider,
ServiceProperties serviceProperties) {
this.logoutFilter = logoutFilter;
this.singleSignOutFilter = singleSignOutFilter;
this.serviceProperties = serviceProperties;
this.casAuthenticationProvider = casAuthenticationProvider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers( "/secured", "/login").authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
.and()
.addFilterBefore(singleSignOutFilter, CasAuthenticationFilter.class)
.addFilterBefore(logoutFilter, LogoutFilter.class)
.csrf().ignoringAntMatchers("/exit/cas");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(casAuthenticationProvider);
}
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return new ProviderManager(Collections.singletonList(casAuthenticationProvider));
}
public AuthenticationEntryPoint authenticationEntryPoint() {
CasAuthenticationEntryPoint entryPoint = new CasAuthenticationEntryPoint();
entryPoint.setLoginUrl("https://localhost:8443/login");
entryPoint.setServiceProperties(serviceProperties);
return entryPoint;
}
}
@@ -1,7 +1,7 @@
package com.baeldung.cassecuredapp.controllers;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
@@ -13,24 +13,27 @@ import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY;
@Controller
public class AuthController {
private Logger logger = LogManager.getLogger(AuthController.class);
@GetMapping("/logout")
public String logout(
HttpServletRequest request, HttpServletResponse response, SecurityContextLogoutHandler logoutHandler) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
logoutHandler.logout(request, response, auth );
new CookieClearingLogoutHandler(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY).logout(request, response, auth);
return "auth/logout";
}
private Logger logger = LoggerFactory.getLogger(AuthController.class);
@GetMapping("/login")
public String login() {
logger.info("/login called");
return "redirect:/secured";
}
@GetMapping("/logout")
public String logout(HttpServletRequest request, HttpServletResponse response, SecurityContextLogoutHandler logoutHandler) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
CookieClearingLogoutHandler cookieClearingLogoutHandler = new CookieClearingLogoutHandler(SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY);
cookieClearingLogoutHandler.logout(request, response, auth);
logoutHandler.logout(request, response, auth);
return "auth/logout";
}
}

Some files were not shown because too many files have changed in this diff Show More