Skip to content

Commit

Permalink
Merge branch 'release/2022-02-m1'
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-gomes committed Feb 28, 2022
2 parents bc75237 + 3c68477 commit 20912e3
Show file tree
Hide file tree
Showing 47 changed files with 2,906 additions and 653 deletions.
15 changes: 14 additions & 1 deletion app/controllers/CommitController.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,21 @@ public CommitController(CommitService commitService, MetamodelProvider metamodel
}

public Result postCommitByProject(UUID projectId, @SuppressWarnings("OptionalUsedAsFieldOrParameterType") Optional<UUID> branchId, Request request) {
return postCommitByProject(projectId, branchId, request, commitService::create);
}

public Result postCommitByProjectNameResolved(UUID projectId, @SuppressWarnings("OptionalUsedAsFieldOrParameterType") Optional<UUID> branchId, Request request) {
return postCommitByProject(projectId, branchId, request, commitService::createNameResolved);
}

private Result postCommitByProject(UUID projectId, @SuppressWarnings("OptionalUsedAsFieldOrParameterType") Optional<UUID> branchId, Request request, CommitCreator creator) {
JsonNode requestBodyJson = request.body().asJson();
Commit requestedObject = Json.fromJson(requestBodyJson, metamodelProvider.getImplementationClass(Commit.class));
if (requestedObject.getId() != null || requestedObject.getTimestamp() != null) {
return Results.badRequest();
}
requestedObject.setTimestamp(ZonedDateTime.now());
Optional<Commit> commit = commitService.create(projectId, branchId.orElse(null), requestedObject);
Optional<Commit> commit = creator.create(projectId, branchId.orElse(null), requestedObject);
if (commit.isEmpty()) {
return Results.internalServerError();
}
Expand Down Expand Up @@ -119,4 +127,9 @@ public Result getCommitByProjectAndId(UUID projectId, UUID commitId, Request req
protected JsonLdAdorner<Commit, ProjectContainmentParameters> getAdorner() {
return adorner;
}

@FunctionalInterface
private interface CommitCreator {
Optional<Commit> create(UUID projectId, UUID branchId, Commit commit);
}
}
7 changes: 6 additions & 1 deletion app/controllers/ElementController.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public Result getElementsByProjectIdCommitId(UUID projectId, UUID commitId, Requ
}

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

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

public Result getElementByProjectIdCommitIdQualifiedName(UUID projectId, UUID commitId, String qualifiedName, Request request) {
Optional<Element> element = elementService.getElementByProjectIdCommitIdQualifiedName(projectId, commitId, qualifiedName);
return buildResult(element.orElse(null), request, new DataJsonLdAdorner.Parameters(projectId, commitId));
}

private Result buildPaginatedResult(List<Element> elements, UUID projectId, UUID commitId, Request request, PageRequest pageRequest) {
return paginateResult(
buildResult(elements, List.class, metamodelProvider.getImplementationClass(Element.class), request, new DataJsonLdAdorner.Parameters(projectId, commitId)),
Expand Down
2 changes: 2 additions & 0 deletions app/dao/CommitDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ default Optional<Commit> persist(Commit commit) {

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

Optional<Commit> persistNameResolved(Commit commit, Branch branch);

@Override
default Optional<Commit> update(Commit commit) {
throw new UnsupportedOperationException();
Expand Down
2 changes: 1 addition & 1 deletion app/dao/DataDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

import java.util.List;

public interface DataDao extends Dao<Data> {
public interface DataDao {

List<Data> findByCommitAndQuery(Commit commit, Query query);
}
2 changes: 2 additions & 0 deletions app/dao/ElementDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ public interface ElementDao extends Dao<Element> {
Optional<Element> findByCommitAndId(Commit commit, UUID id);

List<Element> findRootsByCommit(Commit commit, @Nullable UUID after, @Nullable UUID before, int maxResults);

Optional<Element> findByCommitAndQualifiedName(Commit commit, String qualifiedName);
}
135 changes: 97 additions & 38 deletions app/dao/impl/jpa/JpaCommitDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@
import javabean.JavaBeanHelper;
import jpa.manager.JPAManager;
import org.omg.sysml.lifecycle.*;
import org.omg.sysml.lifecycle.impl.*;
import org.omg.sysml.lifecycle.impl.CommitImpl;
import org.omg.sysml.lifecycle.impl.CommitImpl_;
import org.omg.sysml.lifecycle.impl.DataIdentityImpl;
import org.omg.sysml.lifecycle.impl.DataImpl;
import org.omg.sysml.metamodel.Element;
import org.omg.sysml.metamodel.impl.ElementImpl_;

import javax.inject.Inject;
import javax.inject.Singleton;
Expand All @@ -41,28 +45,17 @@
import javax.persistence.criteria.Root;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static jackson.RecordSerialization.IDENTITY_FIELD;
import static org.omg.sysml.metamodel.impl.ElementImpl_.QUALIFIED_NAME;

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

// TODO Explore alternative to serializing lazy entity attributes that doesn't involve resolving all proxies one level.
static UnaryOperator<Commit> PROXY_RESOLVER = commit -> {
commit.getChange().stream()
.filter(Objects::nonNull)
.map(DataVersion::getPayload)
.filter(data -> data instanceof Element)
.map(data -> (Element) data)
.map(JpaElementDao.PROXY_RESOLVER)
.forEach(e -> {
});
return commit;
};

private final ElementDao elementDao;
private final JpaBranchDao branchDao;

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

// TODO Explore alternative to serializing lazy entity attributes that doesn't involve resolving all proxies one level.
protected static Commit resolve(Commit commit) {
commit.getChange().stream()
.filter(Objects::nonNull)
.map(DataVersion::getPayload)
.map(data -> JpaDataDao.resolve(data, Data.class))
.forEach(e -> {
});
return commit;
}

@Override
public Optional<Commit> persist(Commit commit, Branch branch) {
return persist(commit, branch,
fnData -> {
if (fnData.getId() == null) {
throw new IllegalArgumentException(String.format("Element must be referenced by %s", IDENTITY_FIELD));
}
},
(fnData, fnCache) -> Optional.ofNullable(fnCache.get(fnData.getId())),
(fnData, fnCommit) -> {
UUID id = fnData.getId();
// TODO change to dataDao
return elementDao.findByCommitAndId(fnCommit, id)
.orElseThrow(() -> new NoSuchElementException(
String.format("Element with %s %s not found", IDENTITY_FIELD, id)
));
}
);
}

@Override
public Optional<Commit> persistNameResolved(Commit commit, Branch branch) {
return persist(commit, branch,
fnData -> {
if (fnData.getId() == null && (!(fnData instanceof Element) || ((Element) fnData).getQualifiedName() == null)) {
throw new IllegalArgumentException(String.format("Element must be referenced by %s or %s", IDENTITY_FIELD, QUALIFIED_NAME));
}
},
(fnData, fnCache) -> {
if (fnData.getId() != null) {
return Optional.ofNullable(fnCache.get(fnData.getId()));
}
else {
return fnCache.values().stream()
.filter(cached -> cached instanceof Element)
.map(cached -> (Element) cached)
.filter(cached -> ((Element) fnData).getQualifiedName().equals(cached.getQualifiedName()))
.map(cached -> (Data) cached)
.findFirst();
}
},
(fnData, fnCommit) -> {
if (fnData.getId() != null) {
UUID id = fnData.getId();
// TODO change to dataDao
return elementDao.findByCommitAndId(fnCommit, id)
.orElseThrow(() -> new NoSuchElementException(
String.format("Element with %s %s not found", IDENTITY_FIELD, id)
));
}
else {
String qualifiedName = ((Element) fnData).getQualifiedName();
return elementDao.findByCommitAndQualifiedName(fnCommit, qualifiedName)
.orElseThrow(() -> new NoSuchElementException(
String.format("Element with %s %s not found", QUALIFIED_NAME, qualifiedName)
));
}
});
}

private Optional<Commit> persist(
Commit commit, Branch branch,
Consumer<Data> validator,
BiFunction<Data, Map<UUID, Data>, Optional<Data>> cacheResolver,
BiFunction<Data, Commit, Data> commitResolver) {
commit.setPreviousCommit(null);
if (branch.getHead() != null) {
commit.setPreviousCommit(branch.getHead());
Expand All @@ -94,20 +161,16 @@ public void setId(UUID id) {
}
};

Supplier<Stream<DataVersionImpl>> changeStream = () -> commit.getChange().stream()
.filter(change -> change instanceof DataVersionImpl)
.map(change -> (DataVersionImpl) change);

// 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.
changeStream.get()
commit.getChange().stream()
.peek(change -> change.setIdentity(change.getIdentity() != null ? change.getIdentity() : new DataIdentityImpl()))
.map(DataVersion::getIdentity)
.filter(identity -> identity instanceof DataIdentityImpl)
.map(identity -> (DataIdentityImpl) identity)
.forEach(identity -> identity.setId(identity.getId() != null ? identity.getId() : UUID.randomUUID()));

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

Function<Data, Data> reattachDataFunction = data -> {
Data reattachedData = identifierToDataMap.computeIfAbsent(data.getId(), identifier -> {
if (commit.getPreviousCommit() == null) {
return tombstone;
}
return elementDao.findByCommitAndId(commit.getPreviousCommit(), identifier)
.map(element -> (Data) element)
.orElse(tombstone);
});
if (Objects.equals(reattachedData, tombstone)) {
throw new IllegalArgumentException("Element with ID " + data.getId() + " not found");
}
return reattachedData;
validator.accept(data);
return cacheResolver.apply(data, identifierToDataMap)
.map(fnData -> fnData != tombstone ? fnData : null)
.orElseGet(() -> {
Data resolved = commitResolver.apply(data, commit.getPreviousCommit());
identifierToDataMap.put(resolved.getId(), resolved);
return resolved;
});
};
changeStream.get()
commit.getChange().stream()
.map(DataVersion::getPayload)
.filter(Objects::nonNull)
.forEach(data -> JavaBeanHelper.getBeanProperties(data).values().stream()
Expand Down Expand Up @@ -222,7 +281,7 @@ else if (Collection.class.isAssignableFrom(type)) {
branch.setHead(c);
branchDao.update(branch, em);
});
return persistedCommit.map(PROXY_RESOLVER);
return persistedCommit.map(JpaCommitDao::resolve);
});
}

Expand Down Expand Up @@ -273,7 +332,7 @@ protected Optional<Commit> findByProjectAndId(Project project, UUID id, EntityMa
@Override
public Optional<Commit> findByProjectAndIdResolved(Project project, UUID id) {
return jpaManager.transact(em -> {
return findByProjectAndId(project, id, em).map(PROXY_RESOLVER);
return findByProjectAndId(project, id, em).map(JpaCommitDao::resolve);
});
}
}
Loading

0 comments on commit 20912e3

Please sign in to comment.