2727import javabean .JavaBeanHelper ;
2828import jpa .manager .JPAManager ;
2929import 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 ;
3134import org .omg .sysml .metamodel .Element ;
35+ import org .omg .sysml .metamodel .impl .ElementImpl_ ;
3236
3337import javax .inject .Inject ;
3438import javax .inject .Singleton ;
4145import javax .persistence .criteria .Root ;
4246import java .lang .reflect .Method ;
4347import java .util .*;
48+ import java .util .function .BiFunction ;
49+ import java .util .function .Consumer ;
4450import java .util .function .Function ;
45- import java .util .function .Supplier ;
46- import java .util .function .UnaryOperator ;
4751import 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
5157public 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