Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions spring/narayana-spring-boot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,15 @@ Usage

In your terminal navigate to the quickstart directory and execute one of the following scenarios:

* Commit demonstration
* Commit and rollback demonstration

mvn clean spring-boot:run -Drun.arguments="commit,Test Value"
mvn clean spring-boot:run -Dspring-boot.run.arguments="commit Test-Value"

* Rollback demonstration

mvn clean spring-boot:run -Drun.arguments="rollback,Test Value"
mvn clean spring-boot:run -Dspring-boot.run.arguments="rollback Test-Value"

* System crash and recovery demonstration

mvn clean spring-boot:run -Drun.arguments="crash,Test Value"
mvn clean spring-boot:run -Dspring-boot.run.arguments="crash Test-Value"

mvn spring-boot:run -Drun.arguments="recovery"
mvn spring-boot:run -Dspring-boot.run.arguments="recovery"

32 changes: 8 additions & 24 deletions spring/narayana-spring-boot/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,23 @@
</dependencyManagement>

<dependencies>
<!-- spring-boot-starter-data-jpa includes hibernate-core -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- javassist dependency updates javassist version 3.22.0-GA included in hibernate-core -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.25.0-GA</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-artemis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-narayana</artifactId>
<groupId>dev.snowdrop</groupId>
<artifactId>narayana-spring-boot-core</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>dev.snowdrop</groupId>
<artifactId>narayana-spring-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
Expand All @@ -80,20 +79,6 @@
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-jms-server</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand All @@ -110,7 +95,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${version.surefire.plugin}</version>
<configuration>
<skip>false</skip>
<argLine>${modular.jdk.args}</argLine>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@
/**
* @author <a href="mailto:[email protected]">Gytis Trikleris</a>
*/
public interface EntriesRepository extends JpaRepository<Entry, Long> {

interface EntriesRepository extends JpaRepository<Entry, Integer> {
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,42 @@
package org.jboss.narayana.quickstart.spring;

import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import jakarta.transaction.Transactional;
import java.util.List;

/**
* Service to store entries in the database.
*
* @author <a href="mailto:[email protected]">Gytis Trikleris</a>
*/
@Service
@Transactional
public class EntriesService {

private final Logger logger = LoggerFactory.getLogger(EntriesService.class);
private final EntriesRepository entriesRepository;

@Autowired
public EntriesService(EntriesRepository entriesRepository) {
this.entriesRepository = entriesRepository;
}

public Entry create(String value) {
System.out.println("Creating entry '" + value + "'");
@Transactional
public Entry createEntry(String value) {
this.logger.info("Creating entry '{}'", value);
return this.entriesRepository.save(new Entry(value));
}

return entriesRepository.save(new Entry(value));
public List<Entry> getEntries() {
List<Entry> entries = this.entriesRepository.findAll();
this.logger.info("Returning entries '{}'", entries);
return entries;
}

public List<Entry> getAll() {
return entriesRepository.findAll();
public void clearEntries() {
this.entriesRepository.deleteAll();
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.jboss.narayana.quickstart.spring;

import java.util.Objects;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
Expand All @@ -14,22 +16,38 @@ public class Entry {
@GeneratedValue
private Long id;

private String value;
private String val;

Entry() {

}

public Entry(String value) {
this.value = value;
public Entry(String val) {
this.val = val;
}

public String getValue() {
return value;
public String getVal() {
return this.val;
}

@Override
public String toString() {
return "Entry{id=" + id + ", value='" + value + "'}";
return "Entry{id=" + this.id + ", value='" + this.val + "'}";
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Entry entry = (Entry) o;
return Objects.equals(this.id, entry.id) && Objects.equals(this.val, entry.val);
}

@Override
public int hashCode() {
return Objects.hash(this.id, this.val);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package org.jboss.narayana.quickstart.spring;

import org.springframework.beans.factory.annotation.Autowired;
import java.util.LinkedList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;

Expand All @@ -12,18 +17,35 @@
* @author <a href="mailto:[email protected]">Gytis Trikleris</a>
*/
@Service
@Transactional
public class MessagesService {

public final static String QUEUE_NAME = "test-messages";
private final Logger logger = LoggerFactory.getLogger(MessagesService.class);
private final List<String> receivedMessages = new LinkedList<>();
private final JmsTemplate jmsTemplate;

@Autowired
public MessagesService(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}

public void send(String message) {
jmsTemplate.convertAndSend(MessagesListener.QUEUE_NAME, message);
@Transactional
public void sendMessage(String message) {
this.logger.info("Sending message '{}' to '{}' queue", message, QUEUE_NAME);
this.jmsTemplate.convertAndSend(QUEUE_NAME, message);
}

public List<String> getReceivedMessages() {
this.logger.info("Returning received messages '{}'", this.receivedMessages);
return this.receivedMessages;
}

public void clearReceivedMessages() {
this.receivedMessages.clear();
}

@JmsListener(destination = QUEUE_NAME)
public void onMessage(String message) {
this.logger.info("Received message '{}'", message);
this.receivedMessages.add(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.jta.narayana.DbcpXADataSourceWrapper;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;

import java.io.Closeable;
import dev.snowdrop.boot.narayana.autoconfigure.NarayanaAutoConfiguration;

/**
* Main Spring Boot application class.
*
* @author <a href="mailto:[email protected]">Gytis Trikleris</a>
*/
@SpringBootApplication
@Import(DbcpXADataSourceWrapper.class)
@Import(NarayanaAutoConfiguration.class)
public class QuickstartApplication {

public static final Object TO_WAIT = new Object();
Expand All @@ -26,7 +25,7 @@ public static void main(String[] args) throws Exception {
throw new IllegalArgumentException("Invalid arguments provided. See README.md for usage examples");
}

ApplicationContext context = SpringApplication.run(QuickstartApplication.class, args);
ConfigurableApplicationContext context = SpringApplication.run(QuickstartApplication.class, args);
QuickstartService quickstartService = context.getBean(QuickstartService.class);

switch (CompleteAction.valueOf(args[0].toUpperCase())) {
Expand All @@ -45,12 +44,18 @@ public static void main(String[] args) throws Exception {
case RECOVERY:
quickstartService.demonstrateRecovery();
}

((Closeable) context).close();
context.close();
}

public enum CompleteAction {
COMMIT, ROLLBACK, CRASH, RECOVERY

COMMIT("COMMIT"), ROLLBACK("ROLLBACK"), CRASH("CRASH"), RECOVERY("RECOVERY");

public final String label;

private CompleteAction(String label) {
this.label = label;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

import jakarta.transaction.TransactionManager;
import javax.transaction.xa.XAResource;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
Expand Down Expand Up @@ -64,11 +67,13 @@ public void demonstrateCrash(String entry) throws Exception {
* @throws Exception
*/
public void demonstrateRecovery() throws Exception {
List<Entry> entriesBefore = entriesService.getAll();
Iterable<Entry> entriesBefore = entriesService.getEntries();
System.out.println("Entries at the start: " + entriesBefore);
recoveryManagerService.addXAResourceRecovery(new DummyXAResourceRecovery());
waitForRecovery(entriesBefore);
System.out.println("Entries at the end: " + entriesService.getAll());
List<Entry> target = new ArrayList<>();
entriesBefore.forEach(target::add);
waitForRecovery(target);
System.out.println("Entries at the end: " + entriesService.getEntries());
}

/**
Expand All @@ -80,17 +85,17 @@ public void demonstrateRecovery() throws Exception {
* @throws Exception
*/
private void executeDemonstration(String entry, TransactionTerminator terminator, XAResource xaResource) throws Exception {
System.out.println("Entries at the start: " + entriesService.getAll());
System.out.println("Entries at the start: " + entriesService.getEntries());

transactionManager.begin();
if (xaResource != null) {
transactionManager.getTransaction().enlistResource(xaResource);
}
entriesService.create(entry);
messagesService.send("Created entry '" + entry + "'");
entriesService.createEntry(entry);
messagesService.sendMessage("Created entry '" + entry + "'");
terminator.terminate();

System.out.println("Entries at the end: " + entriesService.getAll());
System.out.println("Entries at the end: " + entriesService.getEntries());
}

/**
Expand All @@ -104,7 +109,7 @@ private void waitForRecovery(List<Entry> entriesBefore) throws Exception {

for (int i = 0; i < 3 && !isComplete; i++) {
sleep(5000);
isComplete = entriesBefore.size() < entriesService.getAll().size();
isComplete = entriesBefore.size() < ((Collection<?>) entriesService.getEntries()).size();
}

if (isComplete) {
Expand Down
Loading