Skip to content

Commit

Permalink
Review: Add more realistic shopping example application for onion arc…
Browse files Browse the repository at this point in the history
…hitecture. Adjust integration test to match example.

Issue: #174
Signed-off-by: Peter Gafert <[email protected]>
  • Loading branch information
codecholeric committed Jul 19, 2019
1 parent 5873ef6 commit daa45b9
Show file tree
Hide file tree
Showing 29 changed files with 394 additions and 271 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@
@RunWith(ArchUnitRunner.class)
@AnalyzeClasses(packages = "com.tngtech.archunit.example.onionarchitecture")
public class OnionArchitectureTest {
private static final String BASE_PACKAGE = "com.tngtech.archunit.example.onionarchitecture";

@ArchTest
static final ArchRule onion_architecture_is_respected = onionArchitecture()
.domainModel(String.format("%s.domain.model..", BASE_PACKAGE))
.domainService(String.format("%s.domain.service..", BASE_PACKAGE))
.application(String.format("%s.application..", BASE_PACKAGE))
.adapter("cli", String.format("%s.adapter.cli..", BASE_PACKAGE))
.adapter("persistence", String.format("%s.adapter.persistence..", BASE_PACKAGE))
.adapter("rest", String.format("%s.adapter.rest..", BASE_PACKAGE));
.domainModels("..domain.model..")
.domainServices("..domain.service..")
.applicationServices("..application..")
.adapter("cli", "..adapter.cli..")
.adapter("persistence", "..adapter.persistence..")
.adapter("rest", "..adapter.rest..");
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@
@ArchTag("example")
@AnalyzeClasses(packages = "com.tngtech.archunit.example.onionarchitecture")
public class OnionArchitectureTest {
private static final String BASE_PACKAGE = "com.tngtech.archunit.example.onionarchitecture";

@ArchTest
static final ArchRule onion_architecture_is_respected = onionArchitecture()
.domainModel(String.format("%s.domain.model..", BASE_PACKAGE))
.domainService(String.format("%s.domain.service..", BASE_PACKAGE))
.application(String.format("%s.application..", BASE_PACKAGE))
.adapter("cli", String.format("%s.adapter.cli..", BASE_PACKAGE))
.adapter("persistence", String.format("%s.adapter.persistence..", BASE_PACKAGE))
.adapter("rest", String.format("%s.adapter.rest..", BASE_PACKAGE));
.domainModels("..domain.model..")
.domainServices("..domain.service..")
.applicationServices("..application..")
.adapter("cli", "..adapter.cli..")
.adapter("persistence", "..adapter.persistence..")
.adapter("rest", "..adapter.rest..");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.tngtech.archunit.example.onionarchitecture.adapter.cli;

import com.tngtech.archunit.example.onionarchitecture.adapter.persistence.ProductRepository;
import com.tngtech.archunit.example.onionarchitecture.application.AdministrationPort;
import com.tngtech.archunit.example.onionarchitecture.application.ShoppingApplication;

@SuppressWarnings("unused")
public class AdministrationCLI {
public static void main(String[] args) {
AdministrationPort port = ShoppingApplication.openAdministrationPort();
handle(args, port);
}

private static void handle(String[] args, AdministrationPort port) {
// violates the pairwise independence of adapters
ProductRepository repository = port.getInstanceOf(ProductRepository.class);
long count = repository.getTotalCount();
// parse arguments and re-configure application according to count through port
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.tngtech.archunit.example.onionarchitecture.adapter.persistence;

import java.util.UUID;

@SuppressWarnings("unused")
public class ProductId {
private final UUID id;

public ProductId(UUID id) {
if (id == null) {
throw new IllegalArgumentException("ID must not be null");
}
this.id = id;
}

@Override
public String toString() {
return getClass().getSimpleName() + "{id=" + id + '}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.tngtech.archunit.example.onionarchitecture.adapter.persistence;

import com.tngtech.archunit.example.onionarchitecture.domain.model.Product;
import com.tngtech.archunit.example.onionarchitecture.domain.service.ProductName;

@SuppressWarnings("unused")
public class ProductJpaRepository implements ProductRepository {
@Override
public Product read(ProductId id) {
return new Product(id, new ProductName("would normally be read"));
}

@Override
public long getTotalCount() {
return 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.tngtech.archunit.example.onionarchitecture.adapter.persistence;

import com.tngtech.archunit.example.onionarchitecture.domain.model.Product;

// Violates the architecture because Domain must be the owner of the interfaces, not the persistence adapter
public interface ProductRepository {
Product read(ProductId id);

long getTotalCount();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.tngtech.archunit.example.onionarchitecture.adapter.persistence;

import java.util.UUID;

public class ShoppingCartId {
private final UUID id;

public ShoppingCartId(UUID id) {
if (id == null) {
throw new IllegalArgumentException("ID must not be null");
}
this.id = id;
}

@Override
public String toString() {
return getClass().getSimpleName() + "{id=" + id + '}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.tngtech.archunit.example.onionarchitecture.adapter.persistence;

import com.tngtech.archunit.example.onionarchitecture.domain.model.ShoppingCart;

@SuppressWarnings("unused")
public class ShoppingCartJpaRepository implements ShoppingCartRepository {
@Override
public ShoppingCart read(ShoppingCartId id) {
// would normally load fully initialized shopping cart
return new ShoppingCart(id);
}

@Override
public void save(ShoppingCart shoppingCart) {
// store shopping cart via JPA
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.tngtech.archunit.example.onionarchitecture.adapter.persistence;

import com.tngtech.archunit.example.onionarchitecture.domain.model.ShoppingCart;

// Violates the architecture because Domain must be the owner of the interfaces, not the persistence adapter
public interface ShoppingCartRepository {
ShoppingCart read(ShoppingCartId id);

void save(ShoppingCart shoppingCart);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.tngtech.archunit.example.onionarchitecture.adapter.rest;

import java.util.UUID;

import com.tngtech.archunit.example.onionarchitecture.adapter.persistence.ProductId;
import com.tngtech.archunit.example.onionarchitecture.adapter.persistence.ShoppingCartId;
import com.tngtech.archunit.example.onionarchitecture.domain.service.OrderQuantity;
import com.tngtech.archunit.example.onionarchitecture.domain.service.ShoppingService;

@SuppressWarnings("unused")
public class ShoppingController {
private final ShoppingService shoppingService;

public ShoppingController(ShoppingService shoppingService) {
this.shoppingService = shoppingService;
}

// @POST or similar
public void addToShoppingCart(UUID shoppingCartId, UUID productId, int quantity) {
shoppingService.addToShoppingCart(new ShoppingCartId(shoppingCartId), new ProductId(productId), new OrderQuantity(quantity));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.tngtech.archunit.example.onionarchitecture.application;

public interface AdministrationPort {
<T> T getInstanceOf(Class<T> type);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.tngtech.archunit.example.onionarchitecture.application;

public class ShoppingApplication {
public static void main(String[] args) {
// start the whole application / provide IOC features
}

public static AdministrationPort openAdministrationPort() {
return new AdministrationPort() {
@Override
public <T> T getInstanceOf(Class<T> type) {
throw new UnsupportedOperationException("Not yet implemented");
}
};
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.tngtech.archunit.example.onionarchitecture.domain.model;

import com.tngtech.archunit.example.onionarchitecture.domain.service.OrderQuantity;

public class OrderItem {
private final Product product;
private final OrderQuantity quantity;

public OrderItem(Product product, OrderQuantity quantity) {
if (product == null) {
throw new IllegalArgumentException("Product must not be null");
}
if (quantity == null) {
throw new IllegalArgumentException("Quantity not be null");
}
this.product = product;
this.quantity = quantity;
}

@Override
public String toString() {
return getClass().getSimpleName() + "{product=" + product + ", quantity=" + quantity + '}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.tngtech.archunit.example.onionarchitecture.domain.model;

@SuppressWarnings("WeakerAccess")
public class PaymentMethod {
}
Loading

0 comments on commit daa45b9

Please sign in to comment.