Skip to content

Commit 2e2381a

Browse files
committed
Merge branch 'release/2020-03-rc2'
2 parents 7529ba2 + e192db6 commit 2e2381a

131 files changed

Lines changed: 15564 additions & 339 deletions

File tree

Some content is hidden

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

app/dao/impl/jpa/JpaCommitDao.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ protected JPAManager getJpaManager() {
4242
return jpa;
4343
}
4444

45-
private JpaElementDao elementDao = new JpaElementDao();
45+
@Inject
46+
private JpaElementDao elementDao;
4647

4748
@Override
4849
public Optional<Commit> persist(Commit commit) {
@@ -158,7 +159,9 @@ public UUID getId() {
158159
}
159160
}).forEach(em::merge);
160161
commit.setChanges(commit.getChanges().stream().map(em::merge).collect(Collectors.toSet()));
161-
return super.persist(commit, em);
162+
Optional<Commit> persistedCommit = super.persist(commit, em);
163+
persistedCommit.ifPresent(PROXY_RESOLVER);
164+
return persistedCommit;
162165
});
163166
}
164167

app/dao/impl/jpa/JpaElementDao.java

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,28 @@
44
import dao.ElementDao;
55
import javabean.JavaBeanHelper;
66
import jpa.manager.JPAManager;
7+
import org.hibernate.Hibernate;
8+
import org.omg.sysml.internal.CommitIndex;
9+
import org.omg.sysml.internal.impl.CommitIndexImpl;
10+
import org.omg.sysml.internal.impl.CommitIndexImpl_;
711
import org.omg.sysml.lifecycle.Commit;
12+
import org.omg.sysml.lifecycle.ElementVersion;
13+
import org.omg.sysml.lifecycle.impl.ElementIdentityImpl;
14+
import org.omg.sysml.lifecycle.impl.ElementIdentityImpl_;
15+
import org.omg.sysml.lifecycle.impl.ElementVersionImpl;
16+
import org.omg.sysml.lifecycle.impl.ElementVersionImpl_;
817
import org.omg.sysml.metamodel.Element;
918
import org.omg.sysml.metamodel.impl.MofObjectImpl;
1019
import org.omg.sysml.metamodel.impl.MofObjectImpl_;
1120

1221
import javax.inject.Inject;
1322
import javax.inject.Singleton;
23+
import javax.persistence.EntityManager;
24+
import javax.persistence.EntityTransaction;
1425
import javax.persistence.NoResultException;
1526
import javax.persistence.criteria.*;
1627
import java.util.*;
28+
import java.util.concurrent.ConcurrentHashMap;
1729
import java.util.function.Consumer;
1830
import java.util.function.Function;
1931
import java.util.stream.Collectors;
@@ -22,7 +34,7 @@
2234
@Singleton
2335
public class JpaElementDao extends JpaDao<Element> implements ElementDao {
2436
// TODO Explore alternative to serializing lazy entity attributes that doesn't involve resolving all proxies one level.
25-
static Consumer<Element> PROXY_RESOLVER = element -> JavaBeanHelper.getBeanPropertyValues(element).values().stream().flatMap(o -> o instanceof Collection ? ((Collection<?>) o).stream() : Stream.of(o)).forEach(o -> {});
37+
static Consumer<Element> PROXY_RESOLVER = element -> JavaBeanHelper.getBeanPropertyValues(element).values().stream().flatMap(o -> o instanceof Collection ? ((Collection<?>) o).stream() : Stream.of(o)).filter(o -> o instanceof Element).map(o -> (Element) o).forEach(Hibernate::unproxy);
2638

2739
@Inject
2840
private MetamodelProvider metamodelProvider;
@@ -80,17 +92,34 @@ public Set<Element> findAllByCommit(Commit commit) {
8092
return jpa.transact(em -> {
8193
// 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.
8294
Commit c = em.contains(commit) ? commit : em.find(metamodelProvider.getImplementationClass(Commit.class), commit.getId());
83-
return streamFlattenedElements(c).peek(PROXY_RESOLVER).collect(Collectors.toSet());
95+
return getCommitIndex(c, em).getWorkingElementVersions().stream().map(ElementVersion::getData).filter(mof -> mof instanceof Element).map(mof -> (Element) mof).peek(PROXY_RESOLVER).collect(Collectors.toSet());
8496
});
8597
}
8698

8799
@Override
88100
public Optional<Element> findByCommitAndId(Commit commit, UUID id) {
89101
return jpa.transact(em -> {
90-
return queryCommitTree(em.contains(commit) ? commit : em.find(metamodelProvider.getImplementationClass(Commit.class), commit.getId()), c ->
91-
c.getChanges().stream().filter(record -> record.getIdentity() != null && record.getIdentity().getId() != null && record.getData() instanceof Element).filter(record -> id.equals(record.getIdentity().getId())).map(record -> (Element) record.getData()).findAny(),
92-
Optional::isPresent)
93-
.values().stream().filter(Optional::isPresent).map(Optional::get).peek(PROXY_RESOLVER).findAny();
102+
// 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.
103+
Commit c = em.contains(commit) ? commit : em.find(metamodelProvider.getImplementationClass(Commit.class), commit.getId());
104+
CommitIndex commitIndex = getCommitIndex(c, em);
105+
106+
CriteriaBuilder builder = em.getCriteriaBuilder();
107+
CriteriaQuery<ElementVersionImpl> query = builder.createQuery(ElementVersionImpl.class);
108+
Root<CommitIndexImpl> commitIndexRoot = query.from(CommitIndexImpl.class);
109+
SetJoin<CommitIndexImpl, ElementVersionImpl> workingElementVersionsJoin = commitIndexRoot.join(CommitIndexImpl_.workingElementVersions);
110+
Join<ElementVersionImpl, ElementIdentityImpl> elementIdentityJoin = workingElementVersionsJoin.join(ElementVersionImpl_.identity);
111+
query.select(workingElementVersionsJoin).where(
112+
builder.equal(commitIndexRoot.get(CommitIndexImpl_.id), commitIndex.getId()),
113+
builder.equal(elementIdentityJoin.get(ElementIdentityImpl_.id), id)
114+
);
115+
try {
116+
return Optional.of(em.createQuery(query).getSingleResult()).map(ElementVersion::getData).filter(mof -> mof instanceof Element).map(mof -> (Element) mof).map(element -> {
117+
PROXY_RESOLVER.accept(element);
118+
return element;
119+
});
120+
} catch (NoResultException e) {
121+
return Optional.empty();
122+
}
94123
});
95124
}
96125

@@ -114,13 +143,37 @@ protected <T> Map<Commit, T> queryCommitTree(Commit commit, Function<Commit, T>
114143
return results;
115144
}
116145

117-
protected Stream<Element> streamFlattenedElements(Commit commit) {
118-
Set<UUID> visitedElements = new HashSet<>();
119-
Map<Commit, Stream<Element>> results = queryCommitTree(commit,
120-
c -> c.getChanges().stream().filter(record -> record.getIdentity() != null && record.getIdentity().getId() != null && record.getData() instanceof Element).filter(record -> !visitedElements.contains(record.getIdentity().getId())).peek(record -> visitedElements.add(record.getIdentity().getId())).map(record -> (Element) record.getData()));
146+
protected Stream<ElementVersion> streamWorkingElementVersions(Commit commit) {
147+
Set<UUID> visitedElements = ConcurrentHashMap.newKeySet();
148+
Map<Commit, Stream<ElementVersion>> results = queryCommitTree(commit,
149+
c -> c.getChanges().stream().filter(record -> record.getIdentity() != null && record.getIdentity().getId() != null && record.getData() != null).filter(record -> !visitedElements.contains(record.getIdentity().getId())).peek(record -> visitedElements.add(record.getIdentity().getId())));
121150
return results.values().stream().flatMap(Function.identity());
122151
}
123152

153+
protected CommitIndex getCommitIndex(Commit commit, EntityManager em) {
154+
CriteriaBuilder builder = em.getCriteriaBuilder();
155+
CriteriaQuery<CommitIndexImpl> query = builder.createQuery(CommitIndexImpl.class);
156+
Root<CommitIndexImpl> root = query.from(CommitIndexImpl.class);
157+
query.select(root).where(builder.equal(root.get(CommitIndexImpl_.id), commit.getId()));
158+
CommitIndex commitIndex = null;
159+
try {
160+
commitIndex = em.createQuery(query).getSingleResult();
161+
} catch (NoResultException ignored) {
162+
}
163+
if (commitIndex != null) {
164+
return commitIndex;
165+
}
166+
167+
commitIndex = new CommitIndexImpl();
168+
commitIndex.setCommit(commit);
169+
commitIndex.setWorkingElementVersions(streamWorkingElementVersions(commit).collect(Collectors.toSet()));
170+
EntityTransaction transaction = em.getTransaction();
171+
transaction.begin();
172+
em.persist(commitIndex);
173+
transaction.commit();
174+
return commitIndex;
175+
}
176+
124177
private Expression<Boolean> getTypeExpression(CriteriaBuilder builder, Root<?> root) {
125178
return builder.or(metamodelProvider.getAllImplementationClasses().stream().filter(Element.class::isAssignableFrom).map(c -> builder.equal(root.type(), c)).toArray(Predicate[]::new));
126179
}

0 commit comments

Comments
 (0)