Initial commit.
This commit is contained in:
24
reactor-app/build.gradle.kts
Normal file
24
reactor-app/build.gradle.kts
Normal file
@@ -0,0 +1,24 @@
|
||||
plugins {
|
||||
id("java")
|
||||
id("org.springframework.boot")
|
||||
id("io.spring.dependency-management")
|
||||
}
|
||||
|
||||
group = "com.zeenea.experiments.virtualthreads.reactorapp"
|
||||
version = "0.0.1-SNAPSHOT"
|
||||
|
||||
dependencies {
|
||||
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
runtimeOnly("org.postgresql:postgresql")
|
||||
compileOnly("org.projectlombok:lombok")
|
||||
annotationProcessor("org.projectlombok:lombok")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
testImplementation("io.projectreactor:reactor-test")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.configuration;
|
||||
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
|
||||
@Configuration
|
||||
@EnableJpaRepositories("com.zeenea.experiments.virtualthreads.reactorapp.infrastructure")
|
||||
@EntityScan("com.zeenea.experiments.virtualthreads.reactorapp.infrastructure")
|
||||
public class JpaConfiguration {}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog.model.Catalog;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog.port.CatalogPort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class CatalogService {
|
||||
private final CatalogPort catalogPort;
|
||||
|
||||
public CatalogService(CatalogPort catalogPort) {
|
||||
this.catalogPort = catalogPort;
|
||||
}
|
||||
|
||||
public Mono<Catalog> getById(UUID catalogId) {
|
||||
return catalogPort.getById(catalogId);
|
||||
}
|
||||
|
||||
public Flux<Catalog> getAll() {
|
||||
return catalogPort.getAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog.model;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record Catalog(UUID id, String name) {}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog.port;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog.model.Catalog;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface CatalogPort {
|
||||
Mono<Catalog> getById(UUID catalogId);
|
||||
Flux<Catalog> getAll();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.domain.item;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.item.model.Item;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.item.port.ItemPort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
@Service
|
||||
public class ItemService {
|
||||
private final ItemPort itemPort;
|
||||
|
||||
public ItemService(ItemPort itemPort) {
|
||||
this.itemPort = itemPort;
|
||||
}
|
||||
|
||||
public Flux<Item> getAllItems() {
|
||||
return itemPort.getAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.domain.item.model;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
public record Item(
|
||||
UUID id,
|
||||
String name,
|
||||
ZonedDateTime sharedDate
|
||||
) {
|
||||
public boolean isShared() {
|
||||
return sharedDate != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.domain.item.port;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.item.model.Item;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
public interface ItemPort {
|
||||
Flux<Item> getAll();
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.domain.marketplace;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog.CatalogService;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog.model.Catalog;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.item.ItemService;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.item.model.Item;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.marketplace.model.Marketplace;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class MarketplaceService {
|
||||
private final CatalogService catalogService;
|
||||
private final ItemService itemService;
|
||||
|
||||
public MarketplaceService(CatalogService catalogService, ItemService itemService) {
|
||||
this.catalogService = catalogService;
|
||||
this.itemService = itemService;
|
||||
}
|
||||
|
||||
public Mono<Marketplace> getMarketplace() {
|
||||
Mono<List<Catalog>> catalogListMono = catalogService.getAll().collectList();
|
||||
Mono<List<Item>> sharedItemListMono = itemService.getAllItems()
|
||||
.filter(Item::isShared)
|
||||
.collectList();
|
||||
return Mono.zip(catalogListMono, sharedItemListMono)
|
||||
.map(tuple -> {
|
||||
List<Catalog> catalogs = tuple.getT1();
|
||||
List<Item> items = tuple.getT2();
|
||||
return new Marketplace(catalogs, items);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.domain.marketplace.model;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog.model.Catalog;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.item.model.Item;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record Marketplace(
|
||||
List<Catalog> catalogs,
|
||||
List<Item> sharedItems
|
||||
) {}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.exposition.catalog;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog.CatalogService;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.exposition.catalog.model.CatalogDto;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/catalogs")
|
||||
public class CatalogController {
|
||||
private final CatalogService catalogService;
|
||||
|
||||
public CatalogController(CatalogService catalogService) {
|
||||
this.catalogService = catalogService;
|
||||
}
|
||||
|
||||
@GetMapping("/{catalogId}")
|
||||
public Mono<CatalogDto> getById(@PathVariable("catalogId") UUID catalogId) {
|
||||
return catalogService.getById(catalogId)
|
||||
.map(CatalogDto::new);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.exposition.catalog.model;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog.model.Catalog;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record CatalogDto(
|
||||
UUID id,
|
||||
String name
|
||||
) {
|
||||
public CatalogDto(Catalog catalog) {
|
||||
this(catalog.id(), catalog.name());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.exposition.marketplace;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.marketplace.MarketplaceService;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.exposition.marketplace.model.MarketplaceDto;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/marketplace")
|
||||
public class MarketplaceController {
|
||||
private final MarketplaceService marketplaceService;
|
||||
|
||||
public MarketplaceController(MarketplaceService marketplaceService) {
|
||||
this.marketplaceService = marketplaceService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public Mono<MarketplaceDto> getMarketplace() {
|
||||
return marketplaceService.getMarketplace()
|
||||
.map(MarketplaceDto::new);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.exposition.marketplace.model;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.item.model.Item;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record ItemDto(
|
||||
UUID id,
|
||||
String name,
|
||||
Boolean isShared
|
||||
) {
|
||||
public ItemDto(Item item) {
|
||||
this(item.id(), item.name(), item.isShared());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.exposition.marketplace.model;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.marketplace.model.Marketplace;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.exposition.catalog.model.CatalogDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record MarketplaceDto(List<CatalogDto> catalogs, List<ItemDto> sharedItems) {
|
||||
public MarketplaceDto(Marketplace marketplace) {
|
||||
this(
|
||||
marketplace.catalogs().stream().map(CatalogDto::new).toList(),
|
||||
marketplace.sharedItems().stream().map(ItemDto::new).toList()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.infrastructure.catalog;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog.model.Catalog;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog.port.CatalogPort;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.infrastructure.catalog.model.CatalogJpaEntity;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.infrastructure.catalog.repository.CatalogJpaRepository;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Component
|
||||
public class CatalogJpaAdapter implements CatalogPort {
|
||||
private final CatalogJpaRepository catalogJpaRepository;
|
||||
|
||||
public CatalogJpaAdapter(CatalogJpaRepository catalogJpaRepository) {
|
||||
this.catalogJpaRepository = catalogJpaRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Catalog> getById(UUID catalogId) {
|
||||
return Mono.fromCallable(() -> catalogJpaRepository.findById(catalogId))
|
||||
.subscribeOn(Schedulers.boundedElastic())
|
||||
.flatMap(result -> result.map(Mono::just).orElseGet(Mono::empty))
|
||||
.map(CatalogJpaEntity::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Catalog> getAll() {
|
||||
return Mono.fromCallable(catalogJpaRepository::findAll)
|
||||
.subscribeOn(Schedulers.boundedElastic())
|
||||
.flatMapMany(Flux::fromIterable)
|
||||
.map(CatalogJpaEntity::toDomain);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.infrastructure.catalog.model;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.catalog.model.Catalog;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "catalog")
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class CatalogJpaEntity {
|
||||
@Id
|
||||
private UUID id;
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
public CatalogJpaEntity(Catalog catalog) {
|
||||
id = catalog.id();
|
||||
name = catalog.name();
|
||||
}
|
||||
|
||||
public Catalog toDomain() {
|
||||
return new Catalog(id, name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.infrastructure.catalog.repository;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.infrastructure.catalog.model.CatalogJpaEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface CatalogJpaRepository extends JpaRepository<CatalogJpaEntity, UUID> {
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.infrastructure.item;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.item.model.Item;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.item.port.ItemPort;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.infrastructure.item.model.ItemJpaEntity;
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.infrastructure.item.repository.ItemJpaRepository;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
@Component
|
||||
public class ItemJpaAdapter implements ItemPort {
|
||||
private final ItemJpaRepository itemJpaRepository;
|
||||
|
||||
public ItemJpaAdapter(ItemJpaRepository itemJpaRepository) {
|
||||
this.itemJpaRepository = itemJpaRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Item> getAll() {
|
||||
return Mono.fromCallable(itemJpaRepository::findAll)
|
||||
.subscribeOn(Schedulers.boundedElastic())
|
||||
.flatMapMany(Flux::fromIterable)
|
||||
.map(ItemJpaEntity::toDomain);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.infrastructure.item.model;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.domain.item.model.Item;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "item")
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class ItemJpaEntity {
|
||||
@Id
|
||||
private UUID id;
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
@Column(nullable = false)
|
||||
private ZonedDateTime sharedDate;
|
||||
|
||||
public ItemJpaEntity(Item item) {
|
||||
id = item.id();
|
||||
name = item.name();
|
||||
sharedDate = item.sharedDate();
|
||||
}
|
||||
|
||||
public Item toDomain() {
|
||||
return new Item(id, name, sharedDate);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.infrastructure.item.repository;
|
||||
|
||||
import com.zeenea.experiments.virtualthreads.reactorapp.infrastructure.item.model.ItemJpaEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface ItemJpaRepository extends JpaRepository<ItemJpaEntity, UUID> {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.zeenea.experiments.virtualthreads.reactorapp.launcher;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication(scanBasePackages = "com.zeenea.experiments.virtualthreads.reactorapp")
|
||||
public class ReactorApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ReactorApplication.class, args);
|
||||
}
|
||||
}
|
||||
14
reactor-app/src/main/resources/application.yml
Normal file
14
reactor-app/src/main/resources/application.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
spring:
|
||||
application:
|
||||
name: reactor-app
|
||||
datasource:
|
||||
driverClassName: org.postgresql.Driver
|
||||
url: jdbc:postgresql://localhost:51000/virtual_threads_test_db
|
||||
username: virtual_threads_test_user
|
||||
password: password
|
||||
threads:
|
||||
virtual:
|
||||
enabled: true
|
||||
|
||||
server:
|
||||
port: 52001
|
||||
Reference in New Issue
Block a user