From 6a76d17933e9ffc3c002e3c9f8db03ff05c45eac Mon Sep 17 00:00:00 2001 From: pith Date: Mon, 20 Apr 2015 18:05:38 +0200 Subject: [PATCH] Complete assembler DSL use cases Add use cases with lists for dto, aggregate and tuple. Delete the AssemblerContext which was passed between DSL elements. This last change also fixed some bugs. --- .../dsl/AssemblerDslWithTupleIT.java | 22 +- .../assembler/dsl/InternalRegistryIT.java | 11 + .../fixtures/DefaultRepoSample2.java | 1 + .../core/interfaces/AutomaticAssembler.java | 5 +- .../interfaces/AutomaticTupleAssembler.java | 22 +- .../core/interfaces/DefaultAssembler.java | 2 +- .../interfaces/DefaultTupleAssembler.java | 4 +- .../dsl/AggAssemblerProviderImpl.java | 199 +++++++++++++++--- .../dsl/AggAssemblerWithRepoProviderImpl.java | 50 ++--- .../dsl/AggsAssemblerProviderImpl.java | 116 ++++++++++ .../AggsAssemblerWithRepoProviderImpl.java | 112 ++++++++++ .../assembler/dsl/AssembleImpl.java | 32 +-- .../assembler/dsl/AssemblerContext.java | 151 ------------- .../BaseAggAssemblerWithRepoProviderImpl.java | 38 +++- .../dsl/DtoAssemblerProviderImpl.java | 15 +- .../dsl/DtosAssemblerProviderImpl.java | 24 +-- .../assembler/dsl/InternalRegistry.java | 16 -- .../dsl/InternalRegistryInternal.java | 22 +- ...TupleAggAssemblerWithRepoProviderImpl.java | 24 ++- ...upleAggsAssemblerWithRepoProviderImpl.java | 192 +++++++++++++++++ .../resolver/AnnotationResolver.java | 4 +- .../resolver/ParameterHolderInternal.java | 2 +- .../dsl/AggAssemblerProviderImplTest.java | 41 ++-- .../AggAssemblerWithRepoProviderImplTest.java | 8 +- .../assembler/dsl/AssembleTest.java | 2 +- .../dsl/DtoAssemblerProviderImplTest.java | 35 ++- .../domain/DefaultRepositoryProviderTest.java | 32 --- .../org/seedstack/business/api/Tuples.java | 18 ++ .../interfaces/assembler/FluentAssembler.java | 2 + .../assembler/dsl/AggAssemblerProvider.java | 102 ++++++++- .../assembler/dsl/AggsAssemblerProvider.java | 40 +++- .../AggsAssemblerWithRepoAndFactProvider.java | 25 +++ .../dsl/AggsAssemblerWithRepoProvider.java | 25 +++ .../interfaces/assembler/dsl/Assemble.java | 4 +- .../dsl/BaseAggAssemblerProvider.java | 45 ---- ...eAggsAssemblerWithRepoAndFactProvider.java | 24 +++ .../TupleAggsAssemblerWithRepoProvider.java | 24 +++ .../seedstack/business/api/TuplesTest.java | 46 +++- 38 files changed, 1050 insertions(+), 487 deletions(-) create mode 100644 core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggsAssemblerProviderImpl.java create mode 100644 core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggsAssemblerWithRepoProviderImpl.java delete mode 100644 core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AssemblerContext.java create mode 100644 core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/TupleAggsAssemblerWithRepoProviderImpl.java delete mode 100644 core/src/test/java/org/seedstack/business/internal/domain/DefaultRepositoryProviderTest.java create mode 100644 specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggsAssemblerWithRepoAndFactProvider.java create mode 100644 specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggsAssemblerWithRepoProvider.java delete mode 100644 specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/BaseAggAssemblerProvider.java create mode 100644 specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/TupleAggsAssemblerWithRepoAndFactProvider.java create mode 100644 specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/TupleAggsAssemblerWithRepoProvider.java diff --git a/core/src/it/java/org/seedstack/business/assembler/dsl/AssemblerDslWithTupleIT.java b/core/src/it/java/org/seedstack/business/assembler/dsl/AssemblerDslWithTupleIT.java index cab93d5e..107621f0 100644 --- a/core/src/it/java/org/seedstack/business/assembler/dsl/AssemblerDslWithTupleIT.java +++ b/core/src/it/java/org/seedstack/business/assembler/dsl/AssemblerDslWithTupleIT.java @@ -48,7 +48,7 @@ public class AssemblerDslWithTupleIT { public void testAssembleFromFactory() { Recipe recipe = new Recipe("customer1", "luke", "order1", "light saber"); - Pair orderCustomerPair = fluently.assemble().dto(recipe).>to(Order.class, Customer.class).fromFactory(); + Pair orderCustomerPair = fluently.assemble().dto(recipe).to(Order.class, Customer.class).fromFactory(); Assertions.assertThat(orderCustomerPair.getValue0()).isNotNull(); Assertions.assertThat(orderCustomerPair.getValue0().getEntityId()).isEqualTo("order1"); @@ -71,7 +71,7 @@ public void testAssembleFromRepository() { Pair orderCustomerPair = null; try { - orderCustomerPair = fluently.assemble().dto(recipe).>to(Order.class, Customer.class).fromRepository().orFail(); + orderCustomerPair = fluently.assemble().dto(recipe).to(Order.class, Customer.class).fromRepository().orFail(); } catch (AggregateNotFoundException e) { fail(); } @@ -86,8 +86,9 @@ public void testAssembleFromRepository() { @Test @Ignore public void testAssembleFromRepositoryOrFail() { + Recipe recipe = new Recipe("customer1", "luke", "order1", "light saber"); try { - fluently.assemble().dto(new OrderDto("1", "light saber")).to(Order.class).fromRepository().orFail(); + fluently.assemble().dto(recipe).to(Order.class, Customer.class).fromRepository().orFail(); fail(); } catch (AggregateNotFoundException e) { Assertions.assertThat(e).isNotNull(); @@ -97,15 +98,16 @@ public void testAssembleFromRepositoryOrFail() { @Test @Ignore public void testAssembleFromRepositoryOrFactory() { - OrderDto dto = new OrderDto("1", "light saber", PRICE); + Recipe recipe = new Recipe("customer1", "luke", "order1", "light saber"); - Order aggregateRoot = fluently.assemble().dto(dto).to(Order.class).fromRepository().thenFromFactory(); + Pair orderCustomerPair = fluently.assemble().dto(recipe).to(Order.class, Customer.class).fromRepository().thenFromFactory(); - Assertions.assertThat(aggregateRoot).isNotNull(); - Assertions.assertThat(aggregateRoot.getEntityId()).isEqualTo("1"); - Assertions.assertThat(aggregateRoot.getProduct()).isEqualTo("light saber"); - // the customer name is not part of the factory parameters, but so it should be set by the assembler - Assertions.assertThat(aggregateRoot.getPrice()).isEqualTo(PRICE); + Assertions.assertThat(orderCustomerPair.getValue0()).isNotNull(); + Assertions.assertThat(orderCustomerPair.getValue0().getEntityId()).isEqualTo("order1"); + Assertions.assertThat(orderCustomerPair.getValue0().getProduct()).isEqualTo("light saber"); + // the customer name is not part of the factory parameters, so it is set by the assembler + Assertions.assertThat(orderCustomerPair.getValue1().getEntityId()).isEqualTo("customer1"); + Assertions.assertThat(orderCustomerPair.getValue1().getName()).isEqualTo("luke"); } @Test diff --git a/core/src/it/java/org/seedstack/business/assembler/dsl/InternalRegistryIT.java b/core/src/it/java/org/seedstack/business/assembler/dsl/InternalRegistryIT.java index 726435fb..4e30df0c 100644 --- a/core/src/it/java/org/seedstack/business/assembler/dsl/InternalRegistryIT.java +++ b/core/src/it/java/org/seedstack/business/assembler/dsl/InternalRegistryIT.java @@ -9,6 +9,7 @@ */ package org.seedstack.business.assembler.dsl; +import com.google.common.collect.Lists; import org.assertj.core.api.Assertions; import org.junit.Test; import org.junit.runner.RunWith; @@ -23,9 +24,12 @@ import org.seedstack.business.core.interfaces.DefaultAssembler; import org.seedstack.business.core.interfaces.assembler.dsl.InternalRegistry; import org.seedstack.business.core.interfaces.assembler.dsl.fixture.AutoAssembler; +import org.seedstack.business.core.interfaces.assembler.dsl.fixture.Customer; +import org.seedstack.business.core.interfaces.assembler.dsl.fixture.Recipe; import org.seedstack.seed.it.SeedITRunner; import javax.inject.Inject; +import java.util.List; /** * Tests the DSL internal registry. @@ -74,6 +78,13 @@ public void testAssemblerOfWithDefaultAssembler() { Assertions.assertThat(assembler.getClass()).isEqualTo(expectedAutomaticAssembler.getClass()); } + @Test + public void testAssemblerOfTuple() { + List aggregateRootTuple = Lists.newArrayList(org.seedstack.business.core.interfaces.assembler.dsl.fixture.Order.class, Customer.class); + Assembler assembler = registry.tupleAssemblerOf((List>>) aggregateRootTuple, Recipe.class); + Assertions.assertThat(assembler).isNotNull(); + } + @Test public void testAssemblerOfWithAutomaticAssembler() { Assembler assembler = registry.assemblerOf(org.seedstack.business.core.interfaces.assembler.dsl.fixture.Order.class diff --git a/core/src/it/java/org/seedstack/business/repositories/fixtures/DefaultRepoSample2.java b/core/src/it/java/org/seedstack/business/repositories/fixtures/DefaultRepoSample2.java index 21e300a3..ba27ea7e 100644 --- a/core/src/it/java/org/seedstack/business/repositories/fixtures/DefaultRepoSample2.java +++ b/core/src/it/java/org/seedstack/business/repositories/fixtures/DefaultRepoSample2.java @@ -35,6 +35,7 @@ protected A doLoad(K id) { return null; } + @Override protected void doDelete(K id) { diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/AutomaticAssembler.java b/core/src/main/java/org/seedstack/business/core/interfaces/AutomaticAssembler.java index 93d037ef..2dd34fca 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/AutomaticAssembler.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/AutomaticAssembler.java @@ -25,7 +25,6 @@ */ public abstract class AutomaticAssembler, D> extends AbstractBaseAssembler { - protected Class aggregateClass; protected Class dtoClass; private ModelMapper assembleModelMapper; private ModelMapper mergeModelMapper; @@ -37,16 +36,14 @@ public AutomaticAssembler() { // TODO : check modelmappers are not null Class class1 = (Class) SeedReflectionUtils.cleanProxy(getClass()); - aggregateClass = (Class) TypeResolver.resolveRawArguments(class1.getGenericSuperclass(), class1)[0]; dtoClass = (Class) TypeResolver.resolveRawArguments(class1.getGenericSuperclass(), class1)[1]; } - public AutomaticAssembler(Class aggregateClass, Class dtoClass) { + public AutomaticAssembler(Class dtoClass) { assembleModelMapper = configureAssembly(); mergeModelMapper = configureMerge(); // TODO : check modelmappers are not null - this.aggregateClass = aggregateClass; this.dtoClass = dtoClass; } diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/AutomaticTupleAssembler.java b/core/src/main/java/org/seedstack/business/core/interfaces/AutomaticTupleAssembler.java index c72d5b16..339cd45d 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/AutomaticTupleAssembler.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/AutomaticTupleAssembler.java @@ -14,12 +14,8 @@ import org.modelmapper.ModelMapper; import org.seedstack.business.api.interfaces.assembler.AbstractBaseAssembler; import org.seedstack.business.api.interfaces.assembler.BaseTupleAssembler; -import org.seedstack.business.api.Tuples; import org.seedstack.seed.core.utils.SeedReflectionUtils; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - /** * This assembler automatically assembles aggregates in DTO and vice versa. * @@ -30,7 +26,6 @@ */ public abstract class AutomaticTupleAssembler extends AbstractBaseAssembler { - protected ParameterizedType aggregateClasses; protected Class dtoClass; private ModelMapper assembleModelMapper; private ModelMapper mergeModelMapper; @@ -42,25 +37,10 @@ public AutomaticTupleAssembler() { // TODO : check modelmappers are not null Class class1 = (Class) SeedReflectionUtils.cleanProxy(getClass()); - ParameterizedType p1 = (ParameterizedType) class1.getGenericSuperclass(); - // descendant of tuple. - ParameterizedType tupleType = (ParameterizedType) p1.getActualTypeArguments()[0]; - - Type rawTupleType = tupleType.getRawType(); - Class tupleClass = (Class) rawTupleType; - Type[] actualTypeArguments = tupleType.getActualTypeArguments(); - int length = actualTypeArguments.length; - Class[] aggregateClassesArray = new Class[length]; - - System.arraycopy(actualTypeArguments, 0, aggregateClassesArray, 0, length); - - aggregateClasses = Tuples.typeOfTuple(aggregateClassesArray); - dtoClass = (Class) TypeResolver.resolveRawArguments(class1.getGenericSuperclass(), class1)[1]; } - public AutomaticTupleAssembler(ParameterizedType aggregateClasses, Class dtoClass) { - this.aggregateClasses = aggregateClasses; + public AutomaticTupleAssembler(Class dtoClass) { this.dtoClass = dtoClass; assembleModelMapper = configureAssembly(); diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/DefaultAssembler.java b/core/src/main/java/org/seedstack/business/core/interfaces/DefaultAssembler.java index dd7d8b2b..a111359d 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/DefaultAssembler.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/DefaultAssembler.java @@ -30,7 +30,7 @@ public class DefaultAssembler,D> extends AutomaticAss @SuppressWarnings("unchecked") @Inject public DefaultAssembler(@Assisted Object[] genericClasses) { - super((Class) genericClasses.clone()[0], (Class) genericClasses.clone()[1]); + super((Class) genericClasses.clone()[1]); } @Override diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/DefaultTupleAssembler.java b/core/src/main/java/org/seedstack/business/core/interfaces/DefaultTupleAssembler.java index 4595aee2..f87396b3 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/DefaultTupleAssembler.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/DefaultTupleAssembler.java @@ -15,7 +15,6 @@ import org.modelmapper.ModelMapper; import javax.inject.Inject; -import java.lang.reflect.ParameterizedType; /** * This class is a default tuple assembler based on ModelMapper. @@ -32,7 +31,8 @@ public class DefaultTupleAssembler extends AutomaticTupleAss @SuppressWarnings("unchecked") @Inject public DefaultTupleAssembler(@Assisted Object[] genericClasses) { - super((ParameterizedType) genericClasses.clone()[0], (Class) genericClasses.clone()[1]); + // TODO the first parameter is useless remove it + super((Class) genericClasses.clone()[1]); } @Override diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerProviderImpl.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerProviderImpl.java index cda868dd..240b8533 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerProviderImpl.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerProviderImpl.java @@ -9,65 +9,198 @@ */ package org.seedstack.business.core.interfaces.assembler.dsl; -import org.javatuples.Tuple; +import com.google.common.collect.Lists; +import org.javatuples.*; import org.seedstack.business.api.Tuples; import org.seedstack.business.api.domain.AggregateRoot; import org.seedstack.business.api.interfaces.assembler.Assembler; -import org.seedstack.business.api.interfaces.assembler.dsl.*; +import org.seedstack.business.api.interfaces.assembler.dsl.AggAssemblerProvider; +import org.seedstack.business.api.interfaces.assembler.dsl.AggAssemblerWithRepoProvider; +import org.seedstack.business.api.interfaces.assembler.dsl.TupleAggAssemblerWithRepoProvider; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** * @author Pierre Thirouin */ -public class AggAssemblerProviderImpl implements BaseAggAssemblerProvider, AggAssemblerProvider, AggsAssemblerProvider { +public class AggAssemblerProviderImpl implements AggAssemblerProvider { private InternalRegistry registry; - private final AssemblerContext assemblerContext; + private final D dto; - public AggAssemblerProviderImpl(InternalRegistry registry, AssemblerContext assemblerContext) { + public AggAssemblerProviderImpl(InternalRegistry registry, D dto) { this.registry = registry; - this.assemblerContext = assemblerContext; + this.dto = dto; } @Override public > AggAssemblerWithRepoProvider to(Class aggregateRootClass) { - assemblerContext.setAggregateClass(aggregateRootClass); - return new AggAssemblerWithRepoProviderImpl(registry, assemblerContext); + return new AggAssemblerWithRepoProviderImpl(registry, aggregateRootClass, dto); } @Override - public TupleAggAssemblerWithRepoProvider to(Class> firstAggregateClass, Class> secondAggregateClass, Class>... otherAggregateClasses) { - List> aggregateRootClasses = new ArrayList>(); - aggregateRootClasses.add(firstAggregateClass); - aggregateRootClasses.add(secondAggregateClass); - aggregateRootClasses.addAll(Arrays.asList(otherAggregateClasses)); - assemblerContext.setAggregateClasses(Tuples.create((List)aggregateRootClasses)); - return new TupleAggAssemblerWithRepoProviderImpl(registry, assemblerContext); + public , A2 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second) { + return new TupleAggAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second), dto); } @Override - public > A to(A aggregateRoot) { - Assembler assembler = registry.assemblerOf((Class>) aggregateRoot.getClass(), assemblerContext.getDto().getClass()); - assembler.mergeAggregateWithDto(aggregateRoot, assemblerContext.getDto()); - return aggregateRoot; + public , A2 extends AggregateRoot, A3 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third) { + return new TupleAggAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third), dto); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth) { + return new TupleAggAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth), dto); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth) { + return new TupleAggAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth, fifth), dto); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth) { + return new TupleAggAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth, fifth, sixth), dto); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh) { + return new TupleAggAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth, fifth, sixth, seventh), dto); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh, Class eighth) { + return new TupleAggAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth, fifth, sixth, seventh, eighth), dto); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot, A9 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh, Class eighth, Class ninth) { + return new TupleAggAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth, fifth, sixth, seventh, eighth, ninth), dto); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot, A9 extends AggregateRoot, A10 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh, Class eighth, Class ninth, Class tenth) { + return new TupleAggAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth), dto); + } + + @Override + public TupleAggAssemblerWithRepoProvider to(List>> aggregateRootClasses) { + return new TupleAggAssemblerWithRepoProviderImpl(registry, aggregateRootClasses, dto); + } + + // ----------------------------------------------------------------------------------------------------------------- + + @Override + public , A2 extends AggregateRoot> + Pair to(A1 first, A2 second) { + List aggregateRootClasses = Lists.newArrayList(first.getClass(), second.getClass()); + Pair aggregateRootTuple = Tuples.create(first, second); + Assembler, D> assembler = (Assembler, D>) registry.tupleAssemblerOf((List>>) aggregateRootClasses, dto.getClass()); + assembler.mergeAggregateWithDto(aggregateRootTuple, dto); + return aggregateRootTuple; } @Override - public > List to(List aggregateRoots) { - List dtos = assemblerContext.getDtos(); - if (aggregateRoots != null && dtos != null) { - if (aggregateRoots.size() != dtos.size()) { - throw new IllegalArgumentException("The list of dto should have the same size as the list of aggregate"); - } - Assembler assembler = registry.assemblerOf((Class>) aggregateRoots.get(0).getClass(), dtos.get(0).getClass()); - for (int i = 0; i < aggregateRoots.size(); i++) { - assembler.mergeAggregateWithDto(aggregateRoots.get(i), dtos.get(i)); - } - } - return aggregateRoots; + public , A2 extends AggregateRoot, A3 extends AggregateRoot> + Triplet to(A1 first, A2 second, A3 third) { + List aggregateRootClasses = Lists.newArrayList(first.getClass(), second.getClass(), third.getClass()); + Triplet aggregateRootTuple = Tuples.create(first, second, third); + Assembler, D> assembler = (Assembler, D>) registry.tupleAssemblerOf((List>>) aggregateRootClasses, dto.getClass()); + assembler.mergeAggregateWithDto(aggregateRootTuple, dto); + return aggregateRootTuple; + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot> + Quartet to(A1 first, A2 second, A3 third, A4 fourth) { + List aggregateRootClasses = Lists.newArrayList(first.getClass(), second.getClass(), third.getClass(), fourth.getClass()); + Quartet aggregateRootTuple = Tuples.create(first, second, third, fourth); + Assembler, D> assembler = (Assembler, D>) registry.tupleAssemblerOf((List>>) aggregateRootClasses, dto.getClass()); + assembler.mergeAggregateWithDto(aggregateRootTuple, dto); + return aggregateRootTuple; + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot> + Quintet to(A1 first, A2 second, A3 third, A4 fourth, A5 fifth) { + List aggregateRootClasses = Lists.newArrayList(first.getClass(), second.getClass(), third.getClass(), fourth.getClass(), fifth.getClass()); + Quintet aggregateRootTuple = Tuples.create(first, second, third, fourth, fifth); + Assembler, D> assembler = (Assembler, D>) registry.tupleAssemblerOf((List>>) aggregateRootClasses, dto.getClass()); + assembler.mergeAggregateWithDto(aggregateRootTuple, dto); + return aggregateRootTuple; + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot> + Sextet to(A1 first, A2 second, A3 third, A4 fourth, A5 fifth, A6 sixth) { + List aggregateRootClasses = Lists.newArrayList(first.getClass(), second.getClass(), third.getClass(), fourth.getClass(), fifth.getClass(), sixth.getClass()); + Sextet aggregateRootTuple = Tuples.create(first, second, third, fourth, fifth, sixth); + Assembler, D> assembler = (Assembler, D>) registry.tupleAssemblerOf((List>>) aggregateRootClasses, dto.getClass()); + assembler.mergeAggregateWithDto(aggregateRootTuple, dto); + return aggregateRootTuple; + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot> + Septet to(A1 first, A2 second, A3 third, A4 fourth, A5 fifth, A6 sixth, A7 seventh) { + List aggregateRootClasses = Lists.newArrayList(first.getClass(), second.getClass(), third.getClass(), fourth.getClass(), fifth.getClass(), sixth.getClass(), seventh.getClass()); + Septet aggregateRootTuple = Tuples.create(first, second, third, fourth, fifth, sixth, seventh); + Assembler, D> assembler = (Assembler, D>) registry.tupleAssemblerOf((List>>) aggregateRootClasses, dto.getClass()); + assembler.mergeAggregateWithDto(aggregateRootTuple, dto); + return aggregateRootTuple; + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot> + Octet to(A1 first, A2 second, A3 third, A4 fourth, A5 fifth, A6 sixth, A7 seventh, A8 eighth) { + List aggregateRootClasses = Lists.newArrayList(first.getClass(), second.getClass(), third.getClass(), fourth.getClass(), fifth.getClass(), sixth.getClass(), seventh.getClass(), eighth.getClass()); + Octet aggregateRootTuple = Tuples.create(first, second, third, fourth, fifth, sixth, seventh, eighth); + Assembler, D> assembler = (Assembler, D>) registry.tupleAssemblerOf((List>>) aggregateRootClasses, dto.getClass()); + assembler.mergeAggregateWithDto(aggregateRootTuple, dto); + return aggregateRootTuple; + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot, A9 extends AggregateRoot> + Ennead to(A1 first, A2 second, A3 third, A4 fourth, A5 fifth, A6 sixth, A7 seventh, A8 eighth, A9 ninth) { + List aggregateRootClasses = Lists.newArrayList(first.getClass(), second.getClass(), third.getClass(), fourth.getClass(), fifth.getClass(), sixth.getClass(), seventh.getClass(), eighth.getClass(), ninth.getClass()); + Ennead aggregateRootTuple = Tuples.create(first, second, third, fourth, fifth, sixth, seventh, eighth, ninth); + Assembler, D> assembler = (Assembler, D>) registry.tupleAssemblerOf((List>>) aggregateRootClasses, dto.getClass()); + assembler.mergeAggregateWithDto(aggregateRootTuple, dto); + return aggregateRootTuple; + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot, A9 extends AggregateRoot, A10 extends AggregateRoot> + Decade to(A1 first, A2 second, A3 third, A4 fourth, A5 fifth, A6 sixth, A7 seventh, A8 eighth, A9 ninth, A10 tenth) { + List aggregateRootClasses = Lists.newArrayList(first.getClass(), second.getClass(), third.getClass(), fourth.getClass(), fifth.getClass(), sixth.getClass(), seventh.getClass(), eighth.getClass(), ninth.getClass(), tenth.getClass()); + Decade aggregateRootTuple = Tuples.create(first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth); + Assembler, D> assembler = (Assembler, D>) registry.tupleAssemblerOf((List>>) aggregateRootClasses, dto.getClass()); + assembler.mergeAggregateWithDto(aggregateRootTuple, dto); + return aggregateRootTuple; + } + + @Override + public Tuple to(Tuple aggregateRootTuple) { + Assembler assembler = registry.tupleAssemblerOf((List>>) Tuples.toListOfClasses(aggregateRootTuple), dto.getClass()); + assembler.mergeAggregateWithDto(aggregateRootTuple, dto); + return aggregateRootTuple; + } + + @Override + public > A to(A aggregateRoot) { + Assembler assembler = (Assembler) registry.assemblerOf((Class>) aggregateRoot.getClass(), dto.getClass()); + assembler.mergeAggregateWithDto(aggregateRoot, dto); + return aggregateRoot; } } diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerWithRepoProviderImpl.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerWithRepoProviderImpl.java index d8edff11..7842681d 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerWithRepoProviderImpl.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerWithRepoProviderImpl.java @@ -10,49 +10,47 @@ package org.seedstack.business.core.interfaces.assembler.dsl; import org.seedstack.business.api.domain.AggregateRoot; -import org.seedstack.business.api.domain.GenericFactory; import org.seedstack.business.api.domain.Repository; -import org.seedstack.business.api.interfaces.assembler.Assembler; import org.seedstack.business.api.interfaces.assembler.dsl.AggAssemblerWithRepoAndFactProvider; import org.seedstack.business.api.interfaces.assembler.dsl.AggAssemblerWithRepoProvider; import org.seedstack.business.api.interfaces.assembler.dsl.AggregateNotFoundException; -import org.seedstack.business.api.interfaces.assembler.resolver.ParameterHolder; /** * @author Pierre Thirouin */ -public class AggAssemblerWithRepoProviderImpl> extends BaseAggAssemblerWithRepoProviderImpl implements AggAssemblerWithRepoProvider, AggAssemblerWithRepoAndFactProvider { +public class AggAssemblerWithRepoProviderImpl> extends BaseAggAssemblerWithRepoProviderImpl implements AggAssemblerWithRepoProvider, AggAssemblerWithRepoAndFactProvider { - public AggAssemblerWithRepoProviderImpl(InternalRegistry registry, AssemblerContext assemblerContext) { - super(registry, assemblerContext); + private final Class aggregateClass; + private final Object dto; + + public AggAssemblerWithRepoProviderImpl(InternalRegistry registry, Class aggregateClass, Object dto) { + super(registry); + this.aggregateClass = aggregateClass; + this.dto = dto; } // --------------------------- AggAssemblerWithRepoProvider @Override public AggAssemblerWithRepoAndFactProvider fromRepository() { - assemblerContext.setRepository(registry.repositoryOf(assemblerContext.getAggregateClass())); + // Just redirect to the expected DSL path return this; } @SuppressWarnings("unchecked") @Override public A fromFactory() { - GenericFactory genericFactory = (GenericFactory) registry.genericFactoryOf(assemblerContext.getAggregateClass()); - ParameterHolder parameterHolder = dtoInfoResolver.resolveAggregate(assemblerContext.getDto()); - A aggregateRoot = (A) getAggregateFromFactory(genericFactory, assemblerContext.getAggregateClass(), parameterHolder.parameters()); - return assembleWithDto(aggregateRoot); + return fromFactory(aggregateClass,dto); } /** * Loads an aggregate roots from a repository. * * @param key the aggregate roots identity - * @param the aggregate root type * @return the loaded aggregate root */ - protected A loadFromRepo(Object key) { - Repository repository = assemblerContext.getRepository(); + protected A loadFromRepo(Object key) { + Repository repository = registry.repositoryOf(aggregateClass); //noinspection unchecked return (A) repository.load(key); } @@ -61,43 +59,29 @@ protected A loadFromRepo(Object key) { @Override public A orFail() throws AggregateNotFoundException { - Object id = resolveId(assemblerContext.getDto(), assemblerContext.getAggregateClass()); + Object id = resolveId(dto, aggregateClass); A a = loadFromRepo(id); if (a == null) { - throw new AggregateNotFoundException(String.format("Unable to load aggregate %s for id: %s", assemblerContext.getAggregateClass(), id)); + throw new AggregateNotFoundException(String.format("Unable to load aggregate %s for id: %s", aggregateClass, id)); } - return assembleWithDto(a); + return assembleWithDto(a, dto); } @Override public A thenFromFactory() { // load from the repository - Object id = resolveId(assemblerContext.getDto(), assemblerContext.getAggregateClass()); + Object id = resolveId(dto, aggregateClass); A a = loadFromRepo(id); if (a != null) { // then assemble the dto in the previously created aggregate root - return assembleWithDto(a); + return assembleWithDto(a, dto); } else { // otherwise fallback on the factory return fromFactory(); } } - /** - * Assemble one or a tuple of aggregate root from a dto. - * - * @param aggregateRoots the aggregate root(s) to assemble - * @param type of aggregate root(s). It could be a {@code Tuple} or an {@code AggregateRoot} - * @return the assembled aggregate root(s) - */ - protected T assembleWithDto(T aggregateRoots) { - Assembler assembler = registry.assemblerOf(assemblerContext.getAggregateClass(), assemblerContext.getDto().getClass()); - //noinspection unchecked - assembler.mergeAggregateWithDto(aggregateRoots, assemblerContext.getDto()); - return aggregateRoots; - } - } diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggsAssemblerProviderImpl.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggsAssemblerProviderImpl.java new file mode 100644 index 00000000..648cdab8 --- /dev/null +++ b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggsAssemblerProviderImpl.java @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2013-2015 by The SeedStack authors. All rights reserved. + * + * This file is part of SeedStack, An enterprise-oriented full development stack. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.seedstack.business.core.interfaces.assembler.dsl; + +import com.google.common.collect.Lists; +import org.javatuples.*; +import org.seedstack.business.api.domain.AggregateRoot; +import org.seedstack.business.api.interfaces.assembler.Assembler; +import org.seedstack.business.api.interfaces.assembler.dsl.AggsAssemblerProvider; +import org.seedstack.business.api.interfaces.assembler.dsl.AggsAssemblerWithRepoProvider; +import org.seedstack.business.api.interfaces.assembler.dsl.TupleAggsAssemblerWithRepoProvider; + +import java.util.Arrays; +import java.util.List; + +/** + * @author Pierre Thirouin + */ +public class AggsAssemblerProviderImpl implements AggsAssemblerProvider { + + private InternalRegistry registry; + private final List dtos; + + public AggsAssemblerProviderImpl(InternalRegistry registry, List dtos) { + this.registry = registry; + this.dtos = dtos; + } + + @Override + public > AggsAssemblerWithRepoProvider to(Class aggregateRootClass) { + return new AggsAssemblerWithRepoProviderImpl(registry, aggregateRootClass, dtos); + } + + @Override + public , A2 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second) { + return new TupleAggsAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second), dtos); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third) { + return new TupleAggsAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third), dtos); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth) { + return new TupleAggsAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth), dtos); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth) { + return new TupleAggsAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth, fifth), dtos); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth) { + return new TupleAggsAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth, fifth, sixth), dtos); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh) { + return new TupleAggsAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth, fifth, sixth, seventh), dtos); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh, Class eighth) { + return new TupleAggsAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth, fifth, sixth, seventh, eighth), dtos); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot, A9 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh, Class eighth, Class ninth) { + return new TupleAggsAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth, fifth, sixth, seventh, eighth, ninth), dtos); + } + + @Override + public , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot, A9 extends AggregateRoot, A10 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh, Class eighth, Class ninth, Class tenth) { + return new TupleAggsAssemblerWithRepoProviderImpl>(registry, Lists.newArrayList(first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth), dtos); + } + + // ----------------------------------------------------------------------------------------------------------------- + + public TupleAggsAssemblerWithRepoProvider to(Class>[] aggregateRootClasses) { + // Still used by our legacy Assemblers but not part of the API + return new TupleAggsAssemblerWithRepoProviderImpl(registry, Arrays.asList(aggregateRootClasses), dtos); + } + + @Override + public > List to(List aggregateRoots) { + if (aggregateRoots != null && dtos != null) { + if (aggregateRoots.size() != dtos.size()) { + throw new IllegalArgumentException("The list of dto should have the same size as the list of aggregate"); + } + Assembler assembler = registry.assemblerOf((Class>) aggregateRoots.get(0).getClass(), dtos.get(0).getClass()); + for (int i = 0; i < aggregateRoots.size(); i++) { + assembler.mergeAggregateWithDto(aggregateRoots.get(i), dtos.get(i)); + } + } + return aggregateRoots; + } + +} diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggsAssemblerWithRepoProviderImpl.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggsAssemblerWithRepoProviderImpl.java new file mode 100644 index 00000000..24707dd0 --- /dev/null +++ b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AggsAssemblerWithRepoProviderImpl.java @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2013-2015 by The SeedStack authors. All rights reserved. + * + * This file is part of SeedStack, An enterprise-oriented full development stack. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.seedstack.business.core.interfaces.assembler.dsl; + +import org.seedstack.business.api.domain.AggregateRoot; +import org.seedstack.business.api.domain.Repository; +import org.seedstack.business.api.interfaces.assembler.dsl.AggregateNotFoundException; +import org.seedstack.business.api.interfaces.assembler.dsl.AggsAssemblerWithRepoAndFactProvider; +import org.seedstack.business.api.interfaces.assembler.dsl.AggsAssemblerWithRepoProvider; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Pierre Thirouin + */ +public class AggsAssemblerWithRepoProviderImpl> extends BaseAggAssemblerWithRepoProviderImpl implements AggsAssemblerWithRepoProvider, AggsAssemblerWithRepoAndFactProvider { + + private final Class aggregateClass; + private final List dtos; + + public AggsAssemblerWithRepoProviderImpl(InternalRegistry registry, Class aggregateClass, List dtos) { + super(registry); + this.aggregateClass = aggregateClass; + this.dtos = dtos; + } + + // --------------------------- AggAssemblerWithRepoProvider + + @Override + public AggsAssemblerWithRepoAndFactProvider fromRepository() { + // Just redirect to the expected DSL path + return this; + } + + @Override + public List fromFactory() { + List aggregateRoots = new ArrayList(dtos.size()); + for (Object dto : dtos) { + aggregateRoots.add(fromFactory(aggregateClass, dto)); + } + + return aggregateRoots; + } + + /** + * Loads an aggregate roots from a repository. + * + * @param key the aggregate roots identity + * @return the loaded aggregate root + */ + protected A loadFromRepo(Class> aggregateClass, Object key) { + Repository repository = registry.repositoryOf(aggregateClass); + //noinspection unchecked + return (A) repository.load(key); + } + + // --------------------------- AggAssemblerWithRepoAndFactProvider methods + + @Override + public List orFail() throws AggregateNotFoundException { + List aggregateRoots = new ArrayList(dtos.size()); + for (Object dto : dtos) { + Object id = resolveId(dto, aggregateClass); + A a = loadFromRepo(aggregateClass, id); + + if (a == null) { + throw new AggregateNotFoundException(String.format("Unable to load aggregate %s for id: %s", aggregateClass.getName(), id)); + } + + aggregateRoots.add(assembleWithDto(a, dto)); + } + return aggregateRoots; + } + + @Override + public List thenFromFactory() { + boolean atLeastOneAggregateNotFound = false; + boolean atLeastOneAggregateFound = false; + List aggregateRoots = new ArrayList(dtos.size()); + + // load from the repository + for (Object dto : dtos) { + Object id = resolveId(dto, aggregateClass); + A a = loadFromRepo(aggregateClass, id); + if (a == null) { + atLeastOneAggregateNotFound = true; + } else { + atLeastOneAggregateFound = true; + aggregateRoots.add(a); + } + if (atLeastOneAggregateFound && atLeastOneAggregateNotFound) { + throw new IllegalStateException("State non consistent some aggregate are persisted but not all."); + } + } + + if (atLeastOneAggregateNotFound) { + // Then if none aggregate were persisted, fallback on factory + return fromFactory(); + } else { + return aggregateRoots; + } + } + +} diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AssembleImpl.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AssembleImpl.java index 3f6e355a..cf4a08e0 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AssembleImpl.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AssembleImpl.java @@ -25,60 +25,50 @@ */ public class AssembleImpl implements Assemble, AssembleSecurely { - private final AssemblerContext assemblerContext = new AssemblerContext(); - @Inject private InternalRegistry registry; + private boolean dataSecurityEnabled = false; + /** * Constructor. - *

- * Disable the data security feature by default. - *

*/ public AssembleImpl() { - assemblerContext.setSecured(false); } @Override - public AggsAssemblerProvider dtos(List dtos) { - assemblerContext.setDtos(dtos); - return new AggAssemblerProviderImpl(registry, assemblerContext); + public AggsAssemblerProvider dtos(List dtos) { + return new AggsAssemblerProviderImpl(registry, dtos); } @Override - public AggAssemblerProvider dto(Object dto) { - assemblerContext.setDto(dto); - return new AggAssemblerProviderImpl(registry, assemblerContext); + public AggAssemblerProvider dto(D dto) { + return new AggAssemblerProviderImpl(registry, dto); } @Override public DtoAssemblerProvider aggregate(AggregateRoot aggregateRoot) { - assemblerContext.setAggregate(aggregateRoot); - return new DtoAssemblerProviderImpl(registry, assemblerContext); + return new DtoAssemblerProviderImpl(registry, aggregateRoot); } @Override public DtosAssemblerProvider aggregates(List> aggregateRoots) { - assemblerContext.setAggregates((List>) aggregateRoots); - return new DtosAssemblerProviderImpl(registry, assemblerContext); + return new DtosAssemblerProviderImpl(registry, aggregateRoots, null); } @Override public DtoAssemblerProvider tuple(Tuple aggregateRoots) { - assemblerContext.setAggregateTuple(aggregateRoots); - return new DtoAssemblerProviderImpl(registry, assemblerContext); + return new DtoAssemblerProviderImpl(registry, aggregateRoots); } @Override public DtosAssemblerProvider tuples(List aggregateRoots) { - assemblerContext.setAggregateTuples(aggregateRoots); - return new DtosAssemblerProviderImpl(registry, assemblerContext); + return new DtosAssemblerProviderImpl(registry, null, aggregateRoots); } @Override public Assemble securely() { - assemblerContext.setSecured(true); + dataSecurityEnabled = true; return this; } } diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AssemblerContext.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AssemblerContext.java deleted file mode 100644 index 87e59a41..00000000 --- a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/AssemblerContext.java +++ /dev/null @@ -1,151 +0,0 @@ -/** - * Copyright (c) 2013-2015 by The SeedStack authors. All rights reserved. - * - * This file is part of SeedStack, An enterprise-oriented full development stack. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package org.seedstack.business.core.interfaces.assembler.dsl; - -import org.javatuples.Tuple; -import org.seedstack.business.api.domain.AggregateRoot; -import org.seedstack.business.api.domain.Repository; - -import java.util.ArrayList; -import java.util.List; - -/** - * This class is used as a shared context inside the assembler DSL. - *

- * It is populated by the DSL methods and called at the end to build - * the final object according to the required behaviour. - *

- * @author Pierre Thirouin - */ -class AssemblerContext { - - private boolean secured = false; - - private Class> aggregateClass; - private Tuple aggregateClasses; - - // TODO : change it to - private List> aggregates = new ArrayList>(); - private List aggregateTuples; - private Tuple aggregateTuple; - - private Object dto; - private List dtos = new ArrayList(); - - private Repository repository; - - // --- - - public boolean isSecured() { - return secured; - } - - public void setSecured(boolean secured) { - this.secured = secured; - } - - - - // --- aggregate class - - // --- -- single - - public Class> getAggregateClass() { - return aggregateClass; - } - - public void setAggregateClass(Class> aggregateClass) { - this.aggregateClass = aggregateClass; - } - - // --- -- tuple - - public Tuple getAggregateClasses() { - return aggregateClasses; - } - - public void setAggregateClasses(Tuple aggregateClasses) { - this.aggregateClasses = aggregateClasses; - } - - - - // --- aggregate instance - - // --- -- single - - public List> getAggregates() { - return aggregates; - } - - public void setAggregates(List> aggregates) { - this.aggregates = aggregates; - } - - public AggregateRoot getAggregate() { - if (aggregates != null && !aggregates.isEmpty()) { - return aggregates.get(0); - } else { - return null; - } - } - - public void setAggregate(AggregateRoot aggregate) { - this.aggregates.add(aggregate); - } - - // --- -- tuple - - public List getAggregateTuples() { - return aggregateTuples; - } - - public void setAggregateTuples(List aggregateTuples) { - this.aggregateTuples = aggregateTuples; - } - - public Tuple getAggregateTuple() { - return aggregateTuple; - } - - public void setAggregateTuple(Tuple aggregateTuple) { - this.aggregateTuple= aggregateTuple; - } - - - - // --- dtos - - public List getDtos() { - return dtos; - } - - public void setDtos(List dtos) { - this.dtos = dtos; - } - - public Object getDto() { - return this.dto; - } - - public void setDto(Object dto) { - this.dto = dto; - } - - // --- repository - - public Repository getRepository() { - return repository; - } - - public void setRepository(Repository repository) { - this.repository = repository; - } -} diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/BaseAggAssemblerWithRepoProviderImpl.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/BaseAggAssemblerWithRepoProviderImpl.java index dc4a4854..83a9cf97 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/BaseAggAssemblerWithRepoProviderImpl.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/BaseAggAssemblerWithRepoProviderImpl.java @@ -12,6 +12,7 @@ import org.javatuples.Tuple; import org.seedstack.business.api.Tuples; import org.seedstack.business.api.domain.*; +import org.seedstack.business.api.interfaces.assembler.Assembler; import org.seedstack.business.api.interfaces.assembler.resolver.DtoInfoResolver; import org.seedstack.business.api.interfaces.assembler.resolver.ParameterHolder; import org.seedstack.business.core.interfaces.assembler.resolver.AnnotationResolver; @@ -28,21 +29,18 @@ /** * @author Pierre Thirouin */ -public class BaseAggAssemblerWithRepoProviderImpl { +public class BaseAggAssemblerWithRepoProviderImpl> { protected final DtoInfoResolver dtoInfoResolver = new AnnotationResolver(); - protected final AssemblerContext assemblerContext; protected final InternalRegistry registry; /** * Constructor. * * @param registry the internal registry used to get domain objects - * @param assemblerContext the assembler context which share the data given to the DSL. */ - public BaseAggAssemblerWithRepoProviderImpl(InternalRegistry registry, AssemblerContext assemblerContext) { + public BaseAggAssemblerWithRepoProviderImpl(InternalRegistry registry) { this.registry = registry; - this.assemblerContext = assemblerContext; } protected Object resolveId(Object dto, Class> aggregateRootClass) { @@ -57,7 +55,7 @@ protected Object resolveId(Object dto, Class> aggrega return paramsToIds(aggregateRootClass, parameterHolder, -1); } - protected Tuple resolveIds(Object dto, Tuple aggregateRootClasses) { + protected Tuple resolveIds(Object dto, List>> aggregateRootClasses) { SeedCheckUtils.checkIfNotNull(dto); SeedCheckUtils.checkIfNotNull(aggregateRootClasses); @@ -103,13 +101,33 @@ private Object paramsToIds(Class> aggregateRootClass, return id; } - protected Object getAggregateFromFactory(GenericFactory factory, Class> aggregateClass, Object[] parameters) { + protected A fromFactory(Class> aggregateClass, Object dto) { + GenericFactory genericFactory = (GenericFactory) registry.genericFactoryOf(aggregateClass); + ParameterHolder parameterHolder = dtoInfoResolver.resolveAggregate(dto); + A aggregateRoot = (A) getAggregateFromFactory(genericFactory, dto.getClass(), aggregateClass, parameterHolder.parameters()); + return assembleWithDto(aggregateRoot, dto); + } + + /** + * Assemble one aggregate root from a dto. + * + * @param aggregateRoots the aggregate root to assemble + * @return the assembled aggregate root + */ + protected A assembleWithDto(A aggregateRoots, Object dto) { + Assembler assembler = registry.assemblerOf((Class>) aggregateRoots.getClass(), dto.getClass()); + //noinspection unchecked + assembler.mergeAggregateWithDto(aggregateRoots, dto); + return aggregateRoots; + } + + protected Object getAggregateFromFactory(GenericFactory factory, Class dtoClass, Class> aggregateClass, Object[] parameters) { SeedCheckUtils.checkIfNotNull(factory); SeedCheckUtils.checkIfNotNull(aggregateClass); SeedCheckUtils.checkIfNotNull(parameters); if (parameters.length == 0) { - throw new IllegalArgumentException(assemblerContext.getDto().getClass() + " - No factory parameters found in the DTO. Please check the @MatchingFactoryParameter annotation."); + throw new IllegalArgumentException(dtoClass + " - No factory parameters found in the DTO. Please check the @MatchingFactoryParameter annotation."); } if (Factory.class.isAssignableFrom(factory.getClass())) { @@ -129,9 +147,9 @@ protected Object getAggregateFromFactory(GenericFactory factory, Class aggregate) { + List> aggregates = Lists.newArrayList(aggregate); + this.dtosAssemblerProvider = new DtosAssemblerProviderImpl(registry, aggregates, null); + } + + public DtoAssemblerProviderImpl(InternalRegistry registry, Tuple aggregateTuple) { + List aggregateTuples = new ArrayList(); + aggregateTuples.add(aggregateTuple); + this.dtosAssemblerProvider = new DtosAssemblerProviderImpl(registry, null, aggregateTuples); } @Override diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/DtosAssemblerProviderImpl.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/DtosAssemblerProviderImpl.java index 70f01f92..afce7cf4 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/DtosAssemblerProviderImpl.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/DtosAssemblerProviderImpl.java @@ -10,6 +10,7 @@ package org.seedstack.business.core.interfaces.assembler.dsl; import org.javatuples.Tuple; +import org.seedstack.business.api.Tuples; import org.seedstack.business.api.domain.AggregateRoot; import org.seedstack.business.api.interfaces.assembler.Assembler; import org.seedstack.business.api.interfaces.assembler.dsl.DtosAssemblerProvider; @@ -24,19 +25,18 @@ public class DtosAssemblerProviderImpl implements DtosAssemblerProvider { private InternalRegistry registry; - private final AssemblerContext context; + private final List> aggregates; + private final List aggregateTuples; - public DtosAssemblerProviderImpl(InternalRegistry registry, AssemblerContext context) { + public DtosAssemblerProviderImpl(InternalRegistry registry, List> aggregates, List aggregateTuples) { this.registry = registry; - this.context = context; + this.aggregates = aggregates; + this.aggregateTuples = aggregateTuples; } @SuppressWarnings("unchecked") @Override public List to(Class dtoClass) { - List> aggregates = context.getAggregates(); - List aggregateTuples = context.getAggregateTuples(); - Assembler assembler = getAssembler(dtoClass); List dtos = new ArrayList(); @@ -54,15 +54,15 @@ public List to(Class dtoClass) { @SuppressWarnings("unchecked") private Assembler getAssembler(Class dtoClass) { - AggregateRoot aggregate = context.getAggregate(); - Tuple aggregateTuple = context.getAggregateTuple(); Assembler assembler = null; - if (aggregate != null) { - assembler = registry.assemblerOf((Class>) aggregate.getClass(), dtoClass); - } else if (aggregateTuple != null) { - assembler = registry.tupleAssemblerOf(aggregateTuple, dtoClass); + if (aggregates != null && !aggregates.isEmpty()) { + assembler = registry.assemblerOf((Class>) aggregates.get(0).getClass(), dtoClass); + } else if (aggregateTuples != null && !aggregateTuples.isEmpty()) { + Tuple firstTuple = aggregateTuples.get(0); + List aggregateRootClasses = Tuples.toListOfClasses(firstTuple); + assembler = registry.tupleAssemblerOf((List>>) aggregateRootClasses, dtoClass); } return assembler; } diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/InternalRegistry.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/InternalRegistry.java index 0b1a54e2..deddcd83 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/InternalRegistry.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/InternalRegistry.java @@ -9,7 +9,6 @@ */ package org.seedstack.business.core.interfaces.assembler.dsl; -import org.javatuples.Tuple; import org.seedstack.business.api.domain.*; import org.seedstack.business.api.interfaces.assembler.Assembler; @@ -39,21 +38,6 @@ public interface InternalRegistry { */ Assembler assemblerOf(Class> aggregateRoot, Class dto); - /** - * Returns an BaseTupleAssembler matching the given tuple of aggregate roots and the dto class. - *

- * Be careful, contrarily to the other {@code tupleAssemblerOf()} method, it contains the - * aggregate roots and not their classes. - *

- * If no assembler were created by the client developer, the method returns an - * {@link org.seedstack.business.core.interfaces.AutomaticTupleAssembler}. - * - * @param aggregateRootTuple a tuple of aggregate root. - * @param dto the dto class - * @return the assembler - */ - Assembler tupleAssemblerOf(Tuple aggregateRootTuple, Class dto); - /** * Returns an BaseTupleAssembler matching the given list of aggregate root classes and the dto class. *

diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/InternalRegistryInternal.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/InternalRegistryInternal.java index 091472fd..6a677a1f 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/InternalRegistryInternal.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/InternalRegistryInternal.java @@ -9,19 +9,17 @@ */ package org.seedstack.business.core.interfaces.assembler.dsl; -import com.google.common.collect.Lists; import com.google.inject.ConfigurationException; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.TypeLiteral; import com.google.inject.util.Types; import org.javatuples.Tuple; +import org.seedstack.business.api.Tuples; import org.seedstack.business.api.domain.*; import org.seedstack.business.api.interfaces.assembler.Assembler; -import org.seedstack.business.api.interfaces.assembler.BaseTupleAssembler; import org.seedstack.business.core.interfaces.AutomaticAssembler; import org.seedstack.business.core.interfaces.AutomaticTupleAssembler; -import org.seedstack.business.api.Tuples; import org.seedstack.business.internal.utils.BusinessUtils; import org.seedstack.seed.core.api.Logging; import org.slf4j.Logger; @@ -69,25 +67,14 @@ public InternalRegistryInternal(Injector injector) { return o; } - @Override - public Assembler tupleAssemblerOf(Tuple aggregateRootTuple, Class dto) { - List>> aggregateClasses = Lists.newArrayList(); - for (Object o : aggregateRootTuple) { - if (!(o instanceof Class) || !AggregateRoot.class.isAssignableFrom((Class)o)) { - throw new IllegalArgumentException("The aggregateRootTuple parameter should only contain aggregates. But found " + o); - } - aggregateClasses.add((Class>) o); - } - return tupleAssemblerOf(aggregateClasses, dto); - } - @Override public Assembler tupleAssemblerOf(List>> aggregateRootTuple, Class dto) { Class tupleRawType = Tuples.classOfTuple(aggregateRootTuple); // e.g. Pair or Tiplet - ParameterizedType tupleType = Types.newParameterizedType(tupleRawType, aggregateRootTuple.toArray(new Type[aggregateRootTuple.size()])); + Type[] typeArguments = aggregateRootTuple.toArray(new Type[aggregateRootTuple.size()]); + ParameterizedType tupleType = Types.newParameterizedType(tupleRawType, typeArguments); Assembler o; try { - o = (Assembler) getInstance(BaseTupleAssembler.class, tupleType, dto, Tuple.class); + o = (Assembler) getInstance(Assembler.class, tupleType, dto); } catch (ConfigurationException e) { logger.trace("Unable to find a base tuple assembler for " + tupleType + ", fallback on automatic tuple assembler."); o = (Assembler) getInstance(AutomaticTupleAssembler.class, tupleType, dto); @@ -95,7 +82,6 @@ public InternalRegistryInternal(Injector injector) { return o; } - @Override public GenericFactory genericFactoryOf(Class> aggregateRoot) { GenericFactory o; diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/TupleAggAssemblerWithRepoProviderImpl.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/TupleAggAssemblerWithRepoProviderImpl.java index d0adbeda..1d643662 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/TupleAggAssemblerWithRepoProviderImpl.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/TupleAggAssemblerWithRepoProviderImpl.java @@ -29,8 +29,13 @@ */ public class TupleAggAssemblerWithRepoProviderImpl extends BaseAggAssemblerWithRepoProviderImpl implements TupleAggAssemblerWithRepoProvider, TupleAggAssemblerWithRepoAndFactProvider { - public TupleAggAssemblerWithRepoProviderImpl(InternalRegistry registry, AssemblerContext assemblerContext) { - super(registry, assemblerContext); + private final List>> aggregateClasses; + private final Object dto; + + public TupleAggAssemblerWithRepoProviderImpl(InternalRegistry registry, List>> aggregateClasses, Object dto) { + super(registry); + this.aggregateClasses = aggregateClasses; + this.dto = dto; } // --------------------------- TupleAggAssemblerWithRepoProvider @@ -45,13 +50,13 @@ public TupleAggAssemblerWithRepoAndFactProvider fromRepository() { @Override public T fromFactory() { List aggregateRoots = new ArrayList(); - ParameterHolder parameterHolder = dtoInfoResolver.resolveAggregate(assemblerContext.getDto()); + ParameterHolder parameterHolder = dtoInfoResolver.resolveAggregate(dto); int aggregateIndex = 0; - for (Object o : assemblerContext.getAggregateClasses()) { + for (Object o : aggregateClasses) { if (o instanceof Class) { Class> aggregateClass = (Class>) o; GenericFactory genericFactory = registry.genericFactoryOf(aggregateClass); - Object aggregate = getAggregateFromFactory(genericFactory, aggregateClass, parameterHolder.parametersOfAggregateRoot(aggregateIndex)); + Object aggregate = getAggregateFromFactory(genericFactory, dto.getClass(), aggregateClass, parameterHolder.parametersOfAggregateRoot(aggregateIndex)); aggregateRoots.add(aggregate); } else { // TODO seed exception @@ -130,12 +135,11 @@ public T thenFromFactory() { @SuppressWarnings("unchecked") private List, Object>> loadFromRepository() { - Tuple aggregateClasses = assemblerContext.getAggregateClasses(); - Tuple ids = resolveIds(assemblerContext.getDto(), aggregateClasses); + Tuple ids = resolveIds(dto, aggregateClasses); List, Object>> aggregateRoots = new ArrayList, Object>>(); for (int i = 0; i < ids.getSize(); i++) { - Class> aggregateClass = (Class>) aggregateClasses.getValue(i); + Class> aggregateClass = aggregateClasses.get(i); Object id = ids.getValue(i); Repository repository = registry.repositoryOf(aggregateClass); @@ -155,9 +159,9 @@ private List, Object>> loadFromRepository() { * @return the assembled aggregate root(s) */ protected T assembleWithDto(T aggregateRoots) { - Assembler assembler = registry.tupleAssemblerOf(assemblerContext.getAggregateClasses(), assemblerContext.getDto().getClass()); + Assembler assembler = registry.tupleAssemblerOf(aggregateClasses, dto.getClass()); //noinspection unchecked - assembler.mergeAggregateWithDto(aggregateRoots, assemblerContext.getDto()); + assembler.mergeAggregateWithDto(aggregateRoots, dto); return aggregateRoots; } diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/TupleAggsAssemblerWithRepoProviderImpl.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/TupleAggsAssemblerWithRepoProviderImpl.java new file mode 100644 index 00000000..ca3514cf --- /dev/null +++ b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/dsl/TupleAggsAssemblerWithRepoProviderImpl.java @@ -0,0 +1,192 @@ +/** + * Copyright (c) 2013-2015 by The SeedStack authors. All rights reserved. + * + * This file is part of SeedStack, An enterprise-oriented full development stack. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.seedstack.business.core.interfaces.assembler.dsl; + +import org.javatuples.Triplet; +import org.javatuples.Tuple; +import org.seedstack.business.api.Tuples; +import org.seedstack.business.api.domain.AggregateRoot; +import org.seedstack.business.api.domain.GenericFactory; +import org.seedstack.business.api.domain.Repository; +import org.seedstack.business.api.interfaces.assembler.Assembler; +import org.seedstack.business.api.interfaces.assembler.dsl.AggregateNotFoundException; +import org.seedstack.business.api.interfaces.assembler.dsl.TupleAggsAssemblerWithRepoAndFactProvider; +import org.seedstack.business.api.interfaces.assembler.dsl.TupleAggsAssemblerWithRepoProvider; +import org.seedstack.business.api.interfaces.assembler.resolver.ParameterHolder; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Pierre Thirouin + */ +public class TupleAggsAssemblerWithRepoProviderImpl extends BaseAggAssemblerWithRepoProviderImpl implements TupleAggsAssemblerWithRepoProvider, TupleAggsAssemblerWithRepoAndFactProvider { + + private final List>> aggregateClasses; + private final List dtos; + + public TupleAggsAssemblerWithRepoProviderImpl(InternalRegistry registry, List>> aggregateClasses, List dtos) { + super(registry); + this.aggregateClasses = aggregateClasses; + this.dtos = dtos; + } + + // --------------------------- TupleAggAssemblerWithRepoProvider + + @Override + public TupleAggsAssemblerWithRepoAndFactProvider fromRepository() { + // it just redirect to the good interface + return this; + } + + + @Override + public List fromFactory() { + List aggregateRootTuples = new ArrayList(dtos.size()); + for (Object dto : dtos) { + List aggregateRoots = new ArrayList(); + ParameterHolder parameterHolder = dtoInfoResolver.resolveAggregate(dto); + int aggregateIndex = 0; + for (Object o : aggregateClasses) { + if (o instanceof Class) { + Class> aggregateClass = (Class>) o; + GenericFactory genericFactory = registry.genericFactoryOf(aggregateClass); + Object aggregate = getAggregateFromFactory(genericFactory, dto.getClass(), aggregateClass, parameterHolder.parametersOfAggregateRoot(aggregateIndex)); + aggregateRoots.add(aggregate); + } else { + // TODO seed exception + throw new IllegalArgumentException(o + " should be a class. the .to(Tuple aggregateClasses) method only accepts tuple of aggregate root classes."); + } + aggregateIndex++; + } + + aggregateRootTuples.add(assembleWithDto(dto, aggregateRoots)); + } + return aggregateRootTuples; + } + + // --------------------------- TupleAggsAssemblerWithRepoAndFactProvider + + @Override + public List orFail() throws AggregateNotFoundException { + List aggregateRootTuples = new ArrayList(dtos.size()); + for (Object dto : dtos) { + // list of triplet - each triplet contains the aggregate root instance, its class and its id (useful if the AR is null). + List, Object>> aggregateRootsMetadata = loadFromRepository(dto); + + boolean shouldThrow = false; + + List> aggregateRoots = new ArrayList>(); + + StringBuilder stringBuilder = new StringBuilder().append("Unable to load "); + for (Triplet, Object> triplet : aggregateRootsMetadata) { + + if (triplet.getValue0() == null) { + // If at least one aggregate root is null we throw a AggregateNotFoundException + shouldThrow = true; + stringBuilder.append("aggregate: ").append(triplet.getValue1()).append(" for id: ").append(triplet.getValue2()); + } else { + aggregateRoots.add((AggregateRoot) triplet.getValue0()); + } + } + + if (shouldThrow) { + throw new AggregateNotFoundException(stringBuilder.toString()); + } + + aggregateRootTuples.add(assembleWithDto(dto, aggregateRoots)); + } + return aggregateRootTuples; + } + + @Override + public List thenFromFactory() { + boolean atLeastOneAggregateNotFound = false; + boolean atLeastOneAggregateFound = false; + List aggregateRootTuples = new ArrayList(dtos.size()); + + // load from the repository + for (Object dto : dtos) { + // list of triplet - each triplet contains the aggregate root instance, + // its class and its id (useful if the AR is null). + List, Object>> aggregateRootsMetadata = loadFromRepository(dto); + + List> aggregateRoots = new ArrayList>(); + + StringBuilder errorMessage = new StringBuilder().append("Unable to load "); + for (Triplet, Object> triplet : aggregateRootsMetadata) { + + if (triplet.getValue0() == null) { + errorMessage.append("aggregate: ").append(triplet.getValue1()).append(" for id: ").append(triplet.getValue2()); + } else { + aggregateRoots.add((AggregateRoot) triplet.getValue0()); + } + } + + if (aggregateRoots.isEmpty()) { + // No aggregate root persisted -> fallback on factories + atLeastOneAggregateNotFound = true; + } else if (aggregateRootsMetadata.size() != aggregateRoots.size()) { + // data are inconsistent some required aggregate roots are persisted but not all + throw new IllegalStateException(errorMessage.toString()); + } else { + // all aggregate roots are loaded -> assemble them and return them + atLeastOneAggregateFound = true; + + aggregateRootTuples.add(assembleWithDto(dto, aggregateRoots)); + } + + + if (atLeastOneAggregateFound && atLeastOneAggregateNotFound) { + throw new IllegalStateException("State non consistent some aggregate are persisted but not all."); + } + } + + if (atLeastOneAggregateNotFound) { + // Then if none aggregate were persisted, fallback on factory + return fromFactory(); + } else { + return aggregateRootTuples; + } + } + + + private List, Object>> loadFromRepository(Object dto) { + Tuple ids = resolveIds(dto, aggregateClasses); + + List, Object>> aggregateRoots = new ArrayList, Object>>(); + for (int i = 0; i < ids.getSize(); i++) { + Class> aggregateClass = aggregateClasses.get(i); + Object id = ids.getValue(i); + + Repository repository = registry.repositoryOf(aggregateClass); + AggregateRoot aggregateRoot = repository.load(id); + + aggregateRoots.add(new Triplet, Object>(aggregateRoot, aggregateClass, id)); + } + + return aggregateRoots; + } + + /** + * Assemble one or a tuple of aggregate root from a dto. + * + * @param aggregateRoots the aggregate root(s) to assemble + * @return the assembled aggregate root(s) + */ + protected T assembleWithDto(Object dto, List aggregateRoots) { + T aggregateRootTuple = Tuples.create(aggregateRoots); + Assembler assembler = registry.tupleAssemblerOf(aggregateClasses, dto.getClass()); + //noinspection unchecked + assembler.mergeAggregateWithDto(aggregateRootTuple, dto); + return aggregateRootTuple; + } + +} diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/resolver/AnnotationResolver.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/resolver/AnnotationResolver.java index 407d50c3..160b4fc5 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/resolver/AnnotationResolver.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/resolver/AnnotationResolver.java @@ -48,10 +48,10 @@ public ParameterHolder resolveId(Object dto) { + " don't forget to specify the index to indicate the matching parameter: @" + MATCHING_ENTITY_ID + "(index = 0)"; throw new IllegalArgumentException(message); } - parameterHolder.put(method.getName(), annotation.typeIndex(), -1, getAttributeFromMethod(dto, method)); // The index set to -1 as it is another use case + parameterHolder.put(method.toString(), annotation.typeIndex(), -1, getAttributeFromMethod(dto, method)); // The index set to -1 as it is another use case } else { - parameterHolder.put(method.getName(), annotation.typeIndex(), annotation.index(), getAttributeFromMethod(dto, method)); + parameterHolder.put(method.toString(), annotation.typeIndex(), annotation.index(), getAttributeFromMethod(dto, method)); } } } diff --git a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/resolver/ParameterHolderInternal.java b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/resolver/ParameterHolderInternal.java index 3b97b565..01fd9d59 100644 --- a/core/src/main/java/org/seedstack/business/core/interfaces/assembler/resolver/ParameterHolderInternal.java +++ b/core/src/main/java/org/seedstack/business/core/interfaces/assembler/resolver/ParameterHolderInternal.java @@ -37,7 +37,7 @@ public void put(String sourceMethod, int aggregateIndex, int index, Object value if (parameters.get(index) != null) { String message = String.format("%s - the parameter at the index %d is already specified", sourceMethod, index); if (aggregateIndex > -1) { - message += " for the aggregate root " + aggregateIndex; + message += " for the typeIndex=" + aggregateIndex; } throw new IllegalArgumentException(message); } diff --git a/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerProviderImplTest.java b/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerProviderImplTest.java index c8cdffed..c066f4e5 100644 --- a/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerProviderImplTest.java +++ b/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerProviderImplTest.java @@ -11,13 +11,14 @@ import com.google.common.collect.Lists; import org.assertj.core.api.Assertions; +import org.javatuples.Pair; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; +import org.seedstack.business.api.domain.AggregateRoot; import org.seedstack.business.api.interfaces.assembler.Assembler; -import org.seedstack.business.core.interfaces.assembler.dsl.fixture.AutoAssembler; -import org.seedstack.business.core.interfaces.assembler.dsl.fixture.Order; -import org.seedstack.business.core.interfaces.assembler.dsl.fixture.OrderDto; +import org.seedstack.business.core.interfaces.DefaultTupleAssembler; +import org.seedstack.business.core.interfaces.assembler.dsl.fixture.*; import java.util.List; @@ -26,43 +27,39 @@ */ public class AggAssemblerProviderImplTest { - private AggAssemblerProviderImpl underTest; - private InternalRegistry registry; + @SuppressWarnings("unchecked") @Before public void before() { registry = Mockito.mock(InternalRegistryInternal.class); + Mockito.when(registry.assemblerOf(Order.class, OrderDto.class)).thenReturn((Assembler) new AutoAssembler()); + + List aggregateRootTuple = Lists.newArrayList(Order.class, Customer.class); + Mockito.when(registry.tupleAssemblerOf((List>>) aggregateRootTuple, Recipe.class)). + thenReturn((Assembler) new DefaultTupleAssembler, Recipe>(new Object[]{null, Recipe.class})); } - @SuppressWarnings("unchecked") @Test public void testToAggregate() { - Mockito.when(registry.assemblerOf(Order.class, OrderDto.class)).thenReturn((Assembler) new AutoAssembler()); - - AssemblerContext context = new AssemblerContext(); - context.setDto(new OrderDto("1", "lightsaber")); + AggAssemblerProviderImpl underTest = new AggAssemblerProviderImpl(registry, new OrderDto("1", "lightsaber")); - underTest = new AggAssemblerProviderImpl(registry, context); Order order = underTest.to(new Order()); Assertions.assertThat(order.getProduct()).isEqualTo("lightsaber"); } - @SuppressWarnings("unchecked") @Test public void testToAggregateTuple() { - Mockito.when(registry.assemblerOf(Order.class, OrderDto.class)).thenReturn((Assembler) new AutoAssembler()); - - AssemblerContext context = new AssemblerContext(); - context.setDtos(Lists.newArrayList(new OrderDto("1", "lightsaber"), new OrderDto("1", "death star"))); - underTest = new AggAssemblerProviderImpl(registry, context); - List order = underTest.to(Lists.newArrayList(new Order(), new Order())); + Recipe recipe = new Recipe("customer1", "luke", "order1", "lightsaber"); + AggAssemblerProviderImpl underTest = new AggAssemblerProviderImpl(registry, recipe); + Pair order = underTest.to(new Order(), new Customer("customer1")); - Assertions.assertThat(order).isNotNull(); - Assertions.assertThat(order).isNotEmpty(); - Assertions.assertThat(order.get(0).getProduct()).isEqualTo("lightsaber"); - Assertions.assertThat(order.get(1).getProduct()).isEqualTo("death star"); + Assertions.assertThat((Iterable) order).isNotNull(); + Assertions.assertThat((Iterable) order).isNotEmpty(); + Assertions.assertThat(order.getValue0().getProduct()).isEqualTo("lightsaber"); + Assertions.assertThat(order.getValue1().getEntityId()).isEqualTo("customer1"); + Assertions.assertThat(order.getValue1().getName()).isEqualTo("luke"); } } diff --git a/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerWithRepoProviderImplTest.java b/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerWithRepoProviderImplTest.java index 7b1f1e5a..dd22d911 100644 --- a/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerWithRepoProviderImplTest.java +++ b/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/AggAssemblerWithRepoProviderImplTest.java @@ -31,6 +31,7 @@ public class AggAssemblerWithRepoProviderImplTest { private OrderFactory orderFactory; private Repository repository; + @SuppressWarnings("unchecked") @Before public void before() { registry = Mockito.mock(InternalRegistryInternal.class); @@ -38,16 +39,11 @@ public void before() { orderFactory = new OrderFactoryInternal(); order = new Order("1", "death star"); - AssemblerContext context = new AssemblerContext(); - context.setDto(new OrderDto("1", "lightsaber")); - context.setAggregateClass(Order.class); - Mockito.when(registry.repositoryOf(Order.class)).thenReturn((Repository) repository); Mockito.when(registry.genericFactoryOf(Order.class)).thenReturn((GenericFactory)orderFactory); Mockito.when(registry.assemblerOf(Order.class, OrderDto.class)).thenReturn((Assembler) new AutoAssembler()); - //Mockito.when(injector.getInstance(Key.get(TypeLiteral.get(Types.newParameterizedType(Factory.class, aggregateIdClass))))).thenReturn((Assembler)new AutoAssembler()); - underTest = new AggAssemblerWithRepoProviderImpl(registry, context); + underTest = new AggAssemblerWithRepoProviderImpl(registry, Order.class, new OrderDto("1", "lightsaber")); } @Test diff --git a/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/AssembleTest.java b/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/AssembleTest.java index d7bdd9a5..d8e73ddd 100644 --- a/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/AssembleTest.java +++ b/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/AssembleTest.java @@ -49,7 +49,7 @@ public void testDsl() { order = fluently.assemble().securely().dto(orderDto).to(Order.class).fromFactory(); // list of dto to tuple of aggregates - Pair orderCustomerPair = fluently.assemble().dto(orderDto).>to(Order.class, Customer.class).fromFactory(); + Pair orderCustomerPair = fluently.assemble().dto(orderDto).to(Order.class, Customer.class).fromFactory(); // list of dtos to list of aggregates orders = fluently.assemble().dtos(dtos).to(orders); diff --git a/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/DtoAssemblerProviderImplTest.java b/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/DtoAssemblerProviderImplTest.java index 1b64c875..1b7cbaf6 100644 --- a/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/DtoAssemblerProviderImplTest.java +++ b/core/src/test/java/org/seedstack/business/core/interfaces/assembler/dsl/DtoAssemblerProviderImplTest.java @@ -34,18 +34,21 @@ public class DtoAssemblerProviderImplTest { private InternalRegistry registry; @Before + @SuppressWarnings("unchecked") public void before() { registry = Mockito.mock(InternalRegistryInternal.class); + Mockito.when(registry.assemblerOf(Order.class, OrderDto.class)).thenReturn((Assembler) new AutoAssembler()); + + List>> aggregateRootClasses = new ArrayList>>(); + aggregateRootClasses.add(Order.class); + aggregateRootClasses.add(Customer.class); + Mockito.when(registry.tupleAssemblerOf(aggregateRootClasses, OrderDto.class)).thenReturn((Assembler) new AutoTupleAssembler()); } @Test public void testToDto() { - Mockito.when(registry.assemblerOf(Order.class, OrderDto.class)).thenReturn((Assembler) new AutoAssembler()); - - AssemblerContext context = new AssemblerContext(); - context.setAggregate(new Order("lightsaber")); + underTest = new DtoAssemblerProviderImpl(registry, new Order("lightsaber")); - underTest = new DtoAssemblerProviderImpl(registry, context); OrderDto orderDto = underTest.to(OrderDto.class); Assertions.assertThat(orderDto).isNotNull(); @@ -57,12 +60,7 @@ public void testToDto() { public void testToDtoWithTuple() { Tuple tuple = Tuples.create(new Order("lightsaber"), new Customer("luke")); - Mockito.when(registry.tupleAssemblerOf(tuple, OrderDto.class)).thenReturn((Assembler)new AutoTupleAssembler()); - - AssemblerContext context = new AssemblerContext(); - context.setAggregateTuple(tuple); - - underTest = new DtoAssemblerProviderImpl(registry, context); + underTest = new DtoAssemblerProviderImpl(registry, tuple); OrderDto orderDto = underTest.to(OrderDto.class); Assertions.assertThat(orderDto).isNotNull(); @@ -72,16 +70,11 @@ public void testToDtoWithTuple() { @Test public void testToDtos() { - Mockito.when(registry.assemblerOf(Order.class, OrderDto.class)).thenReturn((Assembler)new AutoAssembler()); - - AssemblerContext context = new AssemblerContext(); - // TODO : try to add the possibility to pass a List>, e.g. List - List> aggregateRoots = new ArrayList>(); + List aggregateRoots = new ArrayList(); aggregateRoots.add(new Order("lightsaber")); aggregateRoots.add(new Order("death star")); - context.setAggregates(aggregateRoots); - underTest2 = new DtosAssemblerProviderImpl(registry, context); + underTest2 = new DtosAssemblerProviderImpl(registry, aggregateRoots, null); List orderDtos = underTest2.to(OrderDto.class); Assertions.assertThat(orderDtos).isNotNull(); @@ -94,13 +87,9 @@ public void testToDtos() { @Ignore public void testToDtosWithTuple() { Tuple tuple1 = Tuples.create(new Order("lightsaber"), new Customer("luke")); // used to get the class of the tuple - Mockito.when(registry.tupleAssemblerOf(tuple1, OrderDto.class)).thenReturn((Assembler)new AutoTupleAssembler()); - - AssemblerContext context = new AssemblerContext(); Tuple tuple2 = Tuples.create(new Order("death star"), new Customer("dark vador")); - context.setAggregateTuples(Lists.newArrayList(tuple1, tuple2)); - underTest2 = new DtosAssemblerProviderImpl(registry, context); + underTest2 = new DtosAssemblerProviderImpl(registry, null, Lists.newArrayList(tuple1, tuple2)); List orderDtos = underTest2.to(OrderDto.class); Assertions.assertThat(orderDtos).isNotNull(); diff --git a/core/src/test/java/org/seedstack/business/internal/domain/DefaultRepositoryProviderTest.java b/core/src/test/java/org/seedstack/business/internal/domain/DefaultRepositoryProviderTest.java deleted file mode 100644 index ade1bbcb..00000000 --- a/core/src/test/java/org/seedstack/business/internal/domain/DefaultRepositoryProviderTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2013-2015 by The SeedStack authors. All rights reserved. - * - * This file is part of SeedStack, An enterprise-oriented full development stack. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package org.seedstack.business.internal.domain; - -import org.seedstack.business.core.domain.InMemoryRepository; -import org.seedstack.business.internal.strategy.api.GenericImplementationProvider; -import org.seedstack.business.fixtures.domain.customer.Customer; -import org.seedstack.business.fixtures.domain.customer.CustomerId; - -/** - * @author pierre.thirouin@ext.mpsa.com - * Date: 26/09/2014 - */ -public class DefaultRepositoryProviderTest { - -// @Test - public void create_default_repository() { - GenericImplementationProvider provider = new GenericImplementationProvider(InMemoryRepository.class, Customer.class, CustomerId.class); - // Repository repository = provider.get(); -// Assertions.assertThat(repository).isNotNull(); -// Assertions.assertThat(repository).isInstanceOf(InMemoryRepository.class); -// Assertions.assertThat(repository.getAggregateRootClass()).isEqualTo(Customer.class); -// Assertions.assertThat(repository.getKeyClass()).isEqualTo(CustomerId.class); - } -} diff --git a/specs/src/main/java/org/seedstack/business/api/Tuples.java b/specs/src/main/java/org/seedstack/business/api/Tuples.java index 77ff4b0a..2f3d026e 100644 --- a/specs/src/main/java/org/seedstack/business/api/Tuples.java +++ b/specs/src/main/java/org/seedstack/business/api/Tuples.java @@ -16,6 +16,7 @@ import org.seedstack.seed.core.utils.SeedCheckUtils; import java.lang.reflect.ParameterizedType; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -160,4 +161,21 @@ public static Class classOfTuple(Object... objects) { public static ParameterizedType typeOfTuple(Class... classes) { return Types.newParameterizedType(classOfTuple(classes), classes); } + + public static List toList(Tuple tuple) { + List objects = new ArrayList(tuple.getSize()); + for (Object o : tuple) { + objects.add(o); + } + //noinspection unchecked + return (List) objects; + } + + public static List toListOfClasses(Tuple tuple) { + List> objects = new ArrayList>(tuple.getSize()); + for (Object o : tuple) { + objects.add(o.getClass()); + } + return objects; + } } \ No newline at end of file diff --git a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/FluentAssembler.java b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/FluentAssembler.java index b167045f..f86df665 100644 --- a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/FluentAssembler.java +++ b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/FluentAssembler.java @@ -9,6 +9,7 @@ */ package org.seedstack.business.api.interfaces.assembler; +import com.google.gag.annotation.team.Visionary; import org.seedstack.business.api.interfaces.assembler.dsl.AssembleSecurely; /** @@ -21,6 +22,7 @@ * * @author Pierre Thirouin */ +@Visionary("Epo Jemba") public interface FluentAssembler { /** diff --git a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggAssemblerProvider.java b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggAssemblerProvider.java index f1227d0e..fda43ffd 100644 --- a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggAssemblerProvider.java +++ b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggAssemblerProvider.java @@ -9,12 +9,108 @@ */ package org.seedstack.business.api.interfaces.assembler.dsl; +import org.javatuples.*; import org.seedstack.business.api.domain.AggregateRoot; +import java.util.List; + /** -* @author Pierre Thirouin -*/ -public interface AggAssemblerProvider extends BaseAggAssemblerProvider { + * @author Pierre Thirouin + */ +public interface AggAssemblerProvider { + + /** + * Assembles the dto to an aggregate root. + * + * @param aggregateRootClass the aggregate root class + * @param the type of aggregate root + * @return the assembler DSL to assemble an aggregate root + */ + > AggAssemblerWithRepoProvider to(Class aggregateRootClass); > A to(A aggregateRoot); + + // --- The above methods are for tuples of instances --- + + , A2 extends AggregateRoot> + Pair to(A1 first, A2 second); + + , A2 extends AggregateRoot, A3 extends AggregateRoot> + Triplet to(A1 first, A2 second, A3 third); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot> + Quartet to(A1 first, A2 second, A3 third, A4 fourth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot> + Quintet to(A1 first, A2 second, A3 third, A4 fourth, A5 fifth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot> + Sextet to(A1 first, A2 second, A3 third, A4 fourth, A5 fifth, A6 sixth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot> + Septet to(A1 first, A2 second, A3 third, A4 fourth, A5 fifth, A6 sixth, A7 seventh); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot> + Octet to(A1 first, A2 second, A3 third, A4 fourth, A5 fifth, A6 sixth, A7 seventh, A8 eighth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot, A9 extends AggregateRoot> + Ennead to(A1 first, A2 second, A3 third, A4 fourth, A5 fifth, A6 sixth, A7 seventh, A8 eighth, A9 ninth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot, A9 extends AggregateRoot, A10 extends AggregateRoot> + Decade to(A1 first, A2 second, A3 third, A4 fourth, A5 fifth, A6 sixth, A7 seventh, A8 eighth, A9 ninth, A10 tenth); + + // --- The above method are tuples of classes + + , A2 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second); + + , A2 extends AggregateRoot, A3 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh, Class eighth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot, A9 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh, Class eighth, Class ninth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot, A9 extends AggregateRoot, A10 extends AggregateRoot> + TupleAggAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh, Class eighth, Class ninth, Class tenth); + + /** + * Assemble the dto into a tuple of aggregate roots. This method is not recommended. + *

+ * If you can, use the method matching the number of aggregate roots you have in the tuple. For instance use + * {@link #to(Class, Class)} for a {@code Pair<Customer, Order>} it will return a more typed result. + *

+ * + * @param aggregateRootClasses a list of aggregate root classes + * @return a tuple of aggregate roots + */ + TupleAggAssemblerWithRepoProvider to(List>> aggregateRootClasses); + + /** + * Assemble the dto into a tuple of aggregate roots. This method is not recommended. + *

+ * If you can, use the method matching the number of aggregate roots you have in the tuple. For instance use + * {@link #to(org.seedstack.business.api.domain.AggregateRoot, org.seedstack.business.api.domain.AggregateRoot)} + * for a {@code Pair<Customer, Order>} it will return a more typed result. + *

+ * + * @param aggregateRoots a list of aggregate root classes + * @return a tuple of aggregate roots + */ + Tuple to(Tuple aggregateRoots); + } diff --git a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggsAssemblerProvider.java b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggsAssemblerProvider.java index ce11865a..2f7bb36f 100644 --- a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggsAssemblerProvider.java +++ b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggsAssemblerProvider.java @@ -9,6 +9,7 @@ */ package org.seedstack.business.api.interfaces.assembler.dsl; +import org.javatuples.*; import org.seedstack.business.api.domain.AggregateRoot; import java.util.List; @@ -16,7 +17,44 @@ /** * @author Pierre Thirouin */ -public interface AggsAssemblerProvider extends BaseAggAssemblerProvider { +public interface AggsAssemblerProvider { + + /** + * Assembles the list of dtos to a list of aggregate roots. + * + * @param aggregateRootClass the aggregate root class + * @param
the type of aggregate root + * @return the assembler DSL to a list of aggregate roots + */ + > AggsAssemblerWithRepoProvider to(Class aggregateRootClass); > List to(List aggregateRoots); + + , A2 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second); + + , A2 extends AggregateRoot, A3 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh, Class eighth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot, A9 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh, Class eighth, Class ninth); + + , A2 extends AggregateRoot, A3 extends AggregateRoot, A4 extends AggregateRoot, A5 extends AggregateRoot, A6 extends AggregateRoot, A7 extends AggregateRoot, A8 extends AggregateRoot, A9 extends AggregateRoot, A10 extends AggregateRoot> + TupleAggsAssemblerWithRepoProvider> to(Class first, Class second, Class third, Class fourth, Class fifth, Class sixth, Class seventh, Class eighth, Class ninth, Class tenth); + } diff --git a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggsAssemblerWithRepoAndFactProvider.java b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggsAssemblerWithRepoAndFactProvider.java new file mode 100644 index 00000000..c86c3117 --- /dev/null +++ b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggsAssemblerWithRepoAndFactProvider.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2013-2015 by The SeedStack authors. All rights reserved. + * + * This file is part of SeedStack, An enterprise-oriented full development stack. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.seedstack.business.api.interfaces.assembler.dsl; + +import org.seedstack.business.api.domain.AggregateRoot; + +import java.util.List; + +/** +* @author Pierre Thirouin +*/ +public interface AggsAssemblerWithRepoAndFactProvider> { + + List orFail() throws AggregateNotFoundException; + + List thenFromFactory(); + +} diff --git a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggsAssemblerWithRepoProvider.java b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggsAssemblerWithRepoProvider.java new file mode 100644 index 00000000..549d9d27 --- /dev/null +++ b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/AggsAssemblerWithRepoProvider.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2013-2015 by The SeedStack authors. All rights reserved. + * + * This file is part of SeedStack, An enterprise-oriented full development stack. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.seedstack.business.api.interfaces.assembler.dsl; + +import org.seedstack.business.api.domain.AggregateRoot; + +import java.util.List; + +/** +* @author Pierre Thirouin +*/ +public interface AggsAssemblerWithRepoProvider> { + + AggsAssemblerWithRepoAndFactProvider fromRepository(); + + List fromFactory(); + +} diff --git a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/Assemble.java b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/Assemble.java index 7e6e8328..9b67fa60 100644 --- a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/Assemble.java +++ b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/Assemble.java @@ -28,7 +28,7 @@ public interface Assemble { * @param dto the list of dtos * @return an AggsAssemblerProvider */ - AggsAssemblerProvider dtos(List dto); + AggsAssemblerProvider dtos(List dto); /** * Assembles a dto. @@ -36,7 +36,7 @@ public interface Assemble { * @param dto the dto * @return an AggAssemblerProvider */ - AggAssemblerProvider dto(Object dto); + AggAssemblerProvider dto(D dto); /** * Assembles an aggregate root. diff --git a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/BaseAggAssemblerProvider.java b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/BaseAggAssemblerProvider.java deleted file mode 100644 index 531f736f..00000000 --- a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/BaseAggAssemblerProvider.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2013-2015 by The SeedStack authors. All rights reserved. - * - * This file is part of SeedStack, An enterprise-oriented full development stack. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package org.seedstack.business.api.interfaces.assembler.dsl; - - -import org.javatuples.Tuple; -import org.seedstack.business.api.domain.AggregateRoot; - -/** - * Provides methods to specify the aggregate class to which aggregate root (or tuple of aggregate root) assemble. - * - * @author Pierre Thirouin - */ -public interface BaseAggAssemblerProvider { - - /** - * Assembles to an aggregate root. - * - * @param aggregateRootClass the aggregate root class - * @param the type of aggregate root - * @return the assembler DSL to assemble an aggregate root - */ - > AggAssemblerWithRepoProvider to(Class aggregateRootClass); - - /** - * Assembles to a tuple of aggregate roots. - *

- * The parameters are cut in three in order to not conflict with the non tuple method. - *

- * - * @param firstAggregateClass the first aggregate root class of the tuple - * @param secondAggregateClass the second class - * @param otherAggregateClasses and the rest - * @param The tuple type - * @return the assembler DSL to assemble a tuple of aggregate roots - */ - TupleAggAssemblerWithRepoProvider to(Class> firstAggregateClass, Class> secondAggregateClass, Class>... otherAggregateClasses); -} diff --git a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/TupleAggsAssemblerWithRepoAndFactProvider.java b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/TupleAggsAssemblerWithRepoAndFactProvider.java new file mode 100644 index 00000000..2ad9b80b --- /dev/null +++ b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/TupleAggsAssemblerWithRepoAndFactProvider.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2013-2015 by The SeedStack authors. All rights reserved. + * + * This file is part of SeedStack, An enterprise-oriented full development stack. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.seedstack.business.api.interfaces.assembler.dsl; + +import org.javatuples.Tuple; + +import java.util.List; + +/** + * @author Pierre Thirouin + */ +public interface TupleAggsAssemblerWithRepoAndFactProvider { + + List orFail() throws AggregateNotFoundException; + + List thenFromFactory(); +} diff --git a/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/TupleAggsAssemblerWithRepoProvider.java b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/TupleAggsAssemblerWithRepoProvider.java new file mode 100644 index 00000000..183de496 --- /dev/null +++ b/specs/src/main/java/org/seedstack/business/api/interfaces/assembler/dsl/TupleAggsAssemblerWithRepoProvider.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2013-2015 by The SeedStack authors. All rights reserved. + * + * This file is part of SeedStack, An enterprise-oriented full development stack. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.seedstack.business.api.interfaces.assembler.dsl; + +import org.javatuples.Tuple; + +import java.util.List; + +/** + * @author Pierre Thirouin + */ +public interface TupleAggsAssemblerWithRepoProvider { + + TupleAggsAssemblerWithRepoAndFactProvider fromRepository(); + + List fromFactory(); +} diff --git a/specs/src/test/java/org/seedstack/business/api/TuplesTest.java b/specs/src/test/java/org/seedstack/business/api/TuplesTest.java index 59dee021..35a14c52 100644 --- a/specs/src/test/java/org/seedstack/business/api/TuplesTest.java +++ b/specs/src/test/java/org/seedstack/business/api/TuplesTest.java @@ -12,12 +12,11 @@ import com.google.common.collect.Lists; import com.google.inject.util.Types; import org.assertj.core.api.Assertions; -import org.javatuples.Pair; -import org.javatuples.Triplet; -import org.javatuples.Tuple; +import org.javatuples.*; import org.junit.Test; import java.lang.reflect.Type; +import java.util.ArrayList; import java.util.List; /** @@ -44,7 +43,7 @@ public void testCreateTupleFromVarArgs() { @Test public void testCreateTupleFromList() { - List classes = Lists.newArrayList(String.class, Long.class); + List classes = Lists.>newArrayList(String.class, Long.class); Tuple tuple = Tuples.create(classes); Assertions.assertThat((Iterable) tuple).isInstanceOf(Pair.class); @@ -52,10 +51,47 @@ public void testCreateTupleFromList() { Assertions.assertThat(tuple.getSize()).isEqualTo(2); } + @Test + public void testClassOfTupleFromList() { + List> classes = new ArrayList>(); + classes.add(String.class); + classes.add(Long.class); + + Class type = Tuples.classOfTuple(classes); + Assertions.assertThat(type).isEqualTo(Pair.class); + } + @Test public void testClassOfTuple() { - Class type = Tuples.classOfTuple(String.class, Long.class); + Class type = Tuples.classOfTuple(String.class); + Assertions.assertThat(type).isEqualTo(Unit.class); + + type = Tuples.classOfTuple(String.class, Integer.class); Assertions.assertThat(type).isEqualTo(Pair.class); + + type = Tuples.classOfTuple(String.class, Integer.class, Long.class); + Assertions.assertThat(type).isEqualTo(Triplet.class); + + type = Tuples.classOfTuple(String.class, Integer.class, Long.class, Float.class); + Assertions.assertThat(type).isEqualTo(Quartet.class); + + type = Tuples.classOfTuple(String.class, Integer.class, Long.class, Float.class, Boolean.class); + Assertions.assertThat(type).isEqualTo(Quintet.class); + + type = Tuples.classOfTuple(String.class, Integer.class, Long.class, Float.class, Boolean.class, Byte.class); + Assertions.assertThat(type).isEqualTo(Sextet.class); + + type = Tuples.classOfTuple(String.class, Integer.class, Long.class, Float.class, Boolean.class, Byte.class, Short.class); + Assertions.assertThat(type).isEqualTo(Septet.class); + + type = Tuples.classOfTuple(String.class, Integer.class, Long.class, Float.class, Boolean.class, Byte.class, Short.class, Double.class); + Assertions.assertThat(type).isEqualTo(Octet.class); + + type = Tuples.classOfTuple(String.class, Integer.class, Long.class, Float.class, Boolean.class, Byte.class, Short.class, Double.class, Number.class); + Assertions.assertThat(type).isEqualTo(Ennead.class); + + type = Tuples.classOfTuple(String.class, Integer.class, Long.class, Float.class, Boolean.class, Byte.class, Short.class, Double.class, Number.class, Character.class); + Assertions.assertThat(type).isEqualTo(Decade.class); } @Test