Skip to content

Commit 267ae1e

Browse files
authored
Merge pull request #85 from Systems-Modeling/feature/ST5AS-218
feat: dedicated endpoints for Commit#change ST5AS-218
2 parents 111e8c9 + 7e84b22 commit 267ae1e

15 files changed

Lines changed: 603 additions & 104 deletions

app/controllers/CommitController.java

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/*
22
* SysML v2 REST/HTTP Pilot Implementation
3-
* Copyright (C) 2020 InterCAX LLC
4-
* Copyright (C) 2020 California Institute of Technology ("Caltech")
3+
* Copyright (C) 2020 InterCAX LLC
4+
* Copyright (C) 2020 California Institute of Technology ("Caltech")
5+
* Copyright (C) 2022 Twingineer LLC
56
*
67
* This program is free software: you can redistribute it and/or modify
78
* it under the terms of the GNU Lesser General Public License as published by
@@ -23,11 +24,12 @@
2324

2425
import com.fasterxml.jackson.databind.JsonNode;
2526
import config.MetamodelProvider;
27+
import jackson.JacksonHelper;
2628
import jackson.jsonld.JsonLdAdorner;
2729
import jackson.jsonld.RecordAdorners.CommitAdorner;
2830
import jackson.jsonld.RecordAdorners.ProjectContainmentParameters;
2931
import org.omg.sysml.lifecycle.Commit;
30-
import org.omg.sysml.lifecycle.impl.CommitImpl;
32+
import org.omg.sysml.lifecycle.DataVersion;
3133
import play.Environment;
3234
import play.libs.Json;
3335
import play.mvc.Http.Request;
@@ -79,8 +81,7 @@ private Result postCommitByProject(UUID projectId, @SuppressWarnings("OptionalUs
7981
request,
8082
new ProjectContainmentParameters(projectId),
8183
ld,
82-
Json.mapper(),
83-
writer -> writer.withView(CommitImpl.Views.Compact.class)
84+
Json.mapper()
8485
);
8586
return buildResult(json, ld);
8687
}
@@ -101,8 +102,7 @@ public Result getCommitsByProject(UUID projectId, Request request) {
101102
request,
102103
new ProjectContainmentParameters(projectId),
103104
ld,
104-
Json.mapper(),
105-
writer -> writer.withView(CommitImpl.Views.Compact.class)
105+
Json.mapper()
106106
);
107107
Result result = buildResult(json, ld);
108108
return uuidResponse(
@@ -123,6 +123,49 @@ public Result getCommitByProjectAndId(UUID projectId, UUID commitId, Request req
123123
return buildResult(commit.orElse(null), request, new ProjectContainmentParameters(projectId));
124124
}
125125

126+
public Result getChangesByProjectAndCommit(UUID projectId, UUID commitId, Request request) {
127+
if (respondWithJsonLd(request)) {
128+
// TODO implement
129+
return Results.status(NOT_IMPLEMENTED);
130+
}
131+
PageRequest<UUID> pageRequest = uuidRequest(request);
132+
List<DataVersion> changes = commitService.getChangesByProjectIdAndCommitId(
133+
projectId,
134+
commitId,
135+
pageRequest.getAfter(),
136+
pageRequest.getBefore(),
137+
pageRequest.getSize()
138+
);
139+
boolean ld = respondWithJsonLd(request);
140+
JsonNode json = JacksonHelper.collectionToTree(
141+
changes,
142+
List.class,
143+
metamodelProvider.getImplementationClass(DataVersion.class),
144+
Json.mapper()
145+
);
146+
Result result = buildResult(json, ld);
147+
return uuidResponse(
148+
result,
149+
changes.size(),
150+
idx -> changes.get(idx).getId(),
151+
request,
152+
pageRequest
153+
);
154+
}
155+
156+
public Result getChangeByProjectCommitAndId(UUID projectId, UUID commitId, UUID changeId, Request request) {
157+
if (respondWithJsonLd(request)) {
158+
// TODO implement
159+
return Results.status(NOT_IMPLEMENTED);
160+
}
161+
Optional<DataVersion> change = commitService.getChangeByProjectIdCommitIdAndId(projectId, commitId, changeId);
162+
JsonNode json = JacksonHelper.objectToTree(
163+
change,
164+
Json.mapper()
165+
);
166+
return Results.ok(json);
167+
}
168+
126169
@Override
127170
protected JsonLdAdorner<Commit, ProjectContainmentParameters> getAdorner() {
128171
return adorner;

app/dao/CommitDao.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/*
22
* SysML v2 REST/HTTP Pilot Implementation
3-
* Copyright (C) 2020 InterCAX LLC
4-
* Copyright (C) 2020 California Institute of Technology ("Caltech")
3+
* Copyright (C) 2020 InterCAX LLC
4+
* Copyright (C) 2020 California Institute of Technology ("Caltech")
5+
* Copyright (C) 2022 Twingineer LLC
56
*
67
* This program is free software: you can redistribute it and/or modify
78
* it under the terms of the GNU Lesser General Public License as published by
@@ -23,6 +24,7 @@
2324

2425
import org.omg.sysml.lifecycle.Branch;
2526
import org.omg.sysml.lifecycle.Commit;
27+
import org.omg.sysml.lifecycle.DataVersion;
2628
import org.omg.sysml.lifecycle.Project;
2729

2830
import java.util.List;
@@ -49,5 +51,7 @@ default Optional<Commit> update(Commit commit) {
4951

5052
Optional<Commit> findByProjectAndId(Project project, UUID id);
5153

52-
Optional<Commit> findByProjectAndIdResolved(Project project, UUID id);
54+
List<DataVersion> findChangesByCommit(Commit commit, UUID after, UUID before, int maxResults);
55+
56+
Optional<DataVersion> findChangeByCommitAndId(Commit commit, UUID id);
5357
}

app/dao/impl/FlatSchemaDao.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@
2121
package dao.impl;
2222

2323
import com.fasterxml.jackson.databind.JsonNode;
24-
import com.fasterxml.jackson.databind.ObjectMapper;
2524
import com.google.common.collect.Streams;
2625
import config.MetamodelProvider;
2726
import dao.SchemaDao;
28-
import jackson.databind.ObjectMapperFactory;
2927
import org.omg.sysml.data.ExternalData;
3028
import org.omg.sysml.data.ExternalRelationship;
3129
import org.omg.sysml.data.ProjectUsage;
30+
import play.libs.Json;
3231

3332
import javax.annotation.Nullable;
3433
import javax.inject.Inject;
@@ -44,11 +43,9 @@
4443
public class FlatSchemaDao implements SchemaDao {
4544

4645
private final TreeMap<String, JsonNode> map;
47-
private final ObjectMapper mapper;
4846

4947
@Inject
50-
public FlatSchemaDao(MetamodelProvider metamodelProvider, ObjectMapperFactory mapperFactory) {
51-
this.mapper = mapperFactory.getObjectMapper();
48+
public FlatSchemaDao(MetamodelProvider metamodelProvider) {
5249
try (Stream<Class<?>> interfaces = metamodelProvider.getAllInterfaces().stream()) {
5350
map = Streams.concat(
5451
interfaces
@@ -61,7 +58,7 @@ public FlatSchemaDao(MetamodelProvider metamodelProvider, ObjectMapperFactory ma
6158
)
6259
.map(input -> {
6360
try {
64-
return mapper.reader().readTree(input);
61+
return Json.mapper().reader().readTree(input);
6562
} catch (IOException e) {
6663
throw new UncheckedIOException(e);
6764
}

app/dao/impl/jpa/JpaCommitDao.java

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* SysML v2 REST/HTTP Pilot Implementation
33
* Copyright (C) 2020 InterCAX LLC
44
* Copyright (C) 2020 California Institute of Technology ("Caltech")
5-
* Copyright (C) 2021 Twingineer LLC
5+
* Copyright (C) 2021-2022 Twingineer LLC
66
*
77
* This program is free software: you can redistribute it and/or modify
88
* it under the terms of the GNU Lesser General Public License as published by
@@ -27,22 +27,15 @@
2727
import javabean.JavaBeanHelper;
2828
import jpa.manager.JPAManager;
2929
import org.omg.sysml.lifecycle.*;
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;
30+
import org.omg.sysml.lifecycle.impl.*;
3431
import org.omg.sysml.metamodel.Element;
35-
import org.omg.sysml.metamodel.impl.ElementImpl_;
3632

3733
import javax.inject.Inject;
3834
import javax.inject.Singleton;
3935
import javax.persistence.EntityManager;
4036
import javax.persistence.NoResultException;
4137
import javax.persistence.TypedQuery;
42-
import javax.persistence.criteria.CriteriaBuilder;
43-
import javax.persistence.criteria.CriteriaQuery;
44-
import javax.persistence.criteria.Expression;
45-
import javax.persistence.criteria.Root;
38+
import javax.persistence.criteria.*;
4639
import java.lang.reflect.Method;
4740
import java.util.*;
4841
import java.util.function.BiFunction;
@@ -334,9 +327,43 @@ protected Optional<Commit> findByProjectAndId(Project project, UUID id, EntityMa
334327
}
335328

336329
@Override
337-
public Optional<Commit> findByProjectAndIdResolved(Project project, UUID id) {
330+
public List<DataVersion> findChangesByCommit(Commit commit, UUID after, UUID before, int maxResults) {
338331
return jpaManager.transact(em -> {
339-
return findByProjectAndId(project, id, em).map(JpaCommitDao::resolve);
332+
CriteriaBuilder builder = em.getCriteriaBuilder();
333+
CriteriaQuery<DataVersionImpl> query = builder.createQuery(DataVersionImpl.class);
334+
Root<CommitImpl> commitRoot = query.from(CommitImpl.class);
335+
SetJoin<CommitImpl, DataVersionImpl> dataVersionJoin = commitRoot.join(CommitImpl_.change);
336+
Path<UUID> idPath = dataVersionJoin.get(DataVersionImpl_.id);
337+
Expression<Boolean> where = builder.equal(commitRoot.get(CommitImpl_.id), commit.getId());
338+
query.select(dataVersionJoin);
339+
Paginated<TypedQuery<DataVersionImpl>> paginated = paginateQuery(after, before, maxResults, query, builder, em, idPath, where);
340+
List<DataVersion> result = paginated.get()
341+
.getResultStream()
342+
.collect(Collectors.toList());
343+
if (paginated.isReversed()) {
344+
Collections.reverse(result);
345+
}
346+
return result;
347+
});
348+
}
349+
350+
@Override
351+
public Optional<DataVersion> findChangeByCommitAndId(Commit commit, UUID id) {
352+
return jpaManager.transact(em -> {
353+
CriteriaBuilder builder = em.getCriteriaBuilder();
354+
CriteriaQuery<DataVersionImpl> query = builder.createQuery(DataVersionImpl.class);
355+
Root<CommitImpl> commitRoot = query.from(CommitImpl.class);
356+
SetJoin<CommitImpl, DataVersionImpl> dataVersionJoin = commitRoot.join(CommitImpl_.change);
357+
Expression<Boolean> where = builder.and(
358+
builder.equal(commitRoot.get(CommitImpl_.id), commit.getId()),
359+
builder.equal(dataVersionJoin.get(DataVersionImpl_.id), id)
360+
);
361+
query.select(dataVersionJoin).where(where);
362+
try {
363+
return Optional.of(em.createQuery(query).getSingleResult());
364+
} catch (NoResultException e) {
365+
return Optional.empty();
366+
}
340367
});
341368
}
342369
}

app/dao/impl/jpa/JpaDao.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* SysML v2 REST/HTTP Pilot Implementation
33
* Copyright (C) 2020 InterCAX LLC
44
* Copyright (C) 2020 California Institute of Technology ("Caltech")
5-
* Copyright (C) 2021 Twingineer LLC
5+
* Copyright (C) 2021-2022 Twingineer LLC
66
*
77
* This program is free software: you can redistribute it and/or modify
88
* it under the terms of the GNU Lesser General Public License as published by
@@ -24,7 +24,6 @@
2424

2525
import dao.Dao;
2626
import jpa.manager.JPAManager;
27-
import org.omg.sysml.lifecycle.Project;
2827

2928
import javax.annotation.Nullable;
3029
import javax.persistence.EntityManager;
@@ -111,11 +110,11 @@ public boolean isReversed() {
111110
}
112111
}
113112

114-
protected <X> Paginated<TypedQuery<X>> paginateQuery(@Nullable UUID after, @Nullable UUID before, int maxResults, CriteriaQuery<X> query, CriteriaBuilder builder, EntityManager em, Path<UUID> idPath) {
113+
protected static <X> Paginated<TypedQuery<X>> paginateQuery(@Nullable UUID after, @Nullable UUID before, int maxResults, CriteriaQuery<X> query, CriteriaBuilder builder, EntityManager em, Path<UUID> idPath) {
115114
return paginateQuery(after, before, maxResults, query, builder, em, idPath, null);
116115
}
117116

118-
protected <X> Paginated<TypedQuery<X>> paginateQuery(@Nullable UUID after, @Nullable UUID before, int maxResults, CriteriaQuery<X> query, CriteriaBuilder builder, EntityManager em, Path<UUID> idPath, @Nullable Expression<Boolean> where) {
117+
protected static <X> Paginated<TypedQuery<X>> paginateQuery(@Nullable UUID after, @Nullable UUID before, int maxResults, CriteriaQuery<X> query, CriteriaBuilder builder, EntityManager em, Path<UUID> idPath, @Nullable Expression<Boolean> where) {
119118
if (after != null) {
120119
Expression<Boolean> expr = builder.greaterThan(idPath, after);
121120
where = where != null ? builder.and(where, expr) : expr;
@@ -137,7 +136,7 @@ protected <X> Paginated<TypedQuery<X>> paginateQuery(@Nullable UUID after, @Null
137136
return new Paginated<>(typedQuery, reversed);
138137
}
139138

140-
protected <X> Paginated<Stream<X>> paginateStream(@Nullable UUID after, @Nullable UUID before, int maxResults, Stream<X> stream, Function<X, UUID> idFunction) {
139+
protected static <X> Paginated<Stream<X>> paginateStream(@Nullable UUID after, @Nullable UUID before, int maxResults, Stream<X> stream, Function<X, UUID> idFunction) {
141140
if (after != null) {
142141
stream = stream.filter(x -> idFunction.apply(x).compareTo(after) > 0);
143142
}

app/dao/impl/jpa/JpaDataDao.java

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* SysML v2 REST/HTTP Pilot Implementation
3-
* Copyright (C) 2021 Twingineer LLC
3+
* Copyright (C) 2021-2022 Twingineer LLC
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Lesser General Public License as published by
@@ -33,20 +33,20 @@
3333
import org.omg.sysml.internal.impl.CommitDataVersionIndexImpl;
3434
import org.omg.sysml.internal.impl.CommitDataVersionIndexImpl_;
3535
import org.omg.sysml.internal.impl.WorkingDataVersionImpl;
36+
import org.omg.sysml.internal.impl.WorkingDataVersionImpl_;
3637
import org.omg.sysml.lifecycle.Commit;
3738
import org.omg.sysml.lifecycle.Data;
3839
import org.omg.sysml.lifecycle.DataVersion;
39-
import org.omg.sysml.lifecycle.impl.CommitImpl;
40+
import org.omg.sysml.lifecycle.impl.*;
4041
import org.omg.sysml.query.*;
4142
import org.omg.sysml.query.impl.QueryImpl;
4243

4344
import javax.inject.Inject;
4445
import javax.persistence.EntityManager;
4546
import javax.persistence.EntityTransaction;
4647
import javax.persistence.NoResultException;
47-
import javax.persistence.criteria.CriteriaBuilder;
48-
import javax.persistence.criteria.CriteriaQuery;
49-
import javax.persistence.criteria.Root;
48+
import javax.persistence.TypedQuery;
49+
import javax.persistence.criteria.*;
5050
import java.beans.PropertyDescriptor;
5151
import java.util.*;
5252
import java.util.concurrent.ConcurrentHashMap;
@@ -55,6 +55,8 @@
5555
import java.util.stream.Collectors;
5656
import java.util.stream.Stream;
5757

58+
import static dao.impl.jpa.JpaDao.paginateQuery;
59+
5860
public class JpaDataDao implements DataDao {
5961

6062
// TODO Explore alternative to serializing lazy entity attributes that doesn't involve resolving all proxies one level.
@@ -104,6 +106,31 @@ public List<Data> findByCommitAndQuery(Commit commit, Query query) {
104106
});
105107
}
106108

109+
List<DataVersion> findChangesByCommit(Commit commit, UUID after, UUID before, int maxResults, boolean excludeUsed, EntityManager em) {
110+
CommitDataVersionIndex commitIndex = getCommitIndex(commit, em);
111+
112+
CriteriaBuilder builder = em.getCriteriaBuilder();
113+
CriteriaQuery<DataVersionImpl> query = builder.createQuery(DataVersionImpl.class);
114+
Root<CommitDataVersionIndexImpl> commitIndexRoot = query.from(CommitDataVersionIndexImpl.class);
115+
SetJoin<CommitDataVersionIndexImpl, WorkingDataVersionImpl> workingDataVersionJoin = commitIndexRoot.join(CommitDataVersionIndexImpl_.workingDataVersion);
116+
Join<WorkingDataVersionImpl, DataVersionImpl> dataVersionJoin = workingDataVersionJoin.join(WorkingDataVersionImpl_.dataVersion);
117+
Join<DataVersionImpl, DataIdentityImpl> dataIdentityJoin = dataVersionJoin.join(DataVersionImpl_.identity);
118+
Path<UUID> idPath = dataIdentityJoin.get(DataIdentityImpl_.id);
119+
Expression<Boolean> where = builder.equal(commitIndexRoot.get(CommitDataVersionIndexImpl_.id), commitIndex.getId());
120+
if (excludeUsed) {
121+
where = builder.and(where, builder.isNull(workingDataVersionJoin.get(WorkingDataVersionImpl_.source)));
122+
}
123+
query.select(dataVersionJoin);
124+
JpaDao.Paginated<TypedQuery<DataVersionImpl>> paginated = paginateQuery(after, before, maxResults, query, builder, em, idPath, where);
125+
List<DataVersion> result = paginated.get()
126+
.getResultStream()
127+
.collect(Collectors.toList());
128+
if (paginated.isReversed()) {
129+
Collections.reverse(result);
130+
}
131+
return result;
132+
}
133+
107134
protected CommitDataVersionIndex getCommitIndex(Commit commit, EntityManager em) {
108135
CriteriaBuilder builder = em.getCriteriaBuilder();
109136
CriteriaQuery<CommitDataVersionIndexImpl> query = builder.createQuery(CommitDataVersionIndexImpl.class);

app/dao/impl/jpa/JpaElementDao.java

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* SysML v2 REST/HTTP Pilot Implementation
33
* Copyright (C) 2020 InterCAX LLC
44
* Copyright (C) 2020 California Institute of Technology ("Caltech")
5-
* Copyright (C) 2021 Twingineer LLC
5+
* Copyright (C) 2021-2022 Twingineer LLC
66
*
77
* This program is free software: you can redistribute it and/or modify
88
* it under the terms of the GNU Lesser General Public License as published by
@@ -133,32 +133,13 @@ public List<Element> findAllByCommit(Commit commit, boolean excludeUsed, @Nullab
133133
return jpaManager.transact(em -> {
134134
// TODO Commit is detached at this point. This ternary mitigates by requerying for the Commit in this transaction. A better solution would be moving transaction handling up to service layer (supported by general wisdom) and optionally migrating to using Play's @Transactional/JPAApi. Pros would include removal of repetitive transaction handling at the DAO layer and ability to interface with multiple DAOs in the same transaction (consistent view). Cons include increased temptation to keep transaction open for longer than needed, e.g. during JSON serialization due to the convenience of @Transactional (deprecated in >= 2.8.x), and the service, a higher level of abstraction, becoming aware of transactions. An alternative would be DAO-to-DAO calls (generally discouraged) and delegating to non-transactional versions of methods.
135135
Commit c = em.contains(commit) ? commit : em.find(CommitImpl.class, commit.getId());
136-
CommitDataVersionIndex commitIndex = dataDao.getCommitIndex(c, em);
137-
138-
CriteriaBuilder builder = em.getCriteriaBuilder();
139-
CriteriaQuery<DataVersionImpl> query = builder.createQuery(DataVersionImpl.class);
140-
Root<CommitDataVersionIndexImpl> commitIndexRoot = query.from(CommitDataVersionIndexImpl.class);
141-
SetJoin<CommitDataVersionIndexImpl, WorkingDataVersionImpl> workingDataVersionJoin = commitIndexRoot.join(CommitDataVersionIndexImpl_.workingDataVersion);
142-
Join<WorkingDataVersionImpl, DataVersionImpl> dataVersionJoin = workingDataVersionJoin.join(WorkingDataVersionImpl_.dataVersion);
143-
Join<DataVersionImpl, DataIdentityImpl> dataIdentityJoin = dataVersionJoin.join(DataVersionImpl_.identity);
144-
Path<UUID> idPath = dataIdentityJoin.get(DataIdentityImpl_.id);
145-
Expression<Boolean> where = builder.equal(commitIndexRoot.get(CommitDataVersionIndexImpl_.id), commitIndex.getId());
146-
if (excludeUsed) {
147-
where = builder.and(where, builder.isNull(workingDataVersionJoin.get(WorkingDataVersionImpl_.source)));
148-
}
149-
query.select(dataVersionJoin);
150-
Paginated<TypedQuery<DataVersionImpl>> paginated = paginateQuery(after, before, maxResults, query, builder, em, idPath, where);
151-
List<Element> result = paginated.get()
152-
.getResultStream()
136+
return dataDao.findChangesByCommit(c, after, before, maxResults, excludeUsed, em)
137+
.stream()
153138
.map(DataVersion::getPayload)
154139
.filter(data -> data instanceof Element)
155140
.map(data -> (Element) data)
156141
.map(element -> JpaDataDao.resolve(element, Element.class))
157142
.collect(Collectors.toList());
158-
if (paginated.isReversed()) {
159-
Collections.reverse(result);
160-
}
161-
return result;
162143
});
163144
}
164145

0 commit comments

Comments
 (0)