Skip to content

Commit 242a85b

Browse files
authored
AR-6 bugfix: ensure there is only one aggregate root after merging (#81)
1 parent 770cfad commit 242a85b

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
BoundedContext AnotherContext {
2+
Aggregate agg1 {
3+
Entity MyEntity {
4+
aggregateRoot
5+
}
6+
}
7+
8+
Aggregate agg2 {
9+
Entity MyOtherEntity {
10+
aggregateRoot
11+
}
12+
}
13+
}

org.contextmapper.dsl.tests/src/org/contextmapper/dsl/tests/refactoring/MergeAggregatesTest.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.contextmapper.dsl.contextMappingDSL.UpstreamDownstreamRelationship;
1919
import org.contextmapper.dsl.refactoring.MergeAggregatesRefactoring;
2020
import org.contextmapper.dsl.refactoring.exception.RefactoringInputException;
21+
import org.contextmapper.tactic.dsl.tacticdsl.DomainObject;
2122
import org.eclipse.emf.ecore.resource.Resource;
2223
import org.eclipse.xtext.xbase.lib.IteratorExtensions;
2324
import org.junit.jupiter.api.Assertions;
@@ -214,7 +215,7 @@ void canTakeAttributesFromFirstAggregateByDefault() throws IOException {
214215
assertEquals("agg1", aggregate.getName());
215216
assertEquals("TeamA", aggregate.getOwner().getName());
216217
}
217-
218+
218219
@Test
219220
void canTakeAttributesFromSecondAggregate() throws IOException {
220221
// given
@@ -238,4 +239,26 @@ void canTakeAttributesFromSecondAggregate() throws IOException {
238239
assertEquals("TeamB", aggregate.getOwner().getName());
239240
}
240241

242+
@Test
243+
void canHandleAggregateRoots() throws IOException {
244+
// given
245+
String inputModelName = "merge-aggregates-test-6-input.cml";
246+
Resource input = getResourceCopyOfTestCML(inputModelName);
247+
MergeAggregatesRefactoring refactoring = new MergeAggregatesRefactoring("agg1", "agg2", true);
248+
249+
// when
250+
refactoring.doRefactor(input);
251+
252+
// then
253+
List<ContextMappingModel> contextMappingModels = IteratorExtensions
254+
.<ContextMappingModel>toList(Iterators.<ContextMappingModel>filter(reloadResource(input).getAllContents(), ContextMappingModel.class));
255+
assertEquals(1, contextMappingModels.get(0).getBoundedContexts().size());
256+
BoundedContext bc = contextMappingModels.get(0).getBoundedContexts().get(0);
257+
assertEquals(1, bc.getAggregates().size());
258+
Aggregate aggregate = bc.getAggregates().get(0);
259+
List<DomainObject> aggregateRoots = aggregate.getDomainObjects().stream().filter(o -> o instanceof DomainObject).map(o -> (DomainObject) o).filter(o -> o.isAggregateRoot())
260+
.collect(Collectors.toList());
261+
assertEquals(1, aggregateRoots.size());
262+
}
263+
241264
}

org.contextmapper.dsl/src/org/contextmapper/dsl/refactoring/MergeAggregatesRefactoring.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.contextmapper.dsl.contextMappingDSL.UpstreamDownstreamRelationship;
2929
import org.contextmapper.dsl.refactoring.exception.RefactoringInputException;
3030
import org.contextmapper.dsl.refactoring.henshin.Refactoring;
31+
import org.contextmapper.tactic.dsl.tacticdsl.DomainObject;
3132
import org.eclipse.xtext.EcoreUtil2;
3233

3334
import com.google.common.collect.Lists;
@@ -70,8 +71,13 @@ protected void doRefactor() {
7071
agg2 = agg1Opt.get();
7172
}
7273

74+
// precondition check, may throw exception
7375
checkForPossibleDomainObjectNameClashes(agg1, agg2);
7476

77+
// ensure there is only one aggregate root
78+
if (containsAggregateRoot(agg1))
79+
changeAggregateRootsToNormalObjects(agg2);
80+
7581
// move content from agg2 to agg1
7682
agg1.getConsumers().addAll(agg2.getConsumers());
7783
agg1.getDomainObjects().addAll(agg2.getDomainObjects());
@@ -105,6 +111,22 @@ private void checkForPossibleDomainObjectNameClashes(Aggregate aggregate1, Aggre
105111
+ String.join(", ", commonDomainObjectNames));
106112
}
107113

114+
/**
115+
* Sets aggregateRoot flag to false for all objects in given aggregate
116+
*/
117+
private void changeAggregateRootsToNormalObjects(Aggregate aggregate) {
118+
getAggregateRoots(aggregate).forEach(o -> o.setAggregateRoot(false));
119+
}
120+
121+
private boolean containsAggregateRoot(Aggregate aggregate) {
122+
return !getAggregateRoots(aggregate).isEmpty();
123+
}
124+
125+
private List<DomainObject> getAggregateRoots(Aggregate aggregate) {
126+
return aggregate.getDomainObjects().stream().filter(o -> o instanceof DomainObject).map(o -> (DomainObject) o).filter(o -> o.isAggregateRoot())
127+
.collect(Collectors.toList());
128+
}
129+
108130
private List<Aggregate> getAllAggregates() {
109131
return EcoreUtil2.<Aggregate>getAllContentsOfType(model, Aggregate.class);
110132
}

0 commit comments

Comments
 (0)