Skip to content

Commit 20912e3

Browse files
committed
Merge branch 'release/2022-02-m1'
2 parents bc75237 + 3c68477 commit 20912e3

47 files changed

Lines changed: 2906 additions & 653 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/controllers/CommitController.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,21 @@ public CommitController(CommitService commitService, MetamodelProvider metamodel
5555
}
5656

5757
public Result postCommitByProject(UUID projectId, @SuppressWarnings("OptionalUsedAsFieldOrParameterType") Optional<UUID> branchId, Request request) {
58+
return postCommitByProject(projectId, branchId, request, commitService::create);
59+
}
60+
61+
public Result postCommitByProjectNameResolved(UUID projectId, @SuppressWarnings("OptionalUsedAsFieldOrParameterType") Optional<UUID> branchId, Request request) {
62+
return postCommitByProject(projectId, branchId, request, commitService::createNameResolved);
63+
}
64+
65+
private Result postCommitByProject(UUID projectId, @SuppressWarnings("OptionalUsedAsFieldOrParameterType") Optional<UUID> branchId, Request request, CommitCreator creator) {
5866
JsonNode requestBodyJson = request.body().asJson();
5967
Commit requestedObject = Json.fromJson(requestBodyJson, metamodelProvider.getImplementationClass(Commit.class));
6068
if (requestedObject.getId() != null || requestedObject.getTimestamp() != null) {
6169
return Results.badRequest();
6270
}
6371
requestedObject.setTimestamp(ZonedDateTime.now());
64-
Optional<Commit> commit = commitService.create(projectId, branchId.orElse(null), requestedObject);
72+
Optional<Commit> commit = creator.create(projectId, branchId.orElse(null), requestedObject);
6573
if (commit.isEmpty()) {
6674
return Results.internalServerError();
6775
}
@@ -119,4 +127,9 @@ public Result getCommitByProjectAndId(UUID projectId, UUID commitId, Request req
119127
protected JsonLdAdorner<Commit, ProjectContainmentParameters> getAdorner() {
120128
return adorner;
121129
}
130+
131+
@FunctionalInterface
132+
private interface CommitCreator {
133+
Optional<Commit> create(UUID projectId, UUID branchId, Commit commit);
134+
}
122135
}

app/controllers/ElementController.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public Result getElementsByProjectIdCommitId(UUID projectId, UUID commitId, Requ
5656
}
5757

5858
public Result getElementByProjectIdCommitIdElementId(UUID projectId, UUID commitId, UUID elementId, Request request) {
59-
Optional<Element> element = elementService.getElementsByProjectIdCommitIdElementId(projectId, commitId, elementId);
59+
Optional<Element> element = elementService.getElementByProjectIdCommitIdElementId(projectId, commitId, elementId);
6060
return buildResult(element.orElse(null), request, new DataJsonLdAdorner.Parameters(projectId, commitId));
6161
}
6262

@@ -66,6 +66,11 @@ public Result getRootsByProjectIdCommitId(UUID projectId, UUID commitId, Request
6666
return buildPaginatedResult(roots, projectId, commitId, request, pageRequest);
6767
}
6868

69+
public Result getElementByProjectIdCommitIdQualifiedName(UUID projectId, UUID commitId, String qualifiedName, Request request) {
70+
Optional<Element> element = elementService.getElementByProjectIdCommitIdQualifiedName(projectId, commitId, qualifiedName);
71+
return buildResult(element.orElse(null), request, new DataJsonLdAdorner.Parameters(projectId, commitId));
72+
}
73+
6974
private Result buildPaginatedResult(List<Element> elements, UUID projectId, UUID commitId, Request request, PageRequest pageRequest) {
7075
return paginateResult(
7176
buildResult(elements, List.class, metamodelProvider.getImplementationClass(Element.class), request, new DataJsonLdAdorner.Parameters(projectId, commitId)),

app/dao/CommitDao.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ default Optional<Commit> persist(Commit commit) {
3838

3939
Optional<Commit> persist(Commit commit, Branch branch);
4040

41+
Optional<Commit> persistNameResolved(Commit commit, Branch branch);
42+
4143
@Override
4244
default Optional<Commit> update(Commit commit) {
4345
throw new UnsupportedOperationException();

app/dao/DataDao.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
import java.util.List;
2828

29-
public interface DataDao extends Dao<Data> {
29+
public interface DataDao {
3030

3131
List<Data> findByCommitAndQuery(Commit commit, Query query);
3232
}

app/dao/ElementDao.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,6 @@ public interface ElementDao extends Dao<Element> {
3737
Optional<Element> findByCommitAndId(Commit commit, UUID id);
3838

3939
List<Element> findRootsByCommit(Commit commit, @Nullable UUID after, @Nullable UUID before, int maxResults);
40+
41+
Optional<Element> findByCommitAndQualifiedName(Commit commit, String qualifiedName);
4042
}

app/dao/impl/jpa/JpaCommitDao.java

Lines changed: 97 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@
2727
import javabean.JavaBeanHelper;
2828
import jpa.manager.JPAManager;
2929
import org.omg.sysml.lifecycle.*;
30-
import org.omg.sysml.lifecycle.impl.*;
30+
import org.omg.sysml.lifecycle.impl.CommitImpl;
31+
import org.omg.sysml.lifecycle.impl.CommitImpl_;
32+
import org.omg.sysml.lifecycle.impl.DataIdentityImpl;
33+
import org.omg.sysml.lifecycle.impl.DataImpl;
3134
import org.omg.sysml.metamodel.Element;
35+
import org.omg.sysml.metamodel.impl.ElementImpl_;
3236

3337
import javax.inject.Inject;
3438
import javax.inject.Singleton;
@@ -41,28 +45,17 @@
4145
import javax.persistence.criteria.Root;
4246
import java.lang.reflect.Method;
4347
import java.util.*;
48+
import java.util.function.BiFunction;
49+
import java.util.function.Consumer;
4450
import java.util.function.Function;
45-
import java.util.function.Supplier;
46-
import java.util.function.UnaryOperator;
4751
import java.util.stream.Collectors;
48-
import java.util.stream.Stream;
52+
53+
import static jackson.RecordSerialization.IDENTITY_FIELD;
54+
import static org.omg.sysml.metamodel.impl.ElementImpl_.QUALIFIED_NAME;
4955

5056
@Singleton
5157
public class JpaCommitDao extends SimpleJpaDao<Commit, CommitImpl> implements CommitDao {
5258

53-
// TODO Explore alternative to serializing lazy entity attributes that doesn't involve resolving all proxies one level.
54-
static UnaryOperator<Commit> PROXY_RESOLVER = commit -> {
55-
commit.getChange().stream()
56-
.filter(Objects::nonNull)
57-
.map(DataVersion::getPayload)
58-
.filter(data -> data instanceof Element)
59-
.map(data -> (Element) data)
60-
.map(JpaElementDao.PROXY_RESOLVER)
61-
.forEach(e -> {
62-
});
63-
return commit;
64-
};
65-
6659
private final ElementDao elementDao;
6760
private final JpaBranchDao branchDao;
6861

@@ -73,8 +66,82 @@ public JpaCommitDao(JPAManager jpaManager, ElementDao elementDao, JpaBranchDao b
7366
this.branchDao = branchDao;
7467
}
7568

69+
// TODO Explore alternative to serializing lazy entity attributes that doesn't involve resolving all proxies one level.
70+
protected static Commit resolve(Commit commit) {
71+
commit.getChange().stream()
72+
.filter(Objects::nonNull)
73+
.map(DataVersion::getPayload)
74+
.map(data -> JpaDataDao.resolve(data, Data.class))
75+
.forEach(e -> {
76+
});
77+
return commit;
78+
}
79+
7680
@Override
7781
public Optional<Commit> persist(Commit commit, Branch branch) {
82+
return persist(commit, branch,
83+
fnData -> {
84+
if (fnData.getId() == null) {
85+
throw new IllegalArgumentException(String.format("Element must be referenced by %s", IDENTITY_FIELD));
86+
}
87+
},
88+
(fnData, fnCache) -> Optional.ofNullable(fnCache.get(fnData.getId())),
89+
(fnData, fnCommit) -> {
90+
UUID id = fnData.getId();
91+
// TODO change to dataDao
92+
return elementDao.findByCommitAndId(fnCommit, id)
93+
.orElseThrow(() -> new NoSuchElementException(
94+
String.format("Element with %s %s not found", IDENTITY_FIELD, id)
95+
));
96+
}
97+
);
98+
}
99+
100+
@Override
101+
public Optional<Commit> persistNameResolved(Commit commit, Branch branch) {
102+
return persist(commit, branch,
103+
fnData -> {
104+
if (fnData.getId() == null && (!(fnData instanceof Element) || ((Element) fnData).getQualifiedName() == null)) {
105+
throw new IllegalArgumentException(String.format("Element must be referenced by %s or %s", IDENTITY_FIELD, QUALIFIED_NAME));
106+
}
107+
},
108+
(fnData, fnCache) -> {
109+
if (fnData.getId() != null) {
110+
return Optional.ofNullable(fnCache.get(fnData.getId()));
111+
}
112+
else {
113+
return fnCache.values().stream()
114+
.filter(cached -> cached instanceof Element)
115+
.map(cached -> (Element) cached)
116+
.filter(cached -> ((Element) fnData).getQualifiedName().equals(cached.getQualifiedName()))
117+
.map(cached -> (Data) cached)
118+
.findFirst();
119+
}
120+
},
121+
(fnData, fnCommit) -> {
122+
if (fnData.getId() != null) {
123+
UUID id = fnData.getId();
124+
// TODO change to dataDao
125+
return elementDao.findByCommitAndId(fnCommit, id)
126+
.orElseThrow(() -> new NoSuchElementException(
127+
String.format("Element with %s %s not found", IDENTITY_FIELD, id)
128+
));
129+
}
130+
else {
131+
String qualifiedName = ((Element) fnData).getQualifiedName();
132+
return elementDao.findByCommitAndQualifiedName(fnCommit, qualifiedName)
133+
.orElseThrow(() -> new NoSuchElementException(
134+
String.format("Element with %s %s not found", QUALIFIED_NAME, qualifiedName)
135+
));
136+
}
137+
});
138+
}
139+
140+
private Optional<Commit> persist(
141+
Commit commit, Branch branch,
142+
Consumer<Data> validator,
143+
BiFunction<Data, Map<UUID, Data>, Optional<Data>> cacheResolver,
144+
BiFunction<Data, Commit, Data> commitResolver) {
78145
commit.setPreviousCommit(null);
79146
if (branch.getHead() != null) {
80147
commit.setPreviousCommit(branch.getHead());
@@ -94,20 +161,16 @@ public void setId(UUID id) {
94161
}
95162
};
96163

97-
Supplier<Stream<DataVersionImpl>> changeStream = () -> commit.getChange().stream()
98-
.filter(change -> change instanceof DataVersionImpl)
99-
.map(change -> (DataVersionImpl) change);
100-
101164
// Give all Commit#changes an identity, if they don't already have one, and all Commit#changes#identity an id, if they don't already have one.
102-
changeStream.get()
165+
commit.getChange().stream()
103166
.peek(change -> change.setIdentity(change.getIdentity() != null ? change.getIdentity() : new DataIdentityImpl()))
104167
.map(DataVersion::getIdentity)
105168
.filter(identity -> identity instanceof DataIdentityImpl)
106169
.map(identity -> (DataIdentityImpl) identity)
107170
.forEach(identity -> identity.setId(identity.getId() != null ? identity.getId() : UUID.randomUUID()));
108171

109172
// Copy all Commit#change#identity#id to Commit#change#payload#id and assign Commit#change#payload#key to a random UUID
110-
Map<UUID, Data> identifierToDataMap = changeStream.get()
173+
Map<UUID, Data> identifierToDataMap = commit.getChange().stream()
111174
.peek(change -> {
112175
Data payload = change.getPayload();
113176
if (payload == null) {
@@ -125,20 +188,16 @@ public void setId(UUID id) {
125188
);
126189

127190
Function<Data, Data> reattachDataFunction = data -> {
128-
Data reattachedData = identifierToDataMap.computeIfAbsent(data.getId(), identifier -> {
129-
if (commit.getPreviousCommit() == null) {
130-
return tombstone;
131-
}
132-
return elementDao.findByCommitAndId(commit.getPreviousCommit(), identifier)
133-
.map(element -> (Data) element)
134-
.orElse(tombstone);
135-
});
136-
if (Objects.equals(reattachedData, tombstone)) {
137-
throw new IllegalArgumentException("Element with ID " + data.getId() + " not found");
138-
}
139-
return reattachedData;
191+
validator.accept(data);
192+
return cacheResolver.apply(data, identifierToDataMap)
193+
.map(fnData -> fnData != tombstone ? fnData : null)
194+
.orElseGet(() -> {
195+
Data resolved = commitResolver.apply(data, commit.getPreviousCommit());
196+
identifierToDataMap.put(resolved.getId(), resolved);
197+
return resolved;
198+
});
140199
};
141-
changeStream.get()
200+
commit.getChange().stream()
142201
.map(DataVersion::getPayload)
143202
.filter(Objects::nonNull)
144203
.forEach(data -> JavaBeanHelper.getBeanProperties(data).values().stream()
@@ -222,7 +281,7 @@ else if (Collection.class.isAssignableFrom(type)) {
222281
branch.setHead(c);
223282
branchDao.update(branch, em);
224283
});
225-
return persistedCommit.map(PROXY_RESOLVER);
284+
return persistedCommit.map(JpaCommitDao::resolve);
226285
});
227286
}
228287

@@ -273,7 +332,7 @@ protected Optional<Commit> findByProjectAndId(Project project, UUID id, EntityMa
273332
@Override
274333
public Optional<Commit> findByProjectAndIdResolved(Project project, UUID id) {
275334
return jpaManager.transact(em -> {
276-
return findByProjectAndId(project, id, em).map(PROXY_RESOLVER);
335+
return findByProjectAndId(project, id, em).map(JpaCommitDao::resolve);
277336
});
278337
}
279338
}

0 commit comments

Comments
 (0)