diff --git a/AlgebraicDataflowArchitectureModel/.settings/org.eclipse.jdt.core.prefs b/AlgebraicDataflowArchitectureModel/.settings/org.eclipse.jdt.core.prefs index 263a512..d0dc81b 100644 --- a/AlgebraicDataflowArchitectureModel/.settings/org.eclipse.jdt.core.prefs +++ b/AlgebraicDataflowArchitectureModel/.settings/org.eclipse.jdt.core.prefs @@ -1,9 +1,9 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=13 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=14 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=13 +org.eclipse.jdt.core.compiler.compliance=14 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -12,4 +12,4 @@ org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=13 +org.eclipse.jdt.core.compiler.source=14 diff --git a/AlgebraicDataflowArchitectureModel/models/Accounts.model b/AlgebraicDataflowArchitectureModel/models/Accounts.model new file mode 100644 index 0000000..24710ee --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Accounts.model @@ -0,0 +1,7 @@ +channel CIO1 { + out accounts(l:List, signup(name:Str)) = append(l, {"name": name}) +} + +channel CIO2(uid:Int) { + out accounts.{uid}.name(n:Str, changeName(name)) = name +} diff --git a/AlgebraicDataflowArchitectureModel/models/Algo.model b/AlgebraicDataflowArchitectureModel/models/Algo.model deleted file mode 100644 index 6228431..0000000 --- a/AlgebraicDataflowArchitectureModel/models/Algo.model +++ /dev/null @@ -1,12 +0,0 @@ -channel turnA{ - ref handsB(b:List, drawA(target:Int, guess:Int, b, d)) - ref deck(d:List, drawA(target, guess, b, d)) - out handsA(a:List, drawA(target, guess, b, d)) == if(eq(get(b, target), guess), cons(tuple(fst(head(d)), false), a), cons(tuple(fst(head(d)), true), a)) - out handsB(a:List, drawA(target, guess, b, d)) == if(eq(get(b, target), guess), set(a, target, tuple(fst(get(a, target)), true)), a) - out deck(t:List, drawA(target, guess, b, d)) == tail(d) -} -channel turnAA{ - ref handsB(b:List, selectA(target:Int, guess:Int, attacker:Int, b)) - out handsA(a:List, selectA(target, guess, attacker, b)) == if(eq(get(b, target), guess), a, set(a, attacker, tuple(fst(get(a, attacker)), true))) - out handsB(a:List, selectA(target, guess, attacker, b)) == if(eq(get(b, target), guess), set(a, target, tuple(fst(get(a, target)), true)), a) -} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/Algolike.model b/AlgebraicDataflowArchitectureModel/models/Algolike.model index 97aef04..8ea8dc2 100644 --- a/AlgebraicDataflowArchitectureModel/models/Algolike.model +++ b/AlgebraicDataflowArchitectureModel/models/Algolike.model @@ -6,25 +6,25 @@ guessB := 0 } channel targetAInput{ - out targetA(t:Int, setTargetA(a:Int)) == a + out targetA(t:Int, setTargetA(a:Int)) = a } channel targetBInput{ - out targetB(t:Int, setTargetB(b:Int)) == b + out targetB(t:Int, setTargetB(b:Int)) = b } channel attackerAInput{ - out attackerA(t:Int, setAttackerA(a:Int)) == a + out attackerA(t:Int, setAttackerA(a:Int)) = a } channel attackerBInput{ - out attackerB(t:Int, setAttackerB(b:Int)) == b + out attackerB(t:Int, setAttackerB(b:Int)) = b } channel guessAInput{ - out guessA(t:Int, setGuessA(a:Int)) == a + out guessA(t:Int, setGuessA(a:Int)) = a } channel guessBInput{ - out guessB(t:Int, setGuessB(b:Int)) == b + out guessB(t:Int, setGuessB(b:Int)) = b } channel addDeck{ - out deck(d:List, addCard(num:Integer)) == cons(tuple(num, false), d) + out deck(d:List, addCard(num:Integer)) = cons(tuple(num, false), d) } channel drawAInput{ @@ -32,21 +32,21 @@ ref targetA(t:Int, drawAndAttackA(t, g, b)) ref guessA(g:Int, drawAndAttackA(t, g, b)) ref handsB(b:List, drawAndAttackA(t, g, b)) - out resultByDrawingA(sda:Tuple, drawAndAttackA(t, g, b)) == tuple(eq(fst(get(b, t)), g), t) + out resultByDrawingA(sda:Tuple, drawAndAttackA(t, g, b)) = tuple(fst(get(b, t)) == g, t) } channel inputDrawArgsA{ - in resultByDrawingA(sda:Tuple, drawA(sucTrg, d)) == sucTrg + in resultByDrawingA(sda:Tuple, drawA(sucTrg, d)) = sucTrg ref deck(d:List, drawA(sucTrg, d)) - out handsA(outA:List, drawA(sucTrg, d)) == if(fst(sucTrg), - sortByKey(cons(tuple(fst(head(d)),false), outA)), + out handsA(outA:List, drawA(sucTrg, d)) = if(fst(sucTrg), + sortByKey(cons(tuple(fst(head(d)), false), outA)), sortByKey(cons(tuple(fst(head(d)), true), outA))) - out handsB(outB:List, drawA(sucTrg, d)) == if(fst(sucTrg), + out handsB(outB:List, drawA(sucTrg, d)) = if(fst(sucTrg), set(outB, snd(sucTrg), tuple(fst(get(outB, snd(sucTrg))), true)), outB) - out deck(t:List, drawA(sucTrg, d)) == tail(t) + out deck(t:List, drawA(sucTrg, d)) = tail(t) } channel selectAInput{ @@ -54,14 +54,14 @@ ref targetA(t:Int, selectAndAttackA(a, t, g, b)) ref guessA(g:Int, selectAndAttackA(a, t, g, b)) ref handsB(b:List, selectAndAttackA(a, t, g, b)) - out resultBySelectingA(ssa:Tuple, selectAndAttackA(a, t, g, b)) == tuple(eq(fst(get(b, t)), g), t, a) + out resultBySelectingA(ssa:Tuple, selectAndAttackA(a, t, g, b)) = tuple(fst(get(b, t)) == g, t, a) } channel inputSelectArgA{ - in resultBySelectingA(ssa, selectA(sucTrgAtk)) == sucTrgAtk - out handsA(outA, selectA(sucTrgAtk)) == if(fst(sucTrgAtk), + in resultBySelectingA(ssa, selectA(sucTrgAtk)) = sucTrgAtk + out handsA(outA, selectA(sucTrgAtk)) = if(fst(sucTrgAtk), outA, set(outA, snd(snd(sucTrgAtk)), tuple(fst(get(outA, snd(snd(sucTrgAtk)))), true))) - out handsB(outB, selectA(sucTrgAtk)) == if(fst(sucTrgAtk), + out handsB(outB, selectA(sucTrgAtk)) = if(fst(sucTrgAtk), set(outB, fst(snd(sucTrgAtk)), tuple(fst(get(outB, fst(snd(sucTrgAtk)))), true)), outB) } @@ -69,21 +69,21 @@ ref targetB(t:Int, drawAndAttackB(t, g, a)) ref guessB(g:Int, drawAndAttackB(t, g, a)) ref handsA(a:List, drawAndAttackB(t, g, a)) - out resultByDrawingB(sdb:Tuple, drawAndAttackB(t, g, a)) == tuple(eq(fst(get(a, t)), g), t) + out resultByDrawingB(sdb:Tuple, drawAndAttackB(t, g, a)) = tuple(fst(get(a, t)) == g, t) } channel inputDrawArgsB{ - in resultByDrawingB(sdb:Tuple, drawB(sucTrg, d)) == sucTrg + in resultByDrawingB(sdb:Tuple, drawB(sucTrg, d)) = sucTrg ref deck(d:List, drawB(sucTrg, d)) - out handsB(outB:List, drawB(sucTrg, d)) == if(fst(sucTrg), + out handsB(outB:List, drawB(sucTrg, d)) = if(fst(sucTrg), sortByKey(cons(tuple(fst(head(d)),false), outB)), sortByKey(cons(tuple(fst(head(d)), true), outB))) - out handsA(outA:List, drawB(sucTrg, d)) == if(fst(sucTrg), + out handsA(outA:List, drawB(sucTrg, d)) = if(fst(sucTrg), set(outA, snd(sucTrg), tuple(fst(get(outA, snd(sucTrg))), true)), outA) - out deck(t:List, drawB(sucTrg, d)) == tail(t) + out deck(t:List, drawB(sucTrg, d)) = tail(t) } channel selectBInput{ @@ -91,23 +91,23 @@ ref targetB(t:Int, selectAndAttackB(atk, t, g, a)) ref guessB(g:Int, selectAndAttackB(atk, t, g, a)) ref handsA(a:List, selectAndAttackB(atk, t, g, a)) - out resultBySelectingB(ssb:Tuple, selectAndAttackB(atk, t, g, a)) == tuple(eq(fst(get(a, t)), g), t, atk) + out resultBySelectingB(ssb:Tuple, selectAndAttackB(atk, t, g, a)) = tuple(fst(get(a, t)) == g, t, atk) } channel inputSelectArgB{ - in resultBySelectingB(ssb, selectB(sucTrgAtk)) == sucTrgAtk - out handsB(outB, selectB(sucTrgAtk)) == if(fst(sucTrgAtk), + in resultBySelectingB(ssb, selectB(sucTrgAtk)) = sucTrgAtk + out handsB(outB, selectB(sucTrgAtk)) = if(fst(sucTrgAtk), outB, set(outB, snd(snd(sucTrgAtk)), tuple(fst(get(outB, snd(snd(sucTrgAtk)))), true))) - out handsA(outA, selectB(sucTrgAtk)) == if(fst(sucTrgAtk), + out handsA(outA, selectB(sucTrgAtk)) = if(fst(sucTrgAtk), set(outA, fst(snd(sucTrgAtk)), tuple(fst(get(outA, fst(snd(sucTrgAtk)))), true)), outA) } channel judgeA{ - in handsA(a:List, judge(j)) == j - out loseA(la:Bool, judge(j)) == eq(length(extractFaceDown(j)), 0) + in handsA(a:List, judge(j)) = j + out loseA(la:Bool, judge(j)) = length(extractFaceDown(j)) == 0 } channel judgeB{ - in handsB(b:List, judge(j)) == j - out loseB(lb:Bool, judge(j)) == eq(length(extractFaceDown(j)), 0) + in handsB(b:List, judge(j)) = j + out loseB(lb:Bool, judge(j)) = length(extractFaceDown(j)) == 0 } \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/Base.model b/AlgebraicDataflowArchitectureModel/models/Base.model index ac44843..bb460e4 100644 --- a/AlgebraicDataflowArchitectureModel/models/Base.model +++ b/AlgebraicDataflowArchitectureModel/models/Base.model @@ -1,13 +1,13 @@ channel CIO{ - out r1(x1:Int, set1(y1:Int)) == y1 - out r1(x1, e) == x1 + out r1(x1:Int, set1(y1:Int)) = y1 + out r1(x1, e) = x1 } channel CIO2{ - out r2(x2:Int, set2(y2:Int)) == y2 - out r2(x2, e) == x2 + out r2(x2:Int, set2(y2:Int)) = y2 + out r2(x2, e) = x2 } channel C1{ - in r1(x1, update(x1:Int, y1:Int, x2:Int, y2:Int)) == y1 - in r2(x2, update(x1, y1, x2, y2)) == y2 - out r3(x3:Int, update(x1, y1, x2, y2)) == x1 + y1 + x2 + y2 + in r1(x1, update(x1:Int, y1:Int, x2:Int, y2:Int)) = y1 + in r2(x2, update(x1, y1, x2, y2)) = y2 + out r3(x3:Int, update(x1, y1, x2, y2)) = x1 + y1 + x2 + y2 } \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/Bug.model b/AlgebraicDataflowArchitectureModel/models/Bug.model deleted file mode 100644 index f31727b..0000000 --- a/AlgebraicDataflowArchitectureModel/models/Bug.model +++ /dev/null @@ -1,7 +0,0 @@ -channel CIO{ - out aUa(a, input(x:Int)) == x -} -channel C1{ - in aUa(a, update(x)) == x - out aUb(b, update(x)) == x + 3 -} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/Citrus.model b/AlgebraicDataflowArchitectureModel/models/Citrus.model new file mode 100644 index 0000000..356405a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Citrus.model @@ -0,0 +1,75 @@ +channel Signup { + out accounts(accDB:Map, signup(aid:Str)) = insert(accDB, aid, {"favorites": nil, "books": nil}) +} + +channel CreateBook(aid:Str) { + out accounts.{aid}.books(bookList:List, createBook(title:Str)) = append(bookList, {"title": title, "todos": nil, "favorited": nil}) +} + +channel DeleteAccount { + out accounts(accDB:Map, deleteAccount(aid:Str)) = if(contains(accDB, aid), delete(accDB, aid), accDB) +} + +channel ChangeAccountName { + out accounts(accDB:Map, changeAccountId(aid:Str, newAid:Str)) = if(aid == newAid, accDB, delete(insert(accDB, newAid, lookup(accDB, aid)), aid)) +} + +channel ChangeBookName(aid:Str, bid:Int) { + out accounts.{aid}.books.{bid}.title(title:Str, changeBookName(newTitle)) = newTitle +} + +channel DeleteBook(aid:Str) { + out accounts.{aid}.books(bookList:List, deleteBook(bid:Int)) = if(bid < length(bookList), remove(bookList, bid), bookList) +} + +channel CreateToDo(aid:Str, bid:Int) { + out accounts.{aid}.books.{bid}.todos(toDoDB:Map, createtodo(year:Str, month:Str, day:Str, title:Str)) = + if( + contains(toDoDB,year), + if( + contains(lookup(toDoDB,year),month), + if( + contains(lookup(lookup(toDoDB,year),month),day), + insert(toDoDB,year,insert(lookup(toDoDB,year),month,insert(lookup(lookup(toDoDB,year),month),day,append(lookup(lookup(lookup(toDoDB,year),month),day),{"title":title,"check":false})))), + insert(toDoDB,year,insert(lookup(toDoDB,year),month,insert(lookup(lookup(toDoDB,year),month),day,append(nil,{"title":title,"check":false})))) + ), + insert(toDoDB,year,insert(lookup(toDoDB,year),month,insert(nil,day,append(nil,{"title":title,"check":false})))) + ), + insert(toDoDB,year,insert(nil,month,insert(nil,day,append(nil,{"title":title,"check":false})))) + ) +} + +channel ChangeToDoName(aid:Str, bid:Int, year:Str, month:Str, day:Str, tid:Int) { + out accounts.{aid}.books.{bid}.todos.{year}.{month}.{day}.{tid}.title(title:Str, changeToDoName(newTitle)) = newTitle +} + +channel ChangeCheck(aid:Str, bid:Int, year:Str, month:Str, day:Str, tid:Int) { + out accounts.{aid}.books.{bid}.todos.{year}.{month}.{day}.{tid}.check(check:Bool, changeCheck(newCheck)) = newCheck +} + +channel DeleteToDo(aid:Str, bid:Int) { + out accounts.{aid}.books.{bid}.todos(toDoDB:Map, deleteToDo(year:Str, month:Str, day:Str, tid:Int)) = insert(toDoDB, + year, + insert(lookup(toDoDB, year), + month, + insert(lookup(lookup(toDoDB, year), month), + day, + remove(lookup(lookup(lookup(toDoDB, year), month), day), + tid)))) +} + +channel AddFavorited(aid:Str, bid:Int) { + out accounts.{aid}.books.{bid}.favorited(faList:List, addFavorited(o_aid:Str)) = if(aid==o_aid, + faList, + if(contains(faList, o_aid), + remove(faList, indexOf(faList, o_aid)), + append(faList, o_aid))) + out accounts.{o_aid}.favorites(aDB:Map, addFavorited(o_aid:Str)) + = if(aid==o_aid, + aDB, + if(contains(aDB, aid), + if(contains(lookup(aDB, aid), bid), + insert(aDB, aid, remove(lookup(aDB, aid), indexOf(lookup(aDB, aid), bid))), + insert(aDB, aid, append(lookup(aDB, aid), bid))), + insert(aDB, aid, append(nil, bid)))) +} diff --git a/AlgebraicDataflowArchitectureModel/models/Clock.dtram b/AlgebraicDataflowArchitectureModel/models/Clock.dtram new file mode 100644 index 0000000..bbeb6dc --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Clock.dtram @@ -0,0 +1,27 @@ +model { +channel CIO1 { + out min(m: Int, tick) = (m + 1) % 60 +} +channel HourUpdate { + in hour(h: Int, update(h2)) = h2 + out hour_ang(h_ang: Double, update(h2)) = h2 / 6 * PI +} +channel MinUpdate { + in min(m, update(m2)) = m2 + out min_ang(m_ang: Double, update(m2)) = m2 / 30 * PI +} +channel Clock { + in min(m, update(m2)) = m2 + out hour(h, update(m2)) = if(m2 == 0, (h + 1) % 24, h) +} +} +geometry { + node c HourUpdate:520,340,30,30 + node c MinUpdate:520,100,30,30 + node c Clock:280,220,30,30 + node r min_ang:670,100,80,30 + node r min:250,100,80,30 + node r hour:270,340,80,30 + node r hour_ang:680,340,80,30 + node ioc CIO1:100,100,30,30 +} diff --git a/AlgebraicDataflowArchitectureModel/models/Clock.model b/AlgebraicDataflowArchitectureModel/models/Clock.model new file mode 100644 index 0000000..0ecb11b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Clock.model @@ -0,0 +1,15 @@ +channel CIO1 { + out min(m: Int, tick) = (m + 1) % 60 +} +channel HourUpdate { + in hour(h: Int, update(h2)) = h2 + out hour_ang(h_ang: Double, update(h2)) = h2 / 6 * PI +} +channel MinUpdate { + in min(m, update(m2)) = m2 + out min_ang(m_ang: Double, update(m2)) = m2 / 30 * PI +} +channel Clock { + in min(m, update(m2)) = m2 + out hour(h, update(m2)) = if(m2 == 0, (h + 1) % 24, h) +} diff --git a/AlgebraicDataflowArchitectureModel/models/CustomerManagement.model b/AlgebraicDataflowArchitectureModel/models/CustomerManagement.model new file mode 100644 index 0000000..5277f32 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/CustomerManagement.model @@ -0,0 +1,21 @@ +channel AddCustomer { + out customers(csDB:Map, addCustomer(uid:Str, org:Str)) = insert(csDB, uid, {"organization": org}) +} + +channel AddCampany { + out companies(cmDB:Map, addCampany(cid:Str, address:Str)) = insert(cmDB, cid, {"address": address}) +} + +channel SetCustomerOrganization(uid:Str) { + out customers.{uid}.organization(prevCid:Str, setOrganization(cid)) = cid +} + +channel SetCompanyAddress(cid:Str) { + out companies.{cid}.address(prevAdd:Str, setAddress(add)) = add +} + +channel UpdateCustomerAddress(uid:Str) { + in customers.{uid}.organization(prevCid, updateCustomerAddress(cid, add)) = cid + in companies.{cid}.address(prevAdd, updateCustomerAddress(cid, add)) = add + out customers.{uid}.address(prevAdd, updateCustomerAddress(cid, add)) = add +} diff --git a/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model b/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model deleted file mode 100644 index f140bff..0000000 --- a/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model +++ /dev/null @@ -1,33 +0,0 @@ -channel C_CustomerAOff_In { - out customerA_off(c:String, setOff(x)) == x - out customerA_off(c, e) == c -} - -channel C_CustomerBOff_In { - out customerB_off(c:String, setOff(x)) == x - out customerB_off(c, e) == c -} - -channel C_CompanyC1Add_In { - out companyC1_add(a:String, setAdd(y)) == y - out companyC1_add(a, e) == a -} - -channel C_CompanyC2Add_In { - out companyC2_add(a:String, setAdd(y)) == y - out companyC2_add(a, e) == a -} - -channel CA { - in customerA_off(c, sync(z, u, v)) == z - in companyC1_add(a1, sync(z, u, v)) == u - in companyC2_add(a2, sync(z, u, v)) == v - out customerA_add(a3:String, sync(z, u, v)) == if(eq(z, C1), u, if(eq(z, C2), v, null)) -} - -channel CB { - in customerB_off(c, sync(z, u, v)) == z - in companyC1_add(a1, sync(z, u, v)) == u - in companyC2_add(a2, sync(z, u, v)) == v - out customerB_add(a3:String, sync(z, u, v)) == if(eq(z, C1), u, if(eq(z, C2), v, null)) -} diff --git a/AlgebraicDataflowArchitectureModel/models/Game.model b/AlgebraicDataflowArchitectureModel/models/Game.model index bc90ba4..1952ff0 100644 --- a/AlgebraicDataflowArchitectureModel/models/Game.model +++ b/AlgebraicDataflowArchitectureModel/models/Game.model @@ -1,32 +1,32 @@ channel CIO { - out force(f:Double, action(x:Double)) == x - out time(t:Double, action(x)) == t + 0.01 - out force(f, e) == x - out time(t, e) == t + 0.01 + out force(f:Double, action(x:Double)) = x + out time(t:Double, action(x)) = t + 0.01 + out force(f, e) = x + out time(t, e) = t + 0.01 } channel CIO2 { - out velocity(v:Double, setVel(x:Double)) == x - out velocity(v, e) == x + out velocity(v:Double, setVel(x:Double)) = x + out velocity(v, e) = x } channel CIO3 { - out mass(m:Double, setMass(x:Double)) == x - out mass(m, e) == m + out mass(m:Double, setMass(x:Double)) = x + out mass(m, e) = m } channel C1 { - in force(f, update1(y, z)) == y - in mass(m, update1(y, z)) == z - out acceleration(a: Double, update1(y, z)) == y / z + in force(f, update1(y, z)) = y + in mass(m, update1(y, z)) = z + out acceleration(a: Double, update1(y, z)) = y / z } channel C2 { - in acceleration(a, update2(z)) == z - out velocity(v:Double, update2(z)) == v + 0.01 * z + in acceleration(a, update2(z)) = z + out velocity(v:Double, update2(z)) = v + 0.01 * z } channel C3 { - in velocity(v, update3(u)) == u - out position(p:Double, update3(u)) == p + 0.01 * u + in velocity(v, update3(u)) = u + out position(p:Double, update3(u)) = p + 0.01 * u } \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/GroupChat.model b/AlgebraicDataflowArchitectureModel/models/GroupChat.model new file mode 100644 index 0000000..1203e1a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/GroupChat.model @@ -0,0 +1,27 @@ +channel Signup { + out accounts(acDB:Map, signUp(aid:Str)) = insert(acDB, aid, {"notifications": nil}) +} + +channel HasRead(aid:Str) { + out accounts.{aid}.notifications(ntMap:Map, hasRead(gid:Str)) = delete(ntMap, gid) +} + +channel CreateGroup { + out groups(grDB:Map, createGroup(gid:Str)) = insert(grDB, gid, {"members": nil, "messages": nil}) +} + +channel AddGroupMember(gid:Str) { + out groups.{gid}.members(memList:List, addGroupMember(aid:Str)) = append(memList, aid) +} + +channel PostMessage(gid:Str) { + out groups.{gid}.messages(mesList:List, postMessage(message:Str)) = append(mesList, message) +} + +channel Notify(gid:Str) { + in groups.{gid}.messages(prevMesList, notify(m)) = mesList + for EachMember(mno:Int) { + ref groups.{gid}.members.{mno}(m.{mno}:Str, notify(m)) + out accounts.{m.{mno}:Str}.notifications(prevNtMap:Map, notify(m)) = insert(prevNtMap, gid, true) + } +} diff --git a/AlgebraicDataflowArchitectureModel/models/Hello.model b/AlgebraicDataflowArchitectureModel/models/Hello.model deleted file mode 100644 index 46bb932..0000000 --- a/AlgebraicDataflowArchitectureModel/models/Hello.model +++ /dev/null @@ -1,3 +0,0 @@ -channel cio { - out r1(x1:Int,set(x2)) == x2 -} diff --git a/AlgebraicDataflowArchitectureModel/models/Hello2.model b/AlgebraicDataflowArchitectureModel/models/Hello2.model deleted file mode 100644 index 4815cf6..0000000 --- a/AlgebraicDataflowArchitectureModel/models/Hello2.model +++ /dev/null @@ -1,3 +0,0 @@ -channel cio { - out r1(x1:Int,set(x2:Int)) == x2:Int -} diff --git a/AlgebraicDataflowArchitectureModel/models/HelloWorld.model b/AlgebraicDataflowArchitectureModel/models/HelloWorld.model deleted file mode 100644 index 44aa310..0000000 --- a/AlgebraicDataflowArchitectureModel/models/HelloWorld.model +++ /dev/null @@ -1,7 +0,0 @@ -channel cio { - out r1(x1:Int,set(x2:Int)) == x2:Int -} -channel c2 { - in r1(x1:Int,update(x2:Int)) == x2:Int - out r2(y1:Int,update(x2:Int)) == (x2:Int+1) -} diff --git a/AlgebraicDataflowArchitectureModel/models/InventoryManagement.model b/AlgebraicDataflowArchitectureModel/models/InventoryManagement.model new file mode 100644 index 0000000..578d56c --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/InventoryManagement.model @@ -0,0 +1,7 @@ +channel ItemRegistration { + out inventory(itemDB:Map, registerItem(itemId:Str, itemName:Str, quantity:Int)) = insert(itemDB, itemId, {"count": quantity, "name": itemName}) +} + +channel ReceivingOrShipping(itemId:Str) { + out inventory.{itemId}.count(prev_quantity:Int, receiveOrShip(quantity:Int)) = prev_quantity + quantity +} diff --git a/AlgebraicDataflowArchitectureModel/models/JumpGame.model b/AlgebraicDataflowArchitectureModel/models/JumpGame.model index 1981df9..43b8d0c 100644 --- a/AlgebraicDataflowArchitectureModel/models/JumpGame.model +++ b/AlgebraicDataflowArchitectureModel/models/JumpGame.model @@ -1,7 +1,8 @@ init { force := pair(0.0, 0.0) time := 0.0 - move := pair(0.0, 0.0) + movex := 0.0 + movey := 0.0 mass := 1.0 ground := true acceleration := pair(0.0, 0.0) @@ -12,59 +13,59 @@ gameover := false } channel CIO { - out force(f:Pair, gravity(y:Double)) == pair(0.0, y) - out time(t:Double, gravity(y)) == t + 0.01 + out force(f:Pair, gravity(y:Double)) = pair(0.0, y) + out time(t:Double, gravity(y)) = t + 0.01 } channel CIO2 { - out movex(x:Double, run(x2:Double)) == x2 + out movex(x:Double, run(x2:Double)) = x2 } channel CIO3 { - out movey(y:Double, jump(y2:Double)) == y2 + out movey(y:Double, jump(y2:Double)) = y2 } channel CIO4 { - out mass(m:Double, setMass(x:Double)) == x + out mass(m:Double, setMass(x:Double)) = x } channel CIO5 { - out ground(g:Bool, openHole) == false - out ground(g, closeHole) == true + out ground(g:Bool, openHole) = false + out ground(g, closeHole) = true } channel C1 { ref onground(o, update1(f2, m2, o)) - in force(f, update1(f2, m2, o)) == f2 - in mass(m, update1(f2, m2, o)) == m2 - out acceleration(a:Pair, update1(f2, m2, o)) == if(o, pair(left(f2) / m2, 0.0), pair(left(f2) / m2, right(f2) / m2)) + in force(f, update1(f2, m2, o)) = f2 + in mass(m, update1(f2, m2, o)) = m2 + out acceleration(a:Pair, update1(f2, m2, o)) = if(o, pair(left(f2) / m2, 0.0), pair(left(f2) / m2, right(f2) / m2)) } channel C2 { ref onground(o, update3(a2, o)) - in acceleration(a, update3(a2, o)) == a2 - out velocity(v:Pair, update3(a2, o)) == if(and(o, lt(right(v), 0.0)), + in acceleration(a, update3(a2, o)) = a2 + out velocity(v:Pair, update3(a2, o)) = if(o && right(v) < 0.0, pair(left(v) + 0.01 * left(a2), 0.0), pair(left(v) + 0.01 * left(a2), right(v) + 0.01 * right(a2))) } channel C3 { ref onground(o, update4(x2, o)) - in movex(x, update4(x2, o)) == x2 - out velocity(v:Pair, update4(x2, o)) == if(o, pair(x2, right(v)), v) + in movex(x, update4(x2, o)) = x2 + out velocity(v:Pair, update4(x2, o)) = if(o, pair(x2, right(v)), v) } channel C4 { ref onground(o, update5(x2, o)) - in movey(y, update5(y2, o)) == y2 - out velocity(v:Pair, update5(y2, o)) == if(o, pair(left(v), y2), v) + in movey(y, update5(y2, o)) = y2 + out velocity(v:Pair, update5(y2, o)) = if(o, pair(left(v), y2), v) } channel C5 { - in velocity(v, update6(v2, g)) == v2 + in velocity(v, update6(v2, g)) = v2 ref ground(g, update6(v2, g)) - out position(p:Pair, update6(v2, g)) == if(and(eq(g, true), lt(right(p) + 0.01 * right(v2), 0.0)), + out position(p:Pair, update6(v2, g)) = if(g == true && right(p) + 0.01 * right(v2) > 0.0, pair(left(p) + 0.01 * left(v2), 0.0), pair(left(p) + 0.01 * left(v2), right(p) + 0.01 * right(v2))) } channel C6 { - in position(p, update2(p2, g2)) == p2 - in ground(g, update2(p2, g2)) == g2 - out onground(o:Bool, update2(p2, g2)) == and(eq(g2, true), le(right(p2), 0.0)) + in position(p, update2(p2, g2)) = p2 + in ground(g, update2(p2, g2)) = g2 + out onground(o:Bool, update2(p2, g2)) = (g2 == true && right(p2) <= 0.0) } channel C7 { - in position(p, update7(p2)) == p2 - out clear(c:Bool, update7(p2)) == if(gt(left(p2), 100.0), true, false) - out gameover(go:Bool, update7(p2)) == if(lt(right(p2), -1.0), true, false) + in position(p, update7(p2)) = p2 + out clear(c:Bool, update7(p2)) = (left(p2) > 100.0) + out gameover(go:Bool, update7(p2)) = (right(p2) < -1.0) } \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/Kinematics.model b/AlgebraicDataflowArchitectureModel/models/Kinematics.model new file mode 100644 index 0000000..3d10af4 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Kinematics.model @@ -0,0 +1,20 @@ +channel CIO { + out force(f:Double, action(x)) = x + out time(t:Double, action(x)) = t + 0.01 +} + +channel C1 { + in force(f, update1(y, m)) = y + in mass(m, update1(y, m)) = m + out acceleration(a:Double, update1(y, m)) = y / m +} + +channel C2 { + in acceleration(a, update2(z)) = z + out velocity(v:Double, update2(z)) = v + 0.01 * z +} + +channel C3 { + in velocity(v, update3(u)) = u + out position(p:Double, update3(u)) = p + 0.01 * u +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/Kinetics.model b/AlgebraicDataflowArchitectureModel/models/Kinetics.model deleted file mode 100644 index 5218206..0000000 --- a/AlgebraicDataflowArchitectureModel/models/Kinetics.model +++ /dev/null @@ -1,20 +0,0 @@ -channel CIO { - out force(f:Double, action(x)) == x - out time(t:Double, action(x)) == t + 0.01 -} - -channel C1 { - in force(f, update1(y, m)) == y - in mass(m, update1(y, m)) == m - out acceleration(a:Double, update1(y, m)) == y / m -} - -channel C2 { - in acceleration(a, update2(z)) == z - out velocity(v:Double, update2(z)) == v + 0.01 * z -} - -channel C3 { - in velocity(v, update3(u)) == u - out position(p:Double, update3(u)) == p + 0.01 * u -} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/NemophilaAccounts.model b/AlgebraicDataflowArchitectureModel/models/NemophilaAccounts.model new file mode 100644 index 0000000..0158d26 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/NemophilaAccounts.model @@ -0,0 +1,86 @@ +channel CIO_CreateAccount { + out accounts(acList:List, createAccount(name:Str)) = append(acList, { + "name": name, + "posts": nil, + "newFriend": null, + "delReqFriend": null, + "newRequesting": null, + "friends": nil, + "requesting": nil, + "requested": nil, + }) +} + +channel CIO_ChangeName(uid:Str) { + out accounts.{uid}.name(prevName:Str, changeName(name)) = name +} + +channel CIO_CreatePost(uid:Str) { + out accounts.{uid}.posts(postsList:List, createPost(comment:Str)) = cons(comment:Str, postsList) +} + +channel CIO_DeletePost(uid:Str) { + out accounts.{uid}.posts(postsList:List, deletePost(pid:Str)) = remove(postsList, pid:Str) +} + +channel CIO_PostRequesting(sendId:Str) { + out accounts.{sendId}.newRequesting(preNewResuesting:Str, postRequesting(recvId:Str)) = recvId +} + +channel C_AddRequesting(sendId:Str) { + in accounts.{sendId}.newRequesting(preNewResuesting:Str, sync1(recvId:Str, sendRequested:Map, recvRequesting:Map, sendFriends:Map)) = recvId + ref accounts.{sendId}.friends(sendFriends:Map, sync1(recvId:Str, sendRequested:Map, recvRequesting:Map, sendFriends:Map)) + ref accounts.{sendId}.requested(sendRequested:Map, sync1(recvId:Str, sendRequested:Map, recvRequesting:Map, sendFriends:Map)) + ref accounts.{recvId}.requesting(recvRequesting:Map, sync1(recvId:Str, sendRequested:Map, recvRequesting:Map, sendFriends:Map)) + + out accounts.{sendId}.requesting(sendRequesting:Map, sync1(recvId:Str, sendRequested:Map, recvRequesting:Map, sendFriends:Map)) = if(contains(sendFriends:Map, recvId) == true, + sendRequesting, + insert(sendRequesting:Map, recvId:Str, true)) + out accounts.{recvId}.requested(recvRequested:Map, sync1(recvId:Str, sendRequested:Map, recvRequesting:Map, sendFriends:Map)) = if(contains(sendFriends:Map, recvId) == true, + recvRequested, + insert(recvRequested:Map, sendId:Str, true)) +} + +channel CIO_RejectRequest(recvId:Str) { + out accounts.{sendId}.requesting(sendRequesting:Map, rejectRequest(sendId:Str)) = delete(sendRequesting:Map, recvId:Str) + out accounts.{recvId}.requested(recvRequested:Map, rejectRequest(sendId:Str)) = delete(recvRequested:Map, sendId:Str) +} + +channel CIO_AdmitFriend(recvId:Str) { + out accounts.{recvId}.newFriend(preNewFriend:Str, admitFriend(sendId:Str)) = sendId +} + +channel C_AddFriend(recvId:Str) { + in accounts.{recvId}.newFriend(preSendId:Str, sync2(sendId:Str, preSendTing:Map, preRecvTed:Map)) = sendId + ref accounts.{sendId}.requesting(preSendTing:Map, sync2(sendId:Str, preSendTing:Map, preRecvTed:Map)) + ref accounts.{recvId}.requested(preRecvTed:Map, sync2(sendId:Str, preSendTing:Map, preRecvTed:Map)) + + out accounts.{sendId}.friends(sendFriends:Map, sync2(sendId:Str, preSendTing:Map, preRecvTed:Map)) = if(contains(preSendTing:Map, recvId) == true && contains(preRecvTed:Map, sendId) == true, + insert(sendFriends, recvId:Str, true), + sendFriends) + out accounts.{recvId}.friends(recvFriends:Map, sync2(sendId:Str, preSendTing:Map, preRecvTed:Map)) = if(contains(preSendTing:Map, recvId) == true && contains(preRecvTed:Map, sendId) == true, + insert(recvFriends, sendId:Str, true), + recvFriends) + out accounts.{sendId}.requesting(sendRequesting:Map, sync2(sendId:Str, preSendTing:Map, preRecvTed:Map)) = if(contains(preSendTing:Map, recvId) == true && contains(preRecvTed:Map, sendId) == true, + delete(sendRequesting:Map, recvId:Str), + sendRequesting) + out accounts.{recvId}.requested(recvRequested:Map, sync2(sendId:Str, preSendTing:Map, preRecvTed:Map)) = if(contains(preSendTing:Map, recvId) == true && contains(preRecvTed:Map, sendId) == true, + delete(recvRequested:Map, sendId:Str), + recvRequested) +} + +channel CIO_DeleteFriendRequest(sendId:Str) { + out accounts.{sendId}.delReqFriend(preDelReqFriend:Str, deleteFriend(recvId:Str)) = recvId +} + +channel CIO_DeleteFriend(sendId:Str) { + in accounts.{sendId}.delReqFriend(preRecvId:Str, sync3(recvId:Str, preSendFriends:Map, preRecvFriends:Map)) = recvId + ref accounts.{sendId}.friends(preSendFriends:Map, sync3(recvId:Str, preSendFriends:Map, preRecvFriends:Map)) + ref accounts.{recvId}.friends(preRecvFriends:Map, sync3(recvId:Str, preSendFriends:Map, preRecvFriends:Map)) + out accounts.{sendId}.friends(sendFriends:Map, sync3(recvId:Str, preSendFriends:Map, preRecvFriends:Map)) = if(contains(preSendFriends:Map, recvId) == true || contains(preRecvFriends:Map, sendId) == true, + delete(sendFriends:Map, recvId:Str), + sendFriends) + out accounts.{recvId}.friends(recvFriends:Map, sync3(recvId:Str, preSendFriends:Map, preRecvFriends:Map)) = if(contains(preSendFriends:Map, recvId) == true || contains(preRecvFriends:Map, sendId) == true, + delete(recvFriends:Map, sendId:Str), + recvFriends) +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/OnlineBattleGame.model b/AlgebraicDataflowArchitectureModel/models/OnlineBattleGame.model new file mode 100644 index 0000000..d91b144 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/OnlineBattleGame.model @@ -0,0 +1,31 @@ +channel Signup { + out accounts(acDB:Map, signUp(aid:Str, name:Str)) = insert(acDB, aid, {"name": name}) +} + +channel ChangeName(aid:Str) { + out accounts.{aid}.name(prevName:Str, changeName(name)) = name +} + +channel CreateRoom { + out rooms(rmDB:Map, createRoom(rid:Str, blueId:Str, redId:Str)) = insert(rmDB, rid, {"blue_id": blueId, "red_id": redId}) +} + +channel ChangeRedId(rid:Str) { + out rooms.{rid}.red_id(prevRedId:Str, changeRedId(redId)) = redId +} + +channel ChangeBlueId(rid:Str) { + out rooms.{rid}.blue_id(prevBlueId:Str, changeBlueId(blueId)) = blueId +} + +channel UpdateRedName(rid:Str) { + in rooms.{rid}.red_id(prevAid:Str, updateRedName(aid, name)) = aid + in accounts.{aid}.name(prevName:Str, updateRedName(aid, name)) = name + out rooms.{rid}.red_name(prevName:Str, updateRedName(aid, name)) = name +} + +channel UpdateBlueName(rid:Str) { + in rooms.{rid}.blue_id(prevAid:Str, updateBlueName(aid, name)) = aid + in accounts.{aid}.name(prevName:Str, updateBlueName(aid, name)) = name + out rooms.{rid}.blue_name(prevName:Str, updateBlueName(aid, name)) = name +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/OnlineBattleGame2.model b/AlgebraicDataflowArchitectureModel/models/OnlineBattleGame2.model new file mode 100644 index 0000000..ccd15a7 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/OnlineBattleGame2.model @@ -0,0 +1,33 @@ +channel Signup { + out accounts(acDB:Map, signUp(aid:Str, name:Str)) = insert(acDB, aid, {"name": name, "point": 0}) +} + +channel ChangeName(aid:Str) { + out accounts.{aid}.name(prevName:Str, changeName(name)) = name +} + +channel CreateRoom { + out rooms(rmDB:Map, createRoom(rid:Str)) = insert(rmDB, rid, {"members": nil, "battle": false}) +} + +channel AddRoomMember(rid:Str) { + out rooms.{rid}.members(mList:List, addRoomMember(id:Str)) = append(mList, {"id": id}) +} + +channel Battle(rid:Str) { + out rooms.{rid}.battle(prevHasWon, battle(hasWon:Bool)) = hasWon +} + +channel UpdateName(rid:Str, mno:Int) { + in rooms.{rid}.members.{mno}.id(prevMid:Str, updateName(mid, name)) = mid + in accounts.{mid}.name(prevName:Str, updateName(mid, name)) = name + out rooms.{rid}.members.{mno}.name(prevName:Str, updateName(mid, name)) = name +} + +channel UpdatePoint(rid:Str) { + in rooms.{rid}.battle(prevState, updatePoint(hasWon, mid)) = hasWon + for EachMember(mno:Int) { + ref rooms.{rid}.members.{mno}.id(mid:Str, updatePoint(hasWon, mid)) + out accounts.{mid}.point(prevPoint:Int, updatePoint(hasWon, mid)) = if(hasWon, prevPoint + 1, prevPoint) + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/POS.dtram b/AlgebraicDataflowArchitectureModel/models/POS.dtram index dc3d2d1..d1cb11c 100644 --- a/AlgebraicDataflowArchitectureModel/models/POS.dtram +++ b/AlgebraicDataflowArchitectureModel/models/POS.dtram @@ -1,18 +1,18 @@ model { channel CIO { - out payment(p:Int, purchase(x:Int)) == x + out payment(p:Int, purchase(x:Int)) = x } channel C3 { - in history(h, update3(u)) == u - out total(t:Int, update3(u)) == sum(u) + in history(h, update3(u)) = u + out total(t:Int, update3(u)) = sum(u) } channel C1 { - in payment(p, update1(y)) == y - out points(l:Int, update1(y)) == floor(y * 0.05) + in payment(p, update1(y)) = y + out points(l:Int, update1(y)) = floor(y * 0.05) } channel C2 { - in payment(p, update2(z)) == z - out history(h:List, update2(z)) == cons(z, h) + in payment(p, update2(z)) = z + out history(h:List, update2(z)) = cons(z, h) } } geometry { diff --git a/AlgebraicDataflowArchitectureModel/models/POS.model b/AlgebraicDataflowArchitectureModel/models/POS.model index 150c106..c15c931 100644 --- a/AlgebraicDataflowArchitectureModel/models/POS.model +++ b/AlgebraicDataflowArchitectureModel/models/POS.model @@ -1,15 +1,15 @@ channel CIO { - out payment(p:Int, purchase(x:Int)) == x + out payment(p:Int, purchase(x:Int)) = x } channel C3 { - in history(h, update3(u)) == u - out total(t:Int, update3(u)) == sum(u) + in history(h, update3(u)) = u + out total(t:Int, update3(u)) = sum(u) } channel C1 { - in payment(p, update1(y)) == y - out points(l:Int, update1(y)) == floor(y * 0.05) + in payment(p, update1(y)) = y + out points(l:Int, update1(y)) = floor(y * 0.05) } channel C2 { - in payment(p, update2(z)) == z - out history(h:List, update2(z)) == cons(z, h) + in payment(p, update2(z)) = z + out history(h:List, update2(z)) = cons(z, h) } diff --git a/AlgebraicDataflowArchitectureModel/models/POS2.model b/AlgebraicDataflowArchitectureModel/models/POS2.model index 6ae676d..0ee31d2 100644 --- a/AlgebraicDataflowArchitectureModel/models/POS2.model +++ b/AlgebraicDataflowArchitectureModel/models/POS2.model @@ -1,14 +1,14 @@ channel CIO { - out payment(p:Int, purchase(x:Int)) == x + out payment(p:Int, purchase(x:Int)) = x } channel C1 { - in payment(p1, update1(y)) == y - out points(l:Int, update1(y)) == floor(y * 0.05) + in payment(p1, update1(y)) = y + out points(l:Int, update1(y)) = floor(y * 0.05) } channel C2 { - in payment(p1, update2(z)) == z - out history(h:List, update2(z)) == cons(z, h) - out total(t:Int, update2(z)) == z + t + in payment(p1, update2(z)) = z + out history(h:List, update2(z)) = cons(z, h) + out total(t:Int, update2(z)) = z + t } \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/RefBug.model b/AlgebraicDataflowArchitectureModel/models/RefBug.model new file mode 100644 index 0000000..e421f6b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/RefBug.model @@ -0,0 +1,19 @@ +init { + constant := 10 + variable := 10 + ans := 20 +} + +channel changeVar { + out variable(cur: Int, change(next: Int)) = next +} + +channel changeConst { + out constant(const: Int, change(next: Int)) = next +} + +channel calcAns { + in variable(curVar: Int, calc(const: Int, nextVar: Int)) = nextVar + ref constant(const: Int, calc(const: Int, var: Int)) + out ans(curAns: Int, calc(const: Int, var: Int)) = var + const +} diff --git a/AlgebraicDataflowArchitectureModel/models/Search.model b/AlgebraicDataflowArchitectureModel/models/Search.model new file mode 100644 index 0000000..e401c34 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Search.model @@ -0,0 +1,25 @@ +init { + accounts := {"001": {"name": "Alice", "age": 25, "address": "Kobe"}, + "002": {"name": "Bob", "age": 25, "address": "Osaka"}, + "003": {"name": "Carol", "age": 22, "address": "Kobe"}, + "004": {"name": "Dave", "age": 25, "address": "Kobe"} + } +} + +channel Signup { + out accounts(acDB:Map, signUp(aid:Str, name:Str, age:Int, address:Str)) = insert(acDB, aid, {"name": name, "age": age, "address": address}) +} + +channel ChangeName(aid:Str) { + out accounts.{aid}.name(n:Str, changeName(name:Str)) = name +} + +channel Query { + out query(q:Json, enterQuery(age:Int, address:Str)) = {"age": age, "address": address} +} + +channel SearchAccount { + in accounts(acDB:Map, searchAccount(acDB2, q2)) = acDB2 + in query(q:Json, searchAccount(acDB2, q2)) = q2 + out result(resultMap:Map, searchAccount(acDB2, q2)) = search(acDB2, q2) +} diff --git a/AlgebraicDataflowArchitectureModel/models/SimpleAddressBook.model b/AlgebraicDataflowArchitectureModel/models/SimpleAddressBook.model new file mode 100644 index 0000000..9a9f38a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/SimpleAddressBook.model @@ -0,0 +1,11 @@ +channel Init { + out book.owner(pre_name: Str, init(name: Str)) = name +} + +channel Add { + out book.addr(pre_addr: Map, add(name: Str, addr: Str)) = insert(pre_addr, name, addr) +} + +channel Del { + out book.addr(pre_addr: Map, del(name: Str)) = delete(pre_addr, name) +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/SimpleTwitter.model b/AlgebraicDataflowArchitectureModel/models/SimpleTwitter.model new file mode 100644 index 0000000..486fafb --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/SimpleTwitter.model @@ -0,0 +1,7 @@ +channel Signup { + out accounts(accountDB:Map, signUp(accountId:Str, name:Str)) = insert(accountDB, accountId, {"name": name, "tweets": nil}) +} + +channel Tweet(accountId:Str) { + out accounts.{accountId}.tweets(tweetList:List, tweet(contents:Str)) = append(tweetList, contents) +} diff --git a/AlgebraicDataflowArchitectureModel/models/SimpleUI.model b/AlgebraicDataflowArchitectureModel/models/SimpleUI.model new file mode 100644 index 0000000..b105544 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/SimpleUI.model @@ -0,0 +1,114 @@ +init { + screenTemplates := { + "000": {"widgets": {"001": {"type": "textInput", "text": "", "state": 0, "visible": true}, + "002": {"type": "button", "text": "Next", "state": 0, "visible": true}}, + "layout": true, + "screenId": "000"}, + "001": {"widgets": {"003": {"type": "label", "text": "label", "state": 0, "visible": true}, + "004": {"type": "button", "text": "Back", "state": 0, "visible": true}}, + "layout": true, + "screenId": "001"} + } +} + +native channel ScreenUpdate { + in screen(curSc: Json, screenUpdate(curSc, nextSc)) = nextSc +} + +native channel SetLayout { + in screen.layout(curLayout: Bool, setLayout(nextLayout)) = nextLayout +} + +native channel SetVisible(wid: Str) { + in screen.widgets.{wid}.visible(curVisible: Bool, setVisible(nextVisible)) = nextVisible +} + +native channel SetText(wid: Str) { + in screen.widgets.{wid}.text(curText: Str, setText(nextText)) = nextText +} + +native channel SetX(wid: Str) { + in screen.widgets.{wid}.x(curX: Int, setX(nextX)) = nextX +} + +native channel SetY(wid: Str) { + in screen.widgets.{wid}.y(curY: Int, setY(nextY)) = nextY +} + +native channel SetWidth(wid: Str) { + in screen.widgets.{wid}.width(curWidth: Int, setWidth(nextWidth)) = nextWidth +} + +native channel SetHeight(wid: Str) { + in screen.widgets.{wid}.height(curHeight: Int, setHeight(nextHeight)) = nextHeight +} + +native channel MouseEvent(wid: Str) { + out screen.widgets.{wid}.state(curState: Int, mouseEvent(nextState)) = nextState +} + +native channel TextEvent(wid: Str) { + out screen.widgets.{wid}.text(curText: Str, textEvent(nextText)) = nextText +} + +channel ChangeCurScreen { + out curScreen(curScId: Str, changeCurScreen(nextScId)) = nextScId +} + +channel ScreenTransition { + in curScreen(curScId: Str, transScreen(nextScId, screen)) = nextScId + ref screenTemplates.{nextScId}(screen, transScreen(nextScId, screen)) + out screen(curS, transScreen(nextScId, screen)) = screen +} + +channel EventDispatch(wid: Str) { + in screen.widgets.{wid}.state(curState: Int, dispatchEvent(curScId, wid, nextState)) = nextState + ref curScreen(curScId: Str, dispatchEvent(curScId, wid, nextState)) + out screenTemplates.{curScId}.widgets.{wid}.state(curState: Int, dispatchEvent(curScId, wid, nextState)) = nextState +} + +channel EventHandler1(scId: Str, wid: Str) { + in screenTemplates.{scId="000"}.widgets.{wid="002"}.state(curState: Int, handleEvent1(nextState)) = nextState + out curScreen(curScId: Str, handleEvent1(nextState)) = if(nextState == 0, "001", curScId) +} + +channel EventHandler2(scId: Str, wid: Str) { + in screenTemplates.{scId="001"}.widgets.{wid="004"}.state(curState: Int, handleEvent2(nextState)) = nextState + out curScreen(curScId: Str, handleEvent2(nextState)) = if(nextState == 0, "000", curScId) +} + +channel ChangeLayout { + out screen.layout(curLayout: Bool, changeLayout(layout)) = layout +} + +channel ChangeX(wid: Str) { + out screen.widgets.{wid}.x(curX: Int, changeX(x)) = x +} + +channel ChangeY(wid: Str) { + out screen.widgets.{wid}.y(curY: Int, changeY(y)) = y +} + +channel AddButton { + out screen.widgets(widgets: Map, addButton(wid: Str, text: Str)) = insert(widgets, wid, {"type": "button", "text": text, "state": 0}) +} + +channel AddLabel { + out screen.widgets(widgets: Map, addLabel(wid: Str, text: Str)) = insert(widgets, wid, {"type": "label", "text": text, "state": 0}) +} + +channel AddTextInput { + out screen.widgets(widgets: Map, addTextInput(wid: Str)) = insert(widgets, wid, {"type": "textInput", "text": "", "state": 0}) +} + +channel AddMovableButton { + out screen.widgets(widgets: Map, addMovableButton(wid: Str, text: Str, x: Int, y: Int, width: Int, height: Int)) = insert(widgets, wid, {"type": "button", "text": text, "x": x, "y": y, "width": width, "height": height, "state": 0}) +} + +channel AddMovableLabel { + out screen.widgets(widgets: Map, addMovableLabel(wid: Str, text: Str, x: Int, y: Int, width: Int, height: Int)) = insert(widgets, wid, {"type": "label", "text": text, "x": x, "y": y, "width": width, "height": height, "state": 0}) +} + +channel AddMovableTextInput { + out screen.widgets(widgets: Map, addMovableTextInput(wid: Str, x: Int, y: Int, width: Int, height: Int)) = insert(widgets, wid, {"type": "textInput", "text": "", "x": x, "y": y, "width": width, "height": height, "state": 0}) +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/StockManagement.model b/AlgebraicDataflowArchitectureModel/models/StockManagement.model index b133f44..4528cb7 100644 --- a/AlgebraicDataflowArchitectureModel/models/StockManagement.model +++ b/AlgebraicDataflowArchitectureModel/models/StockManagement.model @@ -4,47 +4,47 @@ } channel CIO_enter { - out arrival(s:Tuple, arrive(item:Str, num:Int)) == tuple(item, num) + out arrival(s:Tuple, arrive(item:Str, num:Int)) = tuple(item, num) } channel CIO_req { - out request(r:Tuple, req(item:Str, num:Int)) == tuple(item, num) + out request(r:Tuple, req(item:Str, num:Int)) = tuple(item, num) } channel C1 { - in arrival(ar, update1(ar2, st)) == ar2 + in arrival(ar, update1(ar2, st)) = ar2 ref stock(st:Map, update1(ar2, st)) - out available(av:Tuple, update1(ar2, st)) == tuple(fst(ar2), snd(ar2) + lookup(st, fst(ar2))) + out available(av:Tuple, update1(ar2, st)) = tuple(fst(ar2), snd(ar2) + lookup(st, fst(ar2))) } channel C2 { - in available(av, update2(av2, sh)) == av2 + in available(av, update2(av2, sh)) = av2 ref shortage(sh, update2(av2, sh)) - out deriver(dr:Tuple, update2(av2, sh)) == if(ge(snd(av2), lookup(sh, fst(av2))), + out deriver(dr:Tuple, update2(av2, sh)) = if(snd(av2) >= lookup(sh, fst(av2)), tuple(fst(av2), lookup(sh, fst(av2)), snd(av2) - lookup(sh, fst(av2))), tuple(fst(av2), 0, snd(av2))) - out shortage(s, update2(av2, sh)) == if(ge(snd(av2), lookup(s, fst(av2))), + out shortage(s, update2(av2, sh)) = if(snd(av2) >= lookup(s, fst(av2)), insert(s, fst(av2), 0), s) } channel C3 { - in deriver(dr, update3(dr2)) == dr2 - out stock(st, update3(dr2)) == insert(st, fst(dr2), snd(snd(dr2))) + in deriver(dr, update3(dr2)) = dr2 + out stock(st, update3(dr2)) = insert(st, fst(dr2), snd(snd(dr2))) } channel C4 { - in deriver(dr, update4(dr2)) == dr2 - out shipping(sp:Tuple, update4(dr2)) == tuple(fst(dr2), fst(snd(dr2))) + in deriver(dr, update4(dr2)) = dr2 + out shipping(sp:Tuple, update4(dr2)) = tuple(fst(dr2), fst(snd(dr2))) } channel C5 { - in request(rq, update5(rq2, st)) == rq2 + in request(rq, update5(rq2, st)) = rq2 ref stock(st, update5(rq2, st)) - out deriver(dr, update5(rq2, st)) == if(ge(lookup(st, fst(rq2)), snd(rq2)), + out deriver(dr, update5(rq2, st)) = if(lookup(st, fst(rq2)) >= snd(rq2), tuple(fst(rq2), snd(rq2), lookup(st, fst(rq2)) - snd(rq2)), tuple(fst(rq2), 0, lookup(st, fst(rq2)))) - out shortage(sh, update5(rq2, st)) == if(ge(lookup(st, fst(rq2)), snd(rq2)), + out shortage(sh, update5(rq2, st)) = if(lookup(st, fst(rq2)) >= snd(rq2), sh, insert(sh, fst(rq2), lookup(sh, fst(rq2)) + snd(rq2))) } \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/StockManagement2.model b/AlgebraicDataflowArchitectureModel/models/StockManagement2.model index 6ee866a..36d6966 100644 --- a/AlgebraicDataflowArchitectureModel/models/StockManagement2.model +++ b/AlgebraicDataflowArchitectureModel/models/StockManagement2.model @@ -4,10 +4,10 @@ } channel CIO_enter { - out deriver(s:Tuple, arrive(item:Str, num:Int)) == tuple(item, num, num) + out deriver(s:Tuple, arrive(item:Str, num:Int)) = tuple(item, num, num) } channel C3 { - in deriver(dr, update3(dr2)) == dr2 - out shipping(sp:Tuple, update3(dr2)) == tuple(fst(dr2), fst(snd(dr2))) + in deriver(dr, update3(dr2)) = dr2 + out shipping(sp:Tuple, update3(dr2)) = tuple(fst(dr2), fst(snd(dr2))) } diff --git a/AlgebraicDataflowArchitectureModel/models/TableUI.model b/AlgebraicDataflowArchitectureModel/models/TableUI.model new file mode 100644 index 0000000..defb520 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/TableUI.model @@ -0,0 +1,114 @@ +init { + screenTemplates := { + "000": { + "widgets": { + "001": {"type": "textInput", "text": "", "state": 0, "visible": true}, + "002": {"type": "table", "text": "testTeble", "state": 0, "visible": true, + "data": {"_": {"name": "_", "age": 0}}, + "rowHeight": 40, + "colWidth": 100, + "columns": append(append(nil, "name"), "age"), + "primaryKeyName": "id", + } + }, + "layout": true + } + } + screen1 := "000" + w002 := "002" +} + +native channel ScreenUpdate { + in screen(curSc: Json, update(curSc, nextSc)) = nextSc +} + +native channel SetLayout { + in screen.layout(curLayout: Bool, setLayout(nextLayout)) = nextLayout +} + +native channel SetVisible(wid: Str) { + in screen.widgets.{wid}.visible(curVisible: Bool, setVisible(nextVisible)) = nextVisible +} + +native channel SetText(wid: Str) { + in screen.widgets.{wid}.text(curText: Str, setText(nextText)) = nextText +} + +native channel SetX(wid: Str) { + in screen.widgets.{wid}.x(curX: Int, setX(nextX)) = nextX +} + +native channel SetY(wid: Str) { + in screen.widgets.{wid}.y(curY: Int, setY(nextY)) = nextY +} + +native channel SetWidth(wid: Str) { + in screen.widgets.{wid}.width(curWidth: Int, setWidth(nextWidth)) = nextWidth +} + +native channel SetHeight(wid: Str) { + in screen.widgets.{wid}.height(curHeight: Int, setHeight(nextHeight)) = nextHeight +} + +native channel MouseEvent(wid: Str) { + out screen.widgets.{wid}.state(curState: Int, mouseEvent(nextState)) = nextState +} + +native channel OnTableChanged(wid: Str) { + in screen.widgets.{wid}.data(curData: Map, tableChanged(nextData)) = nextData +} + +native channel TextEvent(wid: Str) { + out screen.widgets.{wid}.text(curText: Str, textEvent(nextText)) = nextText +} + +channel ChangeCurScreen { + out curScreen(curScId: Str, changeCurScreen(nextScId)) = nextScId +} + +channel ScreenTransition { + in curScreen(curScId: Str, transScreen(nextScId, screen)) = nextScId + ref screenTemplates.{nextScId}(screen, transScreen(nextScId, screen)) + out screen(curS, transScreen(nextScId, screen)) = screen +} + +channel EventDispatch(wid: Str) { + in screen.widgets.{wid}.state(curState: Int, dispatchEvent(curScId, wid, nextState)) = nextState + ref curScreen(curScId: Str, dispatchEvent(curScId, wid, nextState)) + out screenTemplates.{curScId}.widgets.{wid}.state(curState: Int, dispatchEvent(curScId, wid, nextState)) = nextState +} + + +channel EventHandler1(scId: Str, wid: Str) { + in screenTemplates.{scId="000"}.widgets.{wid="002"}.state(curState: Int, handleEvent1(nextState)) = nextState + out curScreen(curScId: Str, handleEvent1(nextState)) = if(nextState == 0, "001", curScId) +} + +channel EventHandler2(scId: Str, wid: Str) { + in screenTemplates.{scId="001"}.widgets.{wid="004"}.state(curState: Int, handleEvent2(nextState)) = nextState + out curScreen(curScId: Str, handleEvent2(nextState)) = if(nextState == 0, "000", curScId) +} + +channel EventHandler3(curScId: Str, wid: Str) { + in screenTemplates.{curScId="000"}.widgets.{wid="002"}.data(curData: Map, handleEvent3(nextData, wid)) = nextData + out screen.widgets.{wid="002"}.data(curData: Map, handleEvent3(nextData, wid)) = nextData +} + +channel addAccount { + out accounts(accounts: Map, addAccount(id: Str, name: Str, age: Int)) = insert(accounts, id, {"name": name, "age": age}) +} + +channel changeNameOfAccount(id: Str) { + out accounts.{id}.name(curName: Str, changeName(nextName: Str)) = nextName +} + +channel changeNameOfAccount(id: Str) { + out accounts.{id}.age(curAge: Int, changeAge(nextAge: Int)) = nextAge +} + +channel sendAccountToTable { + in accounts(cur: Map, sendAccount(next: Map, scId:Str, wid:Str)) = next + ref screen1(scId:Str, sendAccount(next, scId, wid)) + ref w002(wid: Str, sendAccount(next, scId, wid)) + out screenTemplates.{scId}.widgets.{wid}.data(cur: Map, sendAccount(next, scId, wid)) = next +} diff --git a/AlgebraicDataflowArchitectureModel/models/Test.model b/AlgebraicDataflowArchitectureModel/models/Test.model deleted file mode 100644 index a8a1348..0000000 --- a/AlgebraicDataflowArchitectureModel/models/Test.model +++ /dev/null @@ -1,9 +0,0 @@ -channel CIO { - out a(x:Int, set(n:Int)) == n -} - -channel C1 { - in a(x, update(y)) == y - out b(z, update(y)) == y + 1 - out c(v, update(y)) == v + y -} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/Timer.model b/AlgebraicDataflowArchitectureModel/models/Timer.model new file mode 100644 index 0000000..83a66d5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Timer.model @@ -0,0 +1,15 @@ +native channel TimersUpdated { + in timers(curTimers: Map, update(curTimers, nextTimers)) = nextTimers +} + +native channel TimerEvent(tid: Str) { + out timers.{tid}.count(count: Long, tick()) = count + 1 +} + +channel StartTimer { + out timers(timers: Map, startTimer(tid: Str, interval: Long)) = insert(timers, tid, {"interval": interval, "count": 0}) +} + +channel ClearTimer { + out timers(timers: Map, clearTimer(tid: Str)) = delete(timers, tid) +} diff --git a/AlgebraicDataflowArchitectureModel/models/TravelDistance.model b/AlgebraicDataflowArchitectureModel/models/TravelDistance.model new file mode 100644 index 0000000..07d12db --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/TravelDistance.model @@ -0,0 +1,13 @@ +channel CX { + out pos_x(prev_x: Double, setX(cur_x: Double)) = cur_x +} + +channel CY { + out pos_y(prev_y: Double, setY(cur_y: Double)) = cur_y +} + +channel C { + in pos_x(prev_x, move(dx, dy)) = prev_x + dx + in pos_y(prev_y, move(dx, dy)) = prev_y + dy + out dist(prev_d, move(dx, dy)) = prev_d + sqrt(dx * dx + dy * dy) +} diff --git a/AlgebraicDataflowArchitectureModel/models/Triangle.model b/AlgebraicDataflowArchitectureModel/models/Triangle.model new file mode 100644 index 0000000..cf3d0e0 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Triangle.model @@ -0,0 +1,13 @@ +channel cio1 { + out base(x: Double, setBase(x2)) = x2 +} + +channel cio2 { + out height(y: Double, setHeight(y2)) = y2 +} + +channel triangle { + in base(x, update(x2, y2)) = x2 + in height(y, update(x2, y2)) = y2 + out hypothenuse(z: Double, update(x2, y2)) = sqrt(x2 * x2 + y2 * y2) +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/Triangle2.model b/AlgebraicDataflowArchitectureModel/models/Triangle2.model new file mode 100644 index 0000000..5067fa0 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Triangle2.model @@ -0,0 +1,13 @@ +channel cio1 { + out base(x: Double, setBase(x2)) = x2 +} + +channel cio2 { + out height(y: Double, setHeight(y2)) = y2 +} + +channel triangle { + in base(x, update: Tuple) = fst(update) + in height(y, update) = snd(update) + out hypothenuse(z: Double, update) = sqrt(fst(update) * fst(update) + snd(update) * snd(update)) +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/Twitter.model b/AlgebraicDataflowArchitectureModel/models/Twitter.model index 57de3b3..e5c46a8 100644 --- a/AlgebraicDataflowArchitectureModel/models/Twitter.model +++ b/AlgebraicDataflowArchitectureModel/models/Twitter.model @@ -1,47 +1,20 @@ -channel a_Tweet { - out a_tweets(l:List, a_tweet(t:Str, time:Long)) == cons(tuple(time, t), l) +channel SignUp { + out accounts(acDB:Map, signup(id:Str, name:Str)) = insert(acDB, id, {"name": name, "tweets": nil, "followees": nil, "timeline": nil}) } -channel a_Follow { - out a_following(f:List, a_follow(u:Int)) == cons(u, f) +channel Tweet(id:Str) { + out accounts.{id}.tweets(twList:List, tweet(text:Str, time:Long)) = append(twList, {"time": time, "text": text}) } -channel a_Home { - in a_tweets(la1, update_a(f2, la2, lb2, lc2)) == la2 - in b_tweets(lb1, update_a(f2, la2, lb2, lc2)) == lb2 - in c_tweets(lc1, update_a(f2, la2, lb2, lc2)) == lc2 - in a_following(f, update_a(f2, la2, lb2, lc2)) == f2 - out a_timeline(t:List, update_a(f2, la2, lb2, lc2)) == merge(la2, if(contains(f2,2), merge(lb2, if(contains(f2,3), lc2, nil)), if(contains(f2,3), lc2, nil))) +channel AddFollowee(id:Str) { + out accounts.{id}.followees(fwList:List, addFollowee(flwId:Str)) = append(fwList, flwId) } -channel b_Tweet { - out b_tweets(l:List, b_tweet(t:Str, time:Long)) == cons(tuple(time, t), l) -} - -channel b_Follow { - out b_following(f:List, b_follow(u:Int)) == cons(u, f) -} - -channel b_Home { - in a_tweets(la1, update_b(f2, la2, lb2, lc2)) == la2 - in b_tweets(lb1, update_b(f2, la2, lb2, lc2)) == lb2 - in c_tweets(lc1, update_b(f2, la2, lb2, lc2)) == lc2 - in b_following(f, update_b(f2, la2, lb2, lc2)) == f2 - out b_timeline(t:List, update_b(f2, la2, lb2, lc2)) == merge(lb2, if(contains(f2,1), merge(la2, if(contains(f2,3), lc2, nil)), if(contains(f2,3), lc2, nil))) -} - -channel c_Tweet { - out c_tweets(l:List, c_tweet(t:Str, time:Long)) == cons(tuple(time, t), l) -} - -channel c_Follow { - out c_following(f:List, c_follow(u:Int)) == cons(u, f) -} - -channel c_Home { - in a_tweets(la1, update_c(f2, la2, lb2, lc2)) == la2 - in b_tweets(lb1, update_c(f2, la2, lb2, lc2)) == lb2 - in c_tweets(lc1, update_c(f2, la2, lb2, lc2)) == lc2 - in c_following(f, update_c(f2, la2, lb2, lc2)) == f2 - out c_timeline(t:List, update_c(f2, la2, lb2, lc2)) == merge(lc2, if(contains(f2,1), merge(la2, if(contains(f2,2), lb2, nil)), if(contains(f2,2), lb2, nil))) -} +channel UpdateTimeline(myId:Str) { + in accounts.{myId}.tweets(t1:List, m) = m.myTweets + for EachFollowee(no:Int) { + in accounts.{myId}.followees.{no}(id:Str, m) = m.flw.{no}.id + in accounts.{m.flw.{no}.id}.tweets(t2:List, m) = m.flw.{no}.tweets + } + out accounts.{myId}.timeline(l:List, m) = merge(m.myTweets, m.flw) +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/VotingSystem.model b/AlgebraicDataflowArchitectureModel/models/VotingSystem.model new file mode 100644 index 0000000..b0ce8f8 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/VotingSystem.model @@ -0,0 +1,14 @@ +channel Signup { + out accounts(acDB:Map, signUp(aid:Str, name:Str)) = insert(acDB, aid, {"name": name, "vote": ""}) +} + +channel Cast(aid:Str) { + out accounts.{aid}.vote(preV, cast(v:Str)) = v +} + +channel Collect { + for EachAccount(aid:Str) { + in accounts.{aid}.vote(preV:Str, collect(m)) = m.{aid} + } + out counts(preCnts:Json, collect(m)) = m +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/WOS.dtram b/AlgebraicDataflowArchitectureModel/models/WOS.dtram index 45f640c..81b0779 100644 --- a/AlgebraicDataflowArchitectureModel/models/WOS.dtram +++ b/AlgebraicDataflowArchitectureModel/models/WOS.dtram @@ -1,17 +1,17 @@ model { channel CIO2 { - out highest(h:Double, reset(v)) == v + out highest(h:Double, reset(v)) = v } channel CIO1 { - out temp_f(p:Double, observe(x)) == x + out temp_f(p:Double, observe(x)) = x } channel C1{ - in temp_f(q:Double, conversion(y)) == y - out temp_c(r:Double, conversion(z)) == (z-32) / 1.8 + in temp_f(q:Double, conversion(y)) = y + out temp_c(r:Double, conversion(z)) = (z-32) / 1.8 } channel C2{ - in temp_f(q:Double, update(y)) == y - out highest(h:Double, update(z)) == if(gt(z, h), z, h) + in temp_f(q:Double, update(y)) = y + out highest(h:Double, update(z)) = if(z >= h, z, h) } } geometry { diff --git a/AlgebraicDataflowArchitectureModel/models/WeatherObservationSystem.model b/AlgebraicDataflowArchitectureModel/models/WeatherObservationSystem.model index 2cd84d7..0096407 100644 --- a/AlgebraicDataflowArchitectureModel/models/WeatherObservationSystem.model +++ b/AlgebraicDataflowArchitectureModel/models/WeatherObservationSystem.model @@ -1,14 +1,14 @@ channel CIO2 { - out highest(h:Double, reset(v)) == v + out highest(h:Double, reset(v)) = v } channel CIO1 { - out temp_f(p:Double, observe(x)) == x + out temp_f(p:Double, observe(x)) = x } channel C1{ - in temp_f(q:Double, conversion(y)) == y - out temp_c(r:Double, conversion(z)) == (z-32) / 1.8 + in temp_f(q:Double, conversion(y)) = y + out temp_c(r:Double, conversion(z)) = (z-32) / 1.8 } channel C2{ - in temp_f(q:Double, update(y)) == y - out highest(h:Double, update(z)) == if(gt(z, h), z, h) + in temp_f(q:Double, update(y)) = y + out highest(h:Double, update(z)) = if(z >= h, z, h) } diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Accounts/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Accounts/Account.java new file mode 100644 index 0000000..423e265 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Accounts/Account.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Account { + private String name; + public Map getValue() { + Map temp_nil1 = new HashMap<>(); + temp_nil1.put("name",this.getName()); + return temp_nil1; + } + public String getName() { + return this.name; + } + public void changeName(int uid, String name) { + this.name = name; + } + public Account(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Accounts/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Accounts/Accounts.java new file mode 100644 index 0000000..d851471 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Accounts/Accounts.java @@ -0,0 +1,42 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/accounts") +@Component +public class Accounts { + private List value = new ArrayList<>(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public List getValue() { + return new ArrayList<>(value); + } + public Account getAccount(int uid) { + return this.value.get(uid); + } + @Path("/{uid}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getAccountValue(@PathParam("uid") int uid) { + return getAccount(uid).getValue(); + } + @Path("/{uid}/name") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getNameValue(@PathParam("uid") int uid) { + return getAccount(uid).getName(); + } + @POST + public void signup(@FormParam("name") String name) { + this.value.add(new Account(name)); + } + @Path("/{uid}/name") + @PUT + public void changeName(@PathParam("uid") int uid, @FormParam("name") String name) { + getAccount(uid).changeName(uid, name); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PULL-first/Hour.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PULL-first/Hour.java new file mode 100644 index 0000000..a7acf75 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PULL-first/Hour.java @@ -0,0 +1,28 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/hour") +@Component +public class Hour { + private int value = 0; + @Produces(MediaType.APPLICATION_JSON) + @GET + public int getValue() { + return value; + } + @POST + public void updateFromMin(@FormParam("min") int min) { + int temp_if0; + if ((min==0)) { + temp_if0 = ((this.value+1)%24); + } else { + temp_if0 = this.value; + } + this.value = temp_if0; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PULL-first/Hour_ang.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PULL-first/Hour_ang.java new file mode 100644 index 0000000..9c14018 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PULL-first/Hour_ang.java @@ -0,0 +1,19 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/hour_ang") +@Component +public class Hour_ang { + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public double getValue() { + int hour = client.target("http://localhost:8080").path("/hour").request().get(int.class); + return ((hour/6)*Math.PI); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PULL-first/Min.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PULL-first/Min.java new file mode 100644 index 0000000..db4cea5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PULL-first/Min.java @@ -0,0 +1,27 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/min") +@Component +public class Min { + private int value = 0; + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public int getValue() { + return value; + } + @POST + public void tick() throws JsonProcessingException { + Form form = new Form(); + form.param("min", Integer.toString(this.value)); + Entity
entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); + String result = client.target("http://localhost:8080").path("/hour").request().post(entity, String.class); + this.value = ((this.value+1)%60); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PULL-first/Min_ang.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PULL-first/Min_ang.java new file mode 100644 index 0000000..96ae12b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PULL-first/Min_ang.java @@ -0,0 +1,19 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/min_ang") +@Component +public class Min_ang { + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public double getValue() { + int min = client.target("http://localhost:8080").path("/min").request().get(int.class); + return ((min/30)*Math.PI); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PUSH-first/Hour.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PUSH-first/Hour.java new file mode 100644 index 0000000..12f10e1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PUSH-first/Hour.java @@ -0,0 +1,33 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/hour") +@Component +public class Hour { + private double value = 0.0; + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public double getValue() { + return value; + } + @POST + public void updateFromMin(@FormParam("min") double min) throws JsonProcessingException { + double temp_if1; + if ((min==0)) { + temp_if1 = ((this.value+1)%24); + } else { + temp_if1 = this.value; + } + this.value = temp_if1; + Form form = new Form(); + form.param("hour", Double.toString(this.value)); + Entity entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); + String result = client.target("http://localhost:8080").path("/hour_ang").request().put(entity, String.class); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PUSH-first/Hour_ang.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PUSH-first/Hour_ang.java new file mode 100644 index 0000000..5412a9a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PUSH-first/Hour_ang.java @@ -0,0 +1,22 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/hour_ang") +@Component +public class Hour_ang { + private double value = 0.0; + @Produces(MediaType.APPLICATION_JSON) + @GET + public double getValue() { + return value; + } + @PUT + public void updateFromHour(@FormParam("hour") double hour) { + this.value = ((hour/6)*Math.PI); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PUSH-first/Min.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PUSH-first/Min.java new file mode 100644 index 0000000..f068cb6 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PUSH-first/Min.java @@ -0,0 +1,31 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/min") +@Component +public class Min { + private double value = 0.0; + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public double getValue() { + return value; + } + @POST + public void tick() throws JsonProcessingException { + Form form = new Form(); + form.param("min", Double.toString(this.value)); + Entity entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); + String result = client.target("http://localhost:8080").path("/hour").request().post(entity, String.class); + form = new Form(); + form.param("min", Double.toString(this.value)); + entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); + result = client.target("http://localhost:8080").path("/min_ang").request().put(entity, String.class); + this.value = ((this.value+1)%60); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PUSH-first/Min_ang.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PUSH-first/Min_ang.java new file mode 100644 index 0000000..b467b97 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/Clock/PUSH-first/Min_ang.java @@ -0,0 +1,22 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/min_ang") +@Component +public class Min_ang { + private double value = 0.0; + @Produces(MediaType.APPLICATION_JSON) + @GET + public double getValue() { + return value; + } + @PUT + public void updateFromMin(@FormParam("min") double min) { + this.value = ((min/30)*Math.PI); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/CustomerManagement/Companies.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/CustomerManagement/Companies.java new file mode 100644 index 0000000..a67aea8 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/CustomerManagement/Companies.java @@ -0,0 +1,42 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/companies") +@Component +public class Companies { + private Map value = new HashMap<>(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getValue() { + return new HashMap<>(value); + } + public Company getCompany(String cid) { + return this.value.get(cid); + } + @Path("/{cid}/address") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getAddressValue(@PathParam("cid") String cid) { + return getCompany(cid).getAddress(); + } + @Path("/{cid}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getCompanyValue(@PathParam("cid") String cid) { + return getCompany(cid).getValue(); + } + @Path("/{cid}/address") + @PUT + public void setAddress(@PathParam("cid") String cid, @FormParam("add") String add) { + getCompany(cid).setAddress(cid, add); + } + @POST + public void addCampany(@FormParam("address") String address, @FormParam("cid") String cid) { + this.value.put(cid,new Company(address)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/CustomerManagement/Company.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/CustomerManagement/Company.java new file mode 100644 index 0000000..24e1769 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/CustomerManagement/Company.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Company { + private String address; + public Map getValue() { + Map temp_nil2 = new HashMap<>(); + temp_nil2.put("address",this.getAddress()); + return temp_nil2; + } + public String getAddress() { + return this.address; + } + public void setAddress(String cid, String add) { + this.address = add; + } + public Company(String address) { + this.address = address; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/CustomerManagement/Customer.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/CustomerManagement/Customer.java new file mode 100644 index 0000000..96f2373 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/CustomerManagement/Customer.java @@ -0,0 +1,26 @@ +import java.util.*; +import javax.ws.rs.client.*; + +public class Customer { + private Client client = ClientBuilder.newClient(); + private String organization; + public Map getValue() { + Map temp_nil3 = new HashMap<>(); + temp_nil3.put("address",this.getAddress()); + temp_nil3.put("organization",this.getOrganization()); + return temp_nil3; + } + public String getAddress() { + String address = client.target("http://localhost:8080").path("/companies/" + organization + "/address").request().get(String.class); + return address; + } + public String getOrganization() { + return this.organization; + } + public void setOrganization(String uid, String cid) { + this.organization = cid; + } + public Customer(String organization) { + this.organization = organization; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/CustomerManagement/Customers.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/CustomerManagement/Customers.java new file mode 100644 index 0000000..22358f4 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/CustomerManagement/Customers.java @@ -0,0 +1,48 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/customers") +@Component +public class Customers { + private Map value = new HashMap<>(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getValue() { + return new HashMap<>(value); + } + public Customer getCustomer(String uid) { + return this.value.get(uid); + } + @Path("/{uid}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getCustomerValue(@PathParam("uid") String uid) { + return getCustomer(uid).getValue(); + } + @Path("/{uid}/address") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getAddressValue(@PathParam("uid") String uid) { + return getCustomer(uid).getAddress(); + } + @Path("/{uid}/organization") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getOrganizationValue(@PathParam("uid") String uid) { + return getCustomer(uid).getOrganization(); + } + @POST + public void addCustomer(@FormParam("org") String org, @FormParam("uid") String uid) { + this.value.put(uid,new Customer(org)); + } + @Path("/{uid}/organization") + @PUT + public void setOrganization(@PathParam("uid") String uid, @FormParam("cid") String cid) { + getCustomer(uid).setOrganization(uid, cid); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Account.java new file mode 100644 index 0000000..4867382 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Account.java @@ -0,0 +1,22 @@ +import java.util.*; + +public class Account { + private Map notifications; + public Map getValue() { + Map temp_nil1 = new HashMap<>(); + temp_nil1.put("notifications",this.getNotifications()); + return temp_nil1; + } + public void updateNotificationsFromMessages(String self, String gid, int mno, List messages, String member) { + this.notifications.put(gid,true); + } + public Map getNotifications() { + return this.notifications; + } + public void hasRead(String aid, String gid) { + this.notifications.remove(gid); + } + public Account(Map notifications) { + this.notifications = notifications; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Accounts.java new file mode 100644 index 0000000..30519de --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Accounts.java @@ -0,0 +1,47 @@ +import java.util.*; +import jakarta.ws.rs.*; +import jakarta.ws.rs.client.*; +import jakarta.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/accounts") +@Component +public class Accounts { + private Map value = new HashMap<>(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getValue() { + return new HashMap<>(this.value); + } + public Account getAccount(String v1) { + return this.value.get(v1); + } + @Path("/{v1}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getAccountValue(@PathParam("v1") String v1) { + return getAccount(v1).getValue(); + } + @Path("/{v1}/notifications") + @POST + public void updateNotificationsFromMessages(@PathParam("v1") String v1, @FormParam("gid") String gid, @FormParam("mno") int mno, @FormParam("messages") List messages, @FormParam("member") String member) { + getAccount(v1).updateNotificationsFromMessages(v1, gid, mno, messages, member); + } + @Path("/{v1}/notifications") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getNotificationsValue(@PathParam("v1") String v1) { + return getAccount(v1).getNotifications(); + } + @Path("/{aid}/notifications") + @DELETE + public void hasRead(@PathParam("aid") String aid, @FormParam("gid") String gid) { + getAccount(aid).hasRead(aid, gid); + } + @POST + public void signUp(@FormParam("aid") String aid) { + this.value.put(aid,new Account(new HashMap<>())); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Group.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Group.java new file mode 100644 index 0000000..6d15fd7 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Group.java @@ -0,0 +1,44 @@ +import java.util.*; + +public class Group { + private Client client = ClientBuilder.newClient(); + private List messages; + private List members; + public Map getValue() { + Map temp_nil0 = new HashMap<>(); + temp_nil0.put("members",this.getMembers()); + temp_nil0.put("messages",this.getMessages()); + return temp_nil0; + } + public List getMessages() { + return this.messages; + } + public void postMessage(String gid, String message) { + this.messages.add(message); + for (int mno = 0; mno < members.size(); mno++) { + String member = getMember(mno); + Form form = new Form(); + form.param("gid", gid.toString()); + form.param("mno", Integer.toString(mno)); + for (String i: this.messages) { + form.param("messages", i.toString()); + } + form.param("member", member.toString()); + Entity entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); + String result = client.target("http://localhost:8080").path("/accounts/"+member+"/notifications").request().post(entity, String.class); + } + } + public String getMember(int mno) { + return this.members.get(mno); + } + public List getMembers() { + return this.members; + } + public void addGroupMember(String gid, String aid) { + this.members.add(aid); + } + public Group(List members, List messages) { + this.members = members; + this.messages = messages; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Groups.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Groups.java new file mode 100644 index 0000000..e6f2b90 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Groups.java @@ -0,0 +1,59 @@ +import java.util.*; +import jakarta.ws.rs.*; +import jakarta.ws.rs.client.*; +import jakarta.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/groups") +@Component +public class Groups { + private Map value = new HashMap<>(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getValue() { + return new HashMap<>(this.value); + } + public Group getGroup(String gid) { + return this.value.get(gid); + } + @Path("/{gid}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getGroupValue(@PathParam("gid") String gid) { + return getGroup(gid).getValue(); + } + @Path("/{gid}/messages") + @Produces(MediaType.APPLICATION_JSON) + @GET + public List getMessagesValue(@PathParam("gid") String gid) { + return getGroup(gid).getMessages(); + } + @Path("/{gid}/messages") + @POST + public void postMessage(@PathParam("gid") String gid, @FormParam("message") String message) { + getGroup(gid).postMessage(gid, message); + } + @Path("/{gid}/members/{mno}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getMemberValue(@PathParam("gid") String gid, @PathParam("mno") int mno) { + return getGroup(gid).getMember(mno); + } + @POST + public void createGroup(@FormParam("gid") String gid) { + this.value.put(gid,new Group(new ArrayList<>(), new ArrayList<>())); + } + @Path("/{gid}/members") + @Produces(MediaType.APPLICATION_JSON) + @GET + public List getMembersValue(@PathParam("gid") String gid) { + return getGroup(gid).getMembers(); + } + @Path("/{gid}/members") + @POST + public void addGroupMember(@PathParam("gid") String gid, @FormParam("aid") String aid) { + getGroup(gid).addGroupMember(gid, aid); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/InventoryManagement/Inventory.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/InventoryManagement/Inventory.java new file mode 100644 index 0000000..de0f8fc --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/InventoryManagement/Inventory.java @@ -0,0 +1,42 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/inventory") +@Component +public class Inventory { + private Map value = new HashMap<>(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getValue() { + return new HashMap<>(value); + } + public InventoryElement getInventoryElement(String itemId) { + return this.value.get(itemId); + } + @Path("/{itemId}/count") + @Produces(MediaType.APPLICATION_JSON) + @GET + public int getCountValue(@PathParam("itemId") String itemId) { + return getInventoryElement(itemId).getCount(); + } + @Path("/{itemId}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getInventoryElementValue(@PathParam("itemId") String itemId) { + return getInventoryElement(itemId).getValue(); + } + @Path("/{itemId}/count") + @POST + public void receiveOrShip(@PathParam("itemId") String itemId, @FormParam("quantity") int quantity) { + getInventoryElement(itemId).receiveOrShip(itemId, quantity); + } + @POST + public void registerItem(@FormParam("itemName") String itemName, @FormParam("quantity") int quantity, @FormParam("itemId") String itemId) { + this.value.put(itemId,new InventoryElement(quantity)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/InventoryManagement/InventoryElement.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/InventoryManagement/InventoryElement.java new file mode 100644 index 0000000..8928640 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/InventoryManagement/InventoryElement.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class InventoryElement { + private int count; + public Map getValue() { + Map temp_nil16 = new HashMap<>(); + temp_nil16.put("count",this.getCount()); + return temp_nil16; + } + public int getCount() { + return this.count; + } + public void receiveOrShip(String itemId, int quantity) { + this.count = (this.value+quantity); + } + public InventoryElement(int count) { + this.count = count; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame/Account.java new file mode 100644 index 0000000..1f2a118 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame/Account.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Account { + private String name; + public Map getValue() { + Map temp_nil19 = new HashMap<>(); + temp_nil19.put("name",this.getName()); + return temp_nil19; + } + public String getName() { + return this.name; + } + public void changeName(String aid, String name) { + this.name = name; + } + public Account(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame/Accounts.java new file mode 100644 index 0000000..e4c2155 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame/Accounts.java @@ -0,0 +1,42 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/accounts") +@Component +public class Accounts { + private Map value = new HashMap<>(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getValue() { + return new HashMap<>(value); + } + public Account getAccount(String aid) { + return this.value.get(aid); + } + @Path("/{aid}/name") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getNameValue(@PathParam("aid") String aid) { + return getAccount(aid).getName(); + } + @Path("/{aid}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getAccountValue(@PathParam("aid") String aid) { + return getAccount(aid).getValue(); + } + @POST + public void signUp(@FormParam("name") String name, @FormParam("aid") String aid) { + this.value.put(aid,new Account(name)); + } + @Path("/{aid}/name") + @PUT + public void changeName(@PathParam("aid") String aid, @FormParam("name") String name) { + getAccount(aid).changeName(aid, name); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame/Room.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame/Room.java new file mode 100644 index 0000000..c5ce166 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame/Room.java @@ -0,0 +1,40 @@ +import java.util.*; +import javax.ws.rs.client.*; + +public class Room { + private Client client = ClientBuilder.newClient(); + private String blue_id; + private String red_id; + public Map getValue() { + Map temp_nil18 = new HashMap<>(); + temp_nil18.put("blue_id",this.getBlue_id()); + temp_nil18.put("red_name",this.getRed_name()); + temp_nil18.put("blue_name",this.getBlue_name()); + temp_nil18.put("red_id",this.getRed_id()); + return temp_nil18; + } + public String getRed_name() { + String name = client.target("http://localhost:8080").path("/accounts/" + red_id + "/name").request().get(String.class); + return name; + } + public String getBlue_id() { + return this.blue_id; + } + public String getBlue_name() { + String name = client.target("http://localhost:8080").path("/accounts/" + blue_id + "/name").request().get(String.class); + return name; + } + public String getRed_id() { + return this.red_id; + } + public void changeRedId(String rid, String redId) { + this.red_id = redId; + } + public void changeBlueId(String rid, String blueId) { + this.blue_id = blueId; + } + public Room(String blue_id, String red_id) { + this.blue_id = blue_id; + this.red_id = red_id; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame/Rooms.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame/Rooms.java new file mode 100644 index 0000000..0124b30 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame/Rooms.java @@ -0,0 +1,65 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/rooms") +@Component +public class Rooms { + private Map value = new HashMap<>(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getValue() { + return new HashMap<>(value); + } + public Room getRoom(String rid) { + return this.value.get(rid); + } + @Path("/{rid}/blue_id") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getBlue_idValue(@PathParam("rid") String rid) { + return getRoom(rid).getBlue_id(); + } + @Path("/{rid}/red_name") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getRed_nameValue(@PathParam("rid") String rid) { + return getRoom(rid).getRed_name(); + } + @Path("/{rid}/blue_name") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getBlue_nameValue(@PathParam("rid") String rid) { + return getRoom(rid).getBlue_name(); + } + @Path("/{rid}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getRoomValue(@PathParam("rid") String rid) { + return getRoom(rid).getValue(); + } + @Path("/{rid}/red_id") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getRed_idValue(@PathParam("rid") String rid) { + return getRoom(rid).getRed_id(); + } + @Path("/{rid}/blue_id") + @PUT + public void changeBlueId(@PathParam("rid") String rid, @FormParam("blueId") String blueId) { + getRoom(rid).changeBlueId(rid, blueId); + } + @Path("/{rid}/red_id") + @PUT + public void changeRedId(@PathParam("rid") String rid, @FormParam("redId") String redId) { + getRoom(rid).changeRedId(rid, redId); + } + @POST + public void createRoom(@FormParam("blueId") String blueId, @FormParam("redId") String redId, @FormParam("rid") String rid) { + this.value.put(rid,new Room(blueId, redId)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Account.java new file mode 100644 index 0000000..ca1ca70 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Account.java @@ -0,0 +1,33 @@ +import java.util.*; + +public class Account { + private int point; + private String name; + public Map getValue() { + Map temp_nil2 = new HashMap<>(); + temp_nil2.put("name",this.getName()); + temp_nil2.put("point",this.getPoint()); + return temp_nil2; + } + public void updatePointFromBattle(String self, String rid, int mno, boolean battle, String id) { + int temp_if0; + if (battle) { + temp_if0 = (this.point+1); + } else { + temp_if0 = this.point; + }this.point = temp_if0; + } + public int getPoint() { + return this.point; + } + public String getName() { + return this.name; + } + public void changeName(String aid, String name) { + this.name = name; + } + public Account(String name, int point) { + this.name = name; + this.point = point; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Accounts.java new file mode 100644 index 0000000..3575712 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Accounts.java @@ -0,0 +1,53 @@ +import java.util.*; +import jakarta.ws.rs.*; +import jakarta.ws.rs.client.*; +import jakarta.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/accounts") +@Component +public class Accounts { + private Map value = new HashMap<>(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getValue() { + return new HashMap<>(this.value); + } + public Account getAccount(String mid) { + return this.value.get(mid); + } + @POST + public void signUp(@FormParam("name") String name, @FormParam("aid") String aid) { + this.value.put(aid,new Account(name, 0)); + } + @Path("/{mid}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getAccountValue(@PathParam("mid") String mid) { + return getAccount(mid).getValue(); + } + @Path("/{mid}/point") + @POST + public void updatePointFromBattle(@PathParam("mid") String mid, @FormParam("rid") String rid, @FormParam("mno") int mno, @FormParam("battle") boolean battle, @FormParam("id") String id) { + getAccount(mid).updatePointFromBattle(mid, rid, mno, battle, id); + } + @Path("/{mid}/point") + @Produces(MediaType.APPLICATION_JSON) + @GET + public int getPointValue(@PathParam("mid") String mid) { + return getAccount(mid).getPoint(); + } + @Path("/{mid}/name") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getNameValue(@PathParam("mid") String mid) { + return getAccount(mid).getName(); + } + @Path("/{aid}/name") + @PUT + public void changeName(@PathParam("aid") String aid, @FormParam("name") String name) { + getAccount(aid).changeName(aid, name); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Member.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Member.java new file mode 100644 index 0000000..03ee021 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Member.java @@ -0,0 +1,22 @@ +import java.util.*; + +public class Member { + private String id; + private Client client = ClientBuilder.newClient(); + public Map getValue() { + Map temp_nil3 = new HashMap<>(); + temp_nil3.put("name",this.getName()); + temp_nil3.put("id",this.getId()); + return temp_nil3; + } + public String getId() { + return this.id; + } + public String getName() { + String name = client.target("http://localhost:8080").path("/accounts/"+id+"/name").request().get(String.class); + return name; + } + public Member(String id) { + this.id = id; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Members.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Members.java new file mode 100644 index 0000000..c1ef7ee --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Members.java @@ -0,0 +1,14 @@ +import java.util.*; + +public class Members { + private List value = new ArrayList<>(); + public List getValue() { + return new ArrayList<>(this.value); + } + public Member getMember(int mno) { + return this.value.get(mno); + } + public void addRoomMember(String rid, String id) { + this.value.add(new Member(id)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Room.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Room.java new file mode 100644 index 0000000..3ccf47d --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Room.java @@ -0,0 +1,35 @@ +import java.util.*; + +public class Room { + private Members members = new Members(); + private Client client = ClientBuilder.newClient(); + private boolean battle; + public Map getValue() { + Map temp_nil4 = new HashMap<>(); + temp_nil4.put("members",this.members.getValue()); + temp_nil4.put("battle",this.getBattle()); + return temp_nil4; + } + public Members getMembers() { + return this.members; + } + public boolean getBattle() { + return this.battle; + } + public void battle(String rid, boolean hasWon) { + this.battle = hasWon; + for (int mno = 0; mno < members.getValue().size(); mno++) { + String id = getMembers().getMember(mno).getId(); + Form form = new Form(); + form.param("rid", rid.toString()); + form.param("mno", Integer.toString(mno)); + form.param("battle", Boolean.toString(this.battle)); + form.param("id", id.toString()); + Entity entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); + String result = client.target("http://localhost:8080").path("/accounts/"+id+"/point").request().post(entity, String.class); + } + } + public Room(boolean battle) { + this.battle = battle; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Rooms.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Rooms.java new file mode 100644 index 0000000..c0b5e43 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Rooms.java @@ -0,0 +1,71 @@ +import java.util.*; +import jakarta.ws.rs.*; +import jakarta.ws.rs.client.*; +import jakarta.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/rooms") +@Component +public class Rooms { + private Map value = new HashMap<>(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getValue() { + return new HashMap<>(this.value); + } + public Room getRoom(String rid) { + return this.value.get(rid); + } + @Path("/{rid}/members") + @Produces(MediaType.APPLICATION_JSON) + @GET + public List getMembersValue(@PathParam("rid") String rid) { + return getRoom(rid).getMembers().getValue(); + } + @Path("/{rid}/members") + @POST + public void addRoomMember(@PathParam("rid") String rid, @FormParam("id") String id) { + getRoom(rid).getMembers().addRoomMember(rid, id); + } + @POST + public void createRoom(@FormParam("rid") String rid) { + this.value.put(rid,new Room(false)); + } + @Path("/{rid}/members/{mno}/id") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getIdValue(@PathParam("rid") String rid, @PathParam("mno") int mno) { + return getRoom(rid).getMembers().getMember(mno).getId(); + } + @Path("/{rid}/members/{mno}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getMemberValue(@PathParam("rid") String rid, @PathParam("mno") int mno) { + return getRoom(rid).getMembers().getMember(mno).getValue(); + } + @Path("/{rid}/battle") + @Produces(MediaType.APPLICATION_JSON) + @GET + public boolean getBattleValue(@PathParam("rid") String rid) { + return getRoom(rid).getBattle(); + } + @Path("/{rid}/battle") + @PUT + public void battle(@PathParam("rid") String rid, @FormParam("hasWon") boolean hasWon) { + getRoom(rid).battle(rid, hasWon); + } + @Path("/{rid}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getRoomValue(@PathParam("rid") String rid) { + return getRoom(rid).getValue(); + } + @Path("/{rid}/members/{mno}/name") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getNameValue(@PathParam("rid") String rid, @PathParam("mno") int mno) { + return getRoom(rid).getMembers().getMember(mno).getName(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PULL-first/History.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PULL-first/History.java new file mode 100644 index 0000000..92776d5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PULL-first/History.java @@ -0,0 +1,22 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/history") +@Component +public class History { + private List value = new ArrayList<>(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public List getValue() { + return value; + } + @POST + public void updateFromPayment(@FormParam("payment") int payment) { + this.value.add(0, payment); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PULL-first/Payment.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PULL-first/Payment.java new file mode 100644 index 0000000..a694ab6 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PULL-first/Payment.java @@ -0,0 +1,27 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/payment") +@Component +public class Payment { + private int value = 0; + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public int getValue() { + return value; + } + @PUT + public void purchase(@FormParam("x") int x) throws JsonProcessingException { + Form form = new Form(); + form.param("payment", Integer.toString(this.value)); + Entity entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); + String result = client.target("http://localhost:8080").path("/history").request().post(entity, String.class); + this.value = x; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PULL-first/Points.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PULL-first/Points.java new file mode 100644 index 0000000..f7ac799 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PULL-first/Points.java @@ -0,0 +1,19 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/points") +@Component +public class Points { + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public int getValue() { + int payment = client.target("http://localhost:8080").path("/payment").request().get(int.class); + return (int)Math.floor((payment*0.05)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PULL-first/Total.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PULL-first/Total.java new file mode 100644 index 0000000..87b8845 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PULL-first/Total.java @@ -0,0 +1,23 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/total") +@Component +public class Total { + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public int getValue() { + List history = client.target("http://localhost:8080").path("/history").request().get(ArrayList.class); + Integer temp_sum1 = 0; + for (Integer x: history) { + temp_sum1 += x; + } + return temp_sum1; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PUSH-first/History.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PUSH-first/History.java new file mode 100644 index 0000000..e6c5c7f --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PUSH-first/History.java @@ -0,0 +1,29 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/history") +@Component +public class History { + private List value = new ArrayList<>(); + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public List getValue() { + return value; + } + @POST + public void updateFromPayment(@FormParam("payment") double payment) throws JsonProcessingException { + this.value.add(0, payment); + Form form = new Form(); + for (Double i: this.value) { + form.param("history", i.toString()); + } + Entity entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); + String result = client.target("http://localhost:8080").path("/total").request().put(entity, String.class); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PUSH-first/Payment.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PUSH-first/Payment.java new file mode 100644 index 0000000..5d65395 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PUSH-first/Payment.java @@ -0,0 +1,31 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/payment") +@Component +public class Payment { + private double value = 0.0; + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public double getValue() { + return value; + } + @PUT + public void purchase(@FormParam("x") double x) throws JsonProcessingException { + Form form = new Form(); + form.param("payment", Double.toString(this.value)); + Entity entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); + String result = client.target("http://localhost:8080").path("/points").request().put(entity, String.class); + form = new Form(); + form.param("payment", Double.toString(this.value)); + entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); + result = client.target("http://localhost:8080").path("/history").request().post(entity, String.class); + this.value = x; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PUSH-first/Points.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PUSH-first/Points.java new file mode 100644 index 0000000..7071bf0 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PUSH-first/Points.java @@ -0,0 +1,22 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/points") +@Component +public class Points { + private int value = 0; + @Produces(MediaType.APPLICATION_JSON) + @GET + public int getValue() { + return value; + } + @PUT + public void updateFromPayment(@FormParam("payment") double payment) { + this.value = (int)Math.floor((payment*0.05)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PUSH-first/Total.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PUSH-first/Total.java new file mode 100644 index 0000000..0fdd957 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/POS/PUSH-first/Total.java @@ -0,0 +1,26 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/total") +@Component +public class Total { + private int value = 0; + @Produces(MediaType.APPLICATION_JSON) + @GET + public int getValue() { + return value; + } + @PUT + public void updateFromHistory(@FormParam("history") List history) { + Integer temp_sum1 = 0; + for (Integer x: history) { + temp_sum1 += x; + } + this.value = temp_sum1; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/SimpleTwitter/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/SimpleTwitter/Account.java new file mode 100644 index 0000000..fe3d260 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/SimpleTwitter/Account.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Account { + private List tweets; + public Map getValue() { + Map temp_nil26 = new HashMap<>(); + temp_nil26.put("tweets",this.getTweets()); + return temp_nil26; + } + public List getTweets() { + return this.tweets; + } + public void tweet(String accountId, String contents) { + this.tweets.add(contents); + } + public Account(List tweets) { + this.tweets = tweets; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/SimpleTwitter/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/SimpleTwitter/Accounts.java new file mode 100644 index 0000000..8797c5d --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/SimpleTwitter/Accounts.java @@ -0,0 +1,42 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/accounts") +@Component +public class Accounts { + private Map value = new HashMap<>(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getValue() { + return new HashMap<>(value); + } + public Account getAccount(String accountId) { + return this.value.get(accountId); + } + @Path("/{accountId}/tweets") + @Produces(MediaType.APPLICATION_JSON) + @GET + public List getTweetsValue(@PathParam("accountId") String accountId) { + return getAccount(accountId).getTweets(); + } + @Path("/{accountId}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getAccountValue(@PathParam("accountId") String accountId) { + return getAccount(accountId).getValue(); + } + @POST + public void signUp(@FormParam("name") String name, @FormParam("accountId") String accountId) { + this.value.put(accountId,new Account(new ArrayList<>())); + } + @Path("/{accountId}/tweets") + @POST + public void tweet(@PathParam("accountId") String accountId, @FormParam("contents") String contents) { + getAccount(accountId).tweet(accountId, contents); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/VotingSystem/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/VotingSystem/Account.java new file mode 100644 index 0000000..5bdc922 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/VotingSystem/Account.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Account { + private String vote; + public Map getValue() { + Map temp_nil7 = new HashMap<>(); + temp_nil7.put("vote",this.getVote()); + return temp_nil7; + } + public String getVote() { + return this.vote; + } + public void cast(String aid, String v) { + this.vote = v; + } + public Account(String vote) { + this.vote = vote; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/VotingSystem/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/VotingSystem/Accounts.java new file mode 100644 index 0000000..ab6b793 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/VotingSystem/Accounts.java @@ -0,0 +1,42 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/accounts") +@Component +public class Accounts { + private Map value = new HashMap<>(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getValue() { + return new HashMap<>(value); + } + public Account getAccount(String aid) { + return this.value.get(aid); + } + @Path("/{aid}/vote") + @Produces(MediaType.APPLICATION_JSON) + @GET + public String getVoteValue(@PathParam("aid") String aid) { + return getAccount(aid).getVote(); + } + @Path("/{aid}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getAccountValue(@PathParam("aid") String aid) { + return getAccount(aid).getValue(); + } + @Path("/{aid}/vote") + @PUT + public void cast(@PathParam("aid") String aid, @FormParam("v") String v) { + getAccount(aid).cast(aid, v); + } + @POST + public void signUp(@FormParam("name") String name, @FormParam("aid") String aid) { + this.value.put(aid,new Account(null)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/VotingSystem/Counts.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/VotingSystem/Counts.java new file mode 100644 index 0000000..06026ed --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/VotingSystem/Counts.java @@ -0,0 +1,27 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/counts") +@Component +public class Counts { + private Map value = new HashMap<>(); + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getValue() { + Map v0 = new HashMap<>(); + Map> accounts_json = client.target("http://localhost:8080").path("/accounts").request().get(HashMap.class); + Map> accounts = new HashMap<>(); + accounts = accounts_json; + for (String aid: accounts.keySet()) { + String vote = client.target("http://localhost:8080").path("/accounts/"+aid+"/vote").request().get(String.class); + v0.put(aid,vote); + } + return v0; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PULL-first/Highest.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PULL-first/Highest.java new file mode 100644 index 0000000..0b95991 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PULL-first/Highest.java @@ -0,0 +1,32 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/highest") +@Component +public class Highest { + private double value = 0.0; + @Produces(MediaType.APPLICATION_JSON) + @GET + public double getValue() { + return value; + } + @POST + public void updateFromTemp_f(@FormParam("temp_f") double temp_f) { + double temp_if2; + if ((temp_f>=this.value)) { + temp_if2 = temp_f; + } else { + temp_if2 = this.value; + } + this.value = temp_if2; + } + @PUT + public void reset(@FormParam("v") double v) { + this.value = v; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PULL-first/Temp_c.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PULL-first/Temp_c.java new file mode 100644 index 0000000..3492c58 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PULL-first/Temp_c.java @@ -0,0 +1,19 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/temp_c") +@Component +public class Temp_c { + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public double getValue() { + double temp_f = client.target("http://localhost:8080").path("/temp_f").request().get(double.class); + return ((temp_f-32)/1.8); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PULL-first/Temp_f.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PULL-first/Temp_f.java new file mode 100644 index 0000000..a23f614 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PULL-first/Temp_f.java @@ -0,0 +1,27 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/temp_f") +@Component +public class Temp_f { + private double value = 0.0; + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public double getValue() { + return value; + } + @PUT + public void observe(@FormParam("x") double x) throws JsonProcessingException { + Form form = new Form(); + form.param("temp_f", Double.toString(this.value)); + Entity entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); + String result = client.target("http://localhost:8080").path("/highest").request().post(entity, String.class); + this.value = x; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PUSH-first/Highest.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PUSH-first/Highest.java new file mode 100644 index 0000000..7196436 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PUSH-first/Highest.java @@ -0,0 +1,32 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/highest") +@Component +public class Highest { + private double value = 0.0; + @Produces(MediaType.APPLICATION_JSON) + @GET + public double getValue() { + return value; + } + @POST + public void updateFromTemp_f(@FormParam("temp_f") double temp_f) { + double temp_if3; + if ((temp_f>=this.value)) { + temp_if3 = temp_f; + } else { + temp_if3 = this.value; + } + this.value = temp_if3; + } + @PUT + public void reset(@FormParam("v") double v) { + this.value = v; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PUSH-first/Temp_c.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PUSH-first/Temp_c.java new file mode 100644 index 0000000..ee3d10a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PUSH-first/Temp_c.java @@ -0,0 +1,22 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/temp_c") +@Component +public class Temp_c { + private double value = 0.0; + @Produces(MediaType.APPLICATION_JSON) + @GET + public double getValue() { + return value; + } + @PUT + public void updateFromTemp_f(@FormParam("temp_f") double temp_f) { + this.value = ((temp_f-32)/1.8); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PUSH-first/Temp_f.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PUSH-first/Temp_f.java new file mode 100644 index 0000000..a589b35 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/WeatherObservationSystem/PUSH-first/Temp_f.java @@ -0,0 +1,31 @@ +import java.util.*; +import javax.ws.rs.*; +import javax.ws.rs.client.*; +import javax.ws.rs.core.*; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Path("/temp_f") +@Component +public class Temp_f { + private double value = 0.0; + private Client client = ClientBuilder.newClient(); + @Produces(MediaType.APPLICATION_JSON) + @GET + public double getValue() { + return value; + } + @PUT + public void observe(@FormParam("x") double x) throws JsonProcessingException { + Form form = new Form(); + form.param("temp_f", Double.toString(this.value)); + Entity entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); + String result = client.target("http://localhost:8080").path("/temp_c").request().put(entity, String.class); + form = new Form(); + form.param("temp_f", Double.toString(this.value)); + entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); + result = client.target("http://localhost:8080").path("/highest").request().post(entity, String.class); + this.value = x; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/Accounts/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/Accounts/Account.java new file mode 100644 index 0000000..40c6dfb --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/Accounts/Account.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Account { + private String name; + public Map getValue() { + Map temp_nil0 = new HashMap<>(); + temp_nil0.put("name",this.getName()); + return temp_nil0; + } + public String getName() { + return this.name; + } + public void changeName(int uid, String name) { + this.name = name; + } + public Account(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/Accounts/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/Accounts/Accounts.java new file mode 100644 index 0000000..9053c32 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/Accounts/Accounts.java @@ -0,0 +1,14 @@ +import java.util.*; + +public class Accounts { + private List value = new ArrayList<>(); + public List getValue() { + return new ArrayList<>(value); + } + public Account getAccount(int uid) { + return this.value.get(uid); + } + public void signup(String name) { + this.value.add(new Account(name)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/Accounts/Main.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/Accounts/Main.java new file mode 100644 index 0000000..1340414 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/Accounts/Main.java @@ -0,0 +1,23 @@ +import java.util.*; + +public class Main { + private Accounts accounts; + public Main() { + accounts = new Accounts(); + } + public String getName(int uid) { + return this.accounts.getAccount(uid).getName(); + } + public void changeName(int uid, String name) { + this.accounts.getAccount(uid).changeName(uid, name); + } + public Map getAccount(int uid) { + return this.accounts.getAccount(uid).getValue(); + } + public List getAccounts() { + return this.accounts.getValue(); + } + public void signup(String name) { + this.accounts.signup(name); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Clock.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Clock.java new file mode 100644 index 0000000..a8b488a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Clock.java @@ -0,0 +1,29 @@ +import java.util.*; + +public class Clock { + private Hour hour; + private Hour_ang hour_ang; + private Min min; + private Min_ang min_ang; + public Clock() { + hour = new Hour(); + hour_ang = new Hour_ang(hour); + min = new Min(hour); + min_ang = new Min_ang(min); + } + public double getHour() { + return this.hour.getValue(); + } + public double getHour_ang() { + return this.hour_ang.getValue(); + } + public double getMin() { + return this.min.getValue(); + } + public void tick() { + this.min.tick(); + } + public double getMin_ang() { + return this.min_ang.getValue(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Hour.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Hour.java new file mode 100644 index 0000000..0e389ac --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Hour.java @@ -0,0 +1,17 @@ +import java.util.*; + +public class Hour { + private double value = 0.0; + public double getValue() { + return value; + } + public void updateFromMin(double min) { + double temp_if1; + if ((min==0)) { + temp_if1 = ((this.value+1)%24); + } else { + temp_if1 = this.value; + } + this.value = temp_if1; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Hour_ang.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Hour_ang.java new file mode 100644 index 0000000..2758d12 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Hour_ang.java @@ -0,0 +1,11 @@ +import java.util.*; + +public class Hour_ang { + private Hour hour; + public double getValue() { + return ((this.hour.getValue()/6)*Math.PI); + } + public Hour_ang(Hour hour) { + this.hour = hour; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Min.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Min.java new file mode 100644 index 0000000..f0d82da --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Min.java @@ -0,0 +1,16 @@ +import java.util.*; + +public class Min { + private double value = 0.0; + private Hour hour; + public double getValue() { + return value; + } + public void tick() { + this.value = ((this.value+1)%60); + this.hour.updateFromMin(value); + } + public Min(Hour hour) { + this.hour = hour; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Min_ang.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Min_ang.java new file mode 100644 index 0000000..d91aefa --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PULL-first/Min_ang.java @@ -0,0 +1,11 @@ +import java.util.*; + +public class Min_ang { + private Min min; + public double getValue() { + return ((this.min.getValue()/30)*Math.PI); + } + public Min_ang(Min min) { + this.min = min; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Clock.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Clock.java new file mode 100644 index 0000000..2710bd1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Clock.java @@ -0,0 +1,29 @@ +import java.util.*; + +public class Clock { + private Hour_ang hour_ang; + private Min_ang min_ang; + private Hour hour; + private Min min; + public Clock() { + hour_ang = new Hour_ang(); + min_ang = new Min_ang(); + hour = new Hour(hour_ang); + min = new Min(min_ang,hour); + } + public double getHour_ang() { + return this.hour_ang.getValue(); + } + public double getMin_ang() { + return this.min_ang.getValue(); + } + public int getHour() { + return this.hour.getValue(); + } + public int getMin() { + return this.min.getValue(); + } + public void tick() { + this.min.tick(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Hour.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Hour.java new file mode 100644 index 0000000..a305b95 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Hour.java @@ -0,0 +1,22 @@ +import java.util.*; + +public class Hour { + private int value = 0; + private Hour_ang hour_ang; + public int getValue() { + return value; + } + public void updateFromMin(int min) { + int temp_if0; + if ((min==0)) { + temp_if0 = ((this.value+1)%24); + } else { + temp_if0 = this.value; + } + this.value = temp_if0; + this.hour_ang.updateFromHour(value); + } + public Hour(Hour_ang hour_ang) { + this.hour_ang = hour_ang; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Hour_ang.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Hour_ang.java new file mode 100644 index 0000000..8463ad7 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Hour_ang.java @@ -0,0 +1,11 @@ +import java.util.*; + +public class Hour_ang { + private double value = 0.0; + public double getValue() { + return value; + } + public void updateFromHour(int hour) { + this.value = ((hour/6)*Math.PI); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Min.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Min.java new file mode 100644 index 0000000..c0e4de0 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Min.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Min { + private int value = 0; + private Min_ang min_ang; + private Hour hour; + public int getValue() { + return value; + } + public void tick() { + this.value = ((this.value+1)%60); + this.min_ang.updateFromMin(value); + this.hour.updateFromMin(value); + } + public Min(Min_ang min_ang, Hour hour) { + this.min_ang = min_ang; + this.hour = hour; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Min_ang.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Min_ang.java new file mode 100644 index 0000000..756097f --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/Clock/PUSH-first/Min_ang.java @@ -0,0 +1,11 @@ +import java.util.*; + +public class Min_ang { + private double value = 0.0; + public double getValue() { + return value; + } + public void updateFromMin(int min) { + this.value = ((min/30)*Math.PI); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/Companies.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/Companies.java new file mode 100644 index 0000000..148543f --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/Companies.java @@ -0,0 +1,14 @@ +import java.util.*; + +public class Companies { + private Map value = new HashMap<>(); + public Map getValue() { + return new HashMap<>(value); + } + public Company getCompany(String cid) { + return this.value.get(cid); + } + public void addCampany(String address, String cid) { + this.value.put(cid,new Company(address)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/Company.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/Company.java new file mode 100644 index 0000000..fd0eaba --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/Company.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Company { + private String address; + public Map getValue() { + Map temp_nil6 = new HashMap<>(); + temp_nil6.put("address",this.getAddress()); + return temp_nil6; + } + public String getAddress() { + return this.address; + } + public void setAddress(String cid, String add) { + this.address = add; + } + public Company(String address) { + this.address = address; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/Customer.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/Customer.java new file mode 100644 index 0000000..4c19192 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/Customer.java @@ -0,0 +1,28 @@ +import java.util.*; + +public class Customer { + private String organization; + private Company company; + private Companies companies; + public Map getValue() { + Map temp_nil7 = new HashMap<>(); + temp_nil7.put("address",this.getAddress()); + temp_nil7.put("organization",this.getOrganization()); + return temp_nil7; + } + public String getOrganization() { + return this.organization; + } + public String getAddress() { + return this.company.getAddress(); + } + public void setOrganization(String uid, String cid) { + this.organization = cid; + this.company = this.companies.getCompany(this.organization); + } + public Customer(String organization, Companies companies) { + this.organization = organization; + this.companies = companies; + this.company = this.companies.getCompany(this.organization); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/CustomerManagement.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/CustomerManagement.java new file mode 100644 index 0000000..a919176 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/CustomerManagement.java @@ -0,0 +1,43 @@ +import java.util.*; + +public class CustomerManagement { + private Companies companies; + private Customers customers; + public CustomerManagement() { + companies = new Companies(); + customers = new Customers(companies); + } + public Map getCompanies() { + return this.companies.getValue(); + } + public void addCampany(String address, String cid) { + this.companies.addCampany(address, cid); + } + public String getAddress(String cid) { + return this.companies.getCompany(cid).getAddress(); + } + public void setAddress(String cid, String add) { + this.companies.getCompany(cid).setAddress(cid, add); + } + public String getOrganization(String uid) { + return this.customers.getCustomer(uid).getOrganization(); + } + public void setOrganization(String uid, String cid) { + this.customers.getCustomer(uid).setOrganization(uid, cid); + } + public String getAddress(String uid) { + return this.customers.getCustomer(uid).getAddress(); + } + public Map getCompany(String cid) { + return this.companies.getCompany(cid).getValue(); + } + public Map getCustomers() { + return this.customers.getValue(); + } + public void addCustomer(String org, String uid) { + this.customers.addCustomer(org, uid); + } + public Map getCustomer(String uid) { + return this.customers.getCustomer(uid).getValue(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/Customers.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/Customers.java new file mode 100644 index 0000000..04725d7 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/CustomerManagement/Customers.java @@ -0,0 +1,18 @@ +import java.util.*; + +public class Customers { + private Map value = new HashMap<>(); + private Companies companies; + public Map getValue() { + return new HashMap<>(value); + } + public Customer getCustomer(String uid) { + return this.value.get(uid); + } + public void addCustomer(String org, String uid) { + this.value.put(uid,new Customer(org, companies)); + } + public Customers(Companies companies) { + this.companies = companies; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/Account.java new file mode 100644 index 0000000..10f53f1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/Account.java @@ -0,0 +1,22 @@ +import java.util.*; + +public class Account { + private Map notifications; + public Map getValue() { + Map temp_nil17 = new HashMap<>(); + temp_nil17.put("notifications",this.getNotifications()); + return temp_nil17; + } + public Map getNotifications() { + return new HashMap<>(notifications); + } + public void updateNotificationsFromMessages(String self, String gid, int mno, List messages, String member) { + this.notifications.put(gid,true); + } + public void hasRead(String aid, String gid) { + this.notifications.remove(gid); + } + public Account(Map notifications) { + this.notifications = notifications; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/Accounts.java new file mode 100644 index 0000000..2e7c4e3 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/Accounts.java @@ -0,0 +1,14 @@ +import java.util.*; + +public class Accounts { + private Map value = new HashMap<>(); + public Map getValue() { + return new HashMap<>(value); + } + public Account getAccount(String v1) { + return this.value.get(v1); + } + public void signUp(String aid) { + this.value.put(aid,new Account(new HashMap<>())); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/Group.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/Group.java new file mode 100644 index 0000000..faa7d19 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/Group.java @@ -0,0 +1,39 @@ +import java.util.*; + +public class Group { + private List messages; + private Account account; + private Accounts accounts; + private List members; + public Map getValue() { + Map temp_nil16 = new HashMap<>(); + temp_nil16.put("members",this.getMembers()); + temp_nil16.put("messages",this.getMessages()); + return temp_nil16; + } + public List getMessages() { + return this.messages; + } + public List getMembers() { + return this.members; + } + public String getMember(int mno) { + return this.members.get(mno); + } + public void postMessage(String gid, String message) { + this.messages.add(message); + for (int mno = 0; mno < this.members.size(); mno++) { + String member = getMember(mno); + this.account = accounts.getAccount(member); + this.account.updateNotificationsFromMessages(member, gid, mno, messages, member); + } + } + public void addGroupMember(String gid, String aid) { + this.members.add(aid); + } + public Group(List messages, Accounts accounts, List members) { + this.messages = messages; + this.accounts = accounts; + this.members = members; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/GroupChat.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/GroupChat.java new file mode 100644 index 0000000..6ee5abf --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/GroupChat.java @@ -0,0 +1,49 @@ +import java.util.*; + +public class GroupChat { + private Accounts accounts; + private Groups groups; + public GroupChat() { + accounts = new Accounts(); + groups = new Groups(accounts); + } + public Map getGroup(String gid) { + return this.groups.getGroup(gid).getValue(); + } + public Map getAccount(String v1) { + return this.accounts.getAccount(v1).getValue(); + } + public List getMessages(String gid) { + return this.groups.getGroup(gid).getMessages(); + } + public void postMessage(String gid, String message) { + this.groups.getGroup(gid).postMessage(gid, message); + } + public List getMembers(String gid) { + return this.groups.getGroup(gid).getMembers(); + } + public void addGroupMember(String gid, String aid) { + this.groups.getGroup(gid).addGroupMember(gid, aid); + } + public Map getNotifications(String v1) { + return this.accounts.getAccount(v1).getNotifications(); + } + public void hasRead(String aid, String gid) { + this.accounts.getAccount(aid).hasRead(aid, gid); + } + public String getMember(String gid, int mno) { + return this.groups.getGroup(gid).getMember(mno); + } + public Map getAccounts() { + return this.accounts.getValue(); + } + public void signUp(String aid) { + this.accounts.signUp(aid); + } + public Map getGroups() { + return this.groups.getValue(); + } + public void createGroup(String gid) { + this.groups.createGroup(gid); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/Groups.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/Groups.java new file mode 100644 index 0000000..ada656a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/GroupChat/Groups.java @@ -0,0 +1,18 @@ +import java.util.*; + +public class Groups { + private Map value = new HashMap<>(); + private Accounts accounts; + public Map getValue() { + return new HashMap<>(value); + } + public Group getGroup(String gid) { + return this.value.get(gid); + } + public void createGroup(String gid) { + this.value.put(gid,new Group(new ArrayList<>(), accounts, new ArrayList<>())); + } + public Groups(Accounts accounts) { + this.accounts = accounts; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/InventoryManagement/Inventory.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/InventoryManagement/Inventory.java new file mode 100644 index 0000000..da9dc38 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/InventoryManagement/Inventory.java @@ -0,0 +1,14 @@ +import java.util.*; + +public class Inventory { + private Map value = new HashMap<>(); + public Map getValue() { + return new HashMap<>(value); + } + public InventoryElement getInventoryElement(String itemId) { + return this.value.get(itemId); + } + public void registerItem(String itemName, int quantity, String itemId) { + this.value.put(itemId,new InventoryElement(quantity)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/InventoryManagement/InventoryElement.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/InventoryManagement/InventoryElement.java new file mode 100644 index 0000000..366444a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/InventoryManagement/InventoryElement.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class InventoryElement { + private int count; + public Map getValue() { + Map temp_nil17 = new HashMap<>(); + temp_nil17.put("count",this.getCount()); + return temp_nil17; + } + public int getCount() { + return this.count; + } + public void receiveOrShip(String itemId, int quantity) { + this.count = (this.value+quantity); + } + public InventoryElement(int count) { + this.count = count; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/InventoryManagement/InventoryManagement.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/InventoryManagement/InventoryManagement.java new file mode 100644 index 0000000..3f3d2fc --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/InventoryManagement/InventoryManagement.java @@ -0,0 +1,23 @@ +import java.util.*; + +public class InventoryManagement { + private Inventory inventory; + public InventoryManagement() { + inventory = new Inventory(); + } + public Map getInventory() { + return this.inventory.getValue(); + } + public void registerItem(String itemName, int quantity, String itemId) { + this.inventory.registerItem(itemName, quantity, itemId); + } + public int getCount(String itemId) { + return this.inventory.getInventoryElement(itemId).getCount(); + } + public void receiveOrShip(String itemId, int quantity) { + this.inventory.getInventoryElement(itemId).receiveOrShip(itemId, quantity); + } + public Map getInventoryElement(String itemId) { + return this.inventory.getInventoryElement(itemId).getValue(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/Account.java new file mode 100644 index 0000000..5838e95 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/Account.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Account { + private String name; + public Map getValue() { + Map temp_nil23 = new HashMap<>(); + temp_nil23.put("name",this.getName()); + return temp_nil23; + } + public String getName() { + return this.name; + } + public void changeName(String aid, String name) { + this.name = name; + } + public Account(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/Accounts.java new file mode 100644 index 0000000..feb415f --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/Accounts.java @@ -0,0 +1,14 @@ +import java.util.*; + +public class Accounts { + private Map value = new HashMap<>(); + public Map getValue() { + return new HashMap<>(value); + } + public Account getAccount(String aid) { + return this.value.get(aid); + } + public void signUp(String name, String aid) { + this.value.put(aid,new Account(name)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/OnlineBattleGame.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/OnlineBattleGame.java new file mode 100644 index 0000000..5339f4c --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/OnlineBattleGame.java @@ -0,0 +1,52 @@ +import java.util.*; + +public class OnlineBattleGame { + private Accounts accounts; + private Rooms rooms; + public OnlineBattleGame() { + accounts = new Accounts(); + rooms = new Rooms(accounts); + } + public String getBlue_id(String rid) { + return this.rooms.getRoom(rid).getBlue_id(); + } + public void changeBlueId(String rid, String blueId) { + this.rooms.getRoom(rid).changeBlueId(rid, blueId); + } + public Map getAccount(String aid) { + return this.accounts.getAccount(aid).getValue(); + } + public String getName(String aid) { + return this.accounts.getAccount(aid).getName(); + } + public void changeName(String aid, String name) { + this.accounts.getAccount(aid).changeName(aid, name); + } + public String getBlue_name(String rid) { + return this.rooms.getRoom(rid).getBlue_name(); + } + public Map getRoom(String rid) { + return this.rooms.getRoom(rid).getValue(); + } + public String getRed_id(String rid) { + return this.rooms.getRoom(rid).getRed_id(); + } + public void changeRedId(String rid, String redId) { + this.rooms.getRoom(rid).changeRedId(rid, redId); + } + public Map getAccounts() { + return this.accounts.getValue(); + } + public void signUp(String name, String aid) { + this.accounts.signUp(name, aid); + } + public Map getRooms() { + return this.rooms.getValue(); + } + public void createRoom(String blueId, String redId, String rid) { + this.rooms.createRoom(blueId, redId, rid); + } + public String getRed_name(String rid) { + return this.rooms.getRoom(rid).getRed_name(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/Room.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/Room.java new file mode 100644 index 0000000..399506e --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/Room.java @@ -0,0 +1,43 @@ +import java.util.*; + +public class Room { + private String blue_id; + private Account account; + private Accounts accounts; + private String red_id; + public Map getValue() { + Map temp_nil22 = new HashMap<>(); + temp_nil22.put("blue_id",this.getBlue_id()); + temp_nil22.put("red_name",this.getRed_name()); + temp_nil22.put("blue_name",this.getBlue_name()); + temp_nil22.put("red_id",this.getRed_id()); + return temp_nil22; + } + public String getBlue_id() { + return this.blue_id; + } + public String getBlue_name() { + return this.account.getName(); + } + public String getRed_id() { + return this.red_id; + } + public String getRed_name() { + return this.account.getName(); + } + public void changeRedId(String rid, String redId) { + this.red_id = redId; + this.account = this.accounts.getAccount(this.red_id); + } + public void changeBlueId(String rid, String blueId) { + this.blue_id = blueId; + this.account = this.accounts.getAccount(this.blue_id); + } + public Room(String blue_id, Accounts accounts, String red_id) { + this.blue_id = blue_id; + this.accounts = accounts; + this.red_id = red_id; + this.account = this.accounts.getAccount(this.blue_id); + this.account = this.accounts.getAccount(this.red_id); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/Rooms.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/Rooms.java new file mode 100644 index 0000000..2016c96 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PULL-first/Rooms.java @@ -0,0 +1,18 @@ +import java.util.*; + +public class Rooms { + private Map value = new HashMap<>(); + private Accounts accounts; + public Map getValue() { + return new HashMap<>(value); + } + public Room getRoom(String rid) { + return this.value.get(rid); + } + public void createRoom(String blueId, String redId, String rid) { + this.value.put(rid,new Room(blueId, accounts, redId)); + } + public Rooms(Accounts accounts) { + this.accounts = accounts; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/Account.java new file mode 100644 index 0000000..63f2dd3 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/Account.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Account { + private String name; + public Map getValue() { + Map temp_nil21 = new HashMap<>(); + temp_nil21.put("name",this.getName()); + return temp_nil21; + } + public String getName() { + return this.name; + } + public void changeName(String aid, String name) { + this.name = name; + } + public Account(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/Accounts.java new file mode 100644 index 0000000..feb415f --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/Accounts.java @@ -0,0 +1,14 @@ +import java.util.*; + +public class Accounts { + private Map value = new HashMap<>(); + public Map getValue() { + return new HashMap<>(value); + } + public Account getAccount(String aid) { + return this.value.get(aid); + } + public void signUp(String name, String aid) { + this.value.put(aid,new Account(name)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/OnlineBattleGame.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/OnlineBattleGame.java new file mode 100644 index 0000000..02e2ca7 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/OnlineBattleGame.java @@ -0,0 +1,52 @@ +import java.util.*; + +public class OnlineBattleGame { + private Accounts accounts; + private Rooms rooms; + public OnlineBattleGame() { + accounts = new Accounts(); + rooms = new Rooms(accounts); + } + public Map getAccount(String aid) { + return this.accounts.getAccount(aid).getValue(); + } + public String getBlue_name(String rid) { + return this.rooms.getRoom(rid).getBlue_name(); + } + public String getBlue_id(String rid) { + return this.rooms.getRoom(rid).getBlue_id(); + } + public void changeBlueId(String rid, String blueId) { + this.rooms.getRoom(rid).changeBlueId(rid, blueId); + } + public String getRed_name(String rid) { + return this.rooms.getRoom(rid).getRed_name(); + } + public String getName(String aid) { + return this.accounts.getAccount(aid).getName(); + } + public void changeName(String aid, String name) { + this.accounts.getAccount(aid).changeName(aid, name); + } + public Map getRoom(String rid) { + return this.rooms.getRoom(rid).getValue(); + } + public String getRed_id(String rid) { + return this.rooms.getRoom(rid).getRed_id(); + } + public void changeRedId(String rid, String redId) { + this.rooms.getRoom(rid).changeRedId(rid, redId); + } + public Map getAccounts() { + return this.accounts.getValue(); + } + public void signUp(String name, String aid) { + this.accounts.signUp(name, aid); + } + public Map getRooms() { + return this.rooms.getValue(); + } + public void createRoom(String blueId, String redId, String rid) { + this.rooms.createRoom(blueId, redId, rid); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/Room.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/Room.java new file mode 100644 index 0000000..251aacf --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/Room.java @@ -0,0 +1,53 @@ +import java.util.*; + +public class Room { + private Account account; + private Accounts accounts; + private String blue_id; + private String red_id; + public Map getValue() { + Map temp_nil20 = new HashMap<>(); + temp_nil20.put("blue_id",this.getBlue_id()); + temp_nil20.put("red_name",this.getRed_name()); + temp_nil20.put("blue_name",this.getBlue_name()); + temp_nil20.put("red_id",this.getRed_id()); + return temp_nil20; + } + public String getBlue_name() { + return name; + } + public String getBlue_id() { + return this.blue_id; + } + public String getRed_name() { + return name; + } + public String getRed_id() { + return this.red_id; + } + public void updateBlue_nameFromBlue_id(String self, String rid, String blue_id) { + this.blue_name = name; + this.blue_id = blue_id; + } + public void updateRed_nameFromRed_id(String self, String rid, String red_id) { + this.red_name = name; + this.red_id = red_id; + } + public void changeRedId(String rid, String redId) { + this.red_id = redId; + this.account = this.accounts.getAccount(this.red_id); + this.updateRed_nameFromRed_id(rid, rid, red_id); + } + public void changeBlueId(String rid, String blueId) { + this.blue_id = blueId; + this.account = this.accounts.getAccount(this.blue_id); + this.updateBlue_nameFromBlue_id(rid, rid, blue_id); + } + public Room(Accounts accounts, String blue_id, String red_id) { + this.accounts = accounts; + this.blue_id = blue_id; + this.red_id = red_id; + this.account = this.accounts.getAccount(this.blue_id); + this.account = this.accounts.getAccount(this.red_id); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/Rooms.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/Rooms.java new file mode 100644 index 0000000..f674087 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame/PUSH-first/Rooms.java @@ -0,0 +1,18 @@ +import java.util.*; + +public class Rooms { + private Map value = new HashMap<>(); + private Accounts accounts; + public Map getValue() { + return new HashMap<>(value); + } + public Room getRoom(String rid) { + return this.value.get(rid); + } + public void createRoom(String blueId, String redId, String rid) { + this.value.put(rid,new Room(accounts, blueId, redId)); + } + public Rooms(Accounts accounts) { + this.accounts = accounts; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Account.java new file mode 100644 index 0000000..f95e5e6 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Account.java @@ -0,0 +1,33 @@ +import java.util.*; + +public class Account { + private String name; + private int point; + public Map getValue() { + Map temp_nil1 = new HashMap<>(); + temp_nil1.put("name",this.getName()); + temp_nil1.put("point",this.getPoint()); + return temp_nil1; + } + public String getName() { + return this.name; + } + public int getPoint() { + return point; + } + public void updatePointFromBattle(String self, String rid, int mno, boolean battle, String id) { + int temp_if0; + if (battle) { + temp_if0 = (this.point+1); + } else { + temp_if0 = this.point; + }this.point = temp_if0; + } + public void changeName(String aid, String name) { + this.name = name; + } + public Account(String name, int point) { + this.name = name; + this.point = point; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Accounts.java new file mode 100644 index 0000000..6d92c89 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Accounts.java @@ -0,0 +1,14 @@ +import java.util.*; + +public class Accounts { + private Map value = new HashMap<>(); + public Map getValue() { + return new HashMap<>(value); + } + public Account getAccount(String mid) { + return this.value.get(mid); + } + public void signUp(String name, String aid) { + this.value.put(aid,new Account(name, 0)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Member.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Member.java new file mode 100644 index 0000000..aac4c47 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Member.java @@ -0,0 +1,23 @@ +import java.util.*; + +public class Member { + private String id; + private Account account; + private Accounts accounts; + public Map getValue() { + Map temp_nil2 = new HashMap<>(); + temp_nil2.put("name",this.getName()); + temp_nil2.put("id",this.getId()); + return temp_nil2; + } + public String getId() { + return this.id; + } + public String getName() { + return this.account.getName(); + } + public Member(String id, Accounts accounts) { + this.id = id; + this.accounts = accounts; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Members.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Members.java new file mode 100644 index 0000000..091b561 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Members.java @@ -0,0 +1,14 @@ +import java.util.*; + +public class Members { + private List value = new ArrayList<>(); + public List getValue() { + return new ArrayList<>(value); + } + public Member getMember(int mno) { + return this.value.get(mno); + } + public void addRoomMember(String rid, String id) { + this.value.add(new Member(id, accounts)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/OnlineBattleGame2.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/OnlineBattleGame2.java new file mode 100644 index 0000000..cc758ed --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/OnlineBattleGame2.java @@ -0,0 +1,58 @@ +import java.util.*; + +public class OnlineBattleGame2 { + private Accounts accounts; + private Rooms rooms; + public OnlineBattleGame2() { + accounts = new Accounts(); + rooms = new Rooms(accounts); + } + public boolean getBattle(String rid) { + return this.rooms.getRoom(rid).getBattle(); + } + public void battle(String rid, boolean hasWon) { + this.rooms.getRoom(rid).battle(rid, hasWon); + } + public Map getRoom(String rid) { + return this.rooms.getRoom(rid).getValue(); + } + public String getName(String mid) { + return this.accounts.getAccount(mid).getName(); + } + public void changeName(String aid, String name) { + this.accounts.getAccount(aid).changeName(aid, name); + } + public Map getAccounts() { + return this.accounts.getValue(); + } + public void signUp(String name, String aid) { + this.accounts.signUp(name, aid); + } + public List getMembers(String rid) { + return this.rooms.getRoom(rid).getMembers().getValue(); + } + public void addRoomMember(String rid, String id) { + this.rooms.getRoom(rid).getMembers().addRoomMember(rid, id); + } + public int getPoint(String mid) { + return this.accounts.getAccount(mid).getPoint(); + } + public Map getRooms() { + return this.rooms.getValue(); + } + public void createRoom(String rid) { + this.rooms.createRoom(rid); + } + public Map getAccount(String mid) { + return this.accounts.getAccount(mid).getValue(); + } + public Map getMember(String rid, int mno) { + return this.rooms.getRoom(rid).getMembers().getMember(mno).getValue(); + } + public String getId(String rid, int mno) { + return this.rooms.getRoom(rid).getMembers().getMember(mno).getId(); + } + public String getName(String rid, int mno) { + return this.rooms.getRoom(rid).getMembers().getMember(mno).getName(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Room.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Room.java new file mode 100644 index 0000000..43129a4 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Room.java @@ -0,0 +1,32 @@ +import java.util.*; + +public class Room { + private Members members = new Members(); + private boolean battle; + private Account account; + private Accounts accounts; + public Map getValue() { + Map temp_nil0 = new HashMap<>(); + temp_nil0.put("members",this.members.getValue()); + temp_nil0.put("battle",this.getBattle()); + return temp_nil0; + } + public Members getMembers() { + return this.members; + } + public boolean getBattle() { + return this.battle; + } + public void battle(String rid, boolean hasWon) { + this.battle = hasWon; + for (int mno = 0; mno < this.members.getValue().size(); mno++) { + String id = this.members.getMember(mno).getId(); + this.account = accounts.getAccount(id); + this.account.updatePointFromBattle(id, rid, mno, battle, id); + } + } + public Room(boolean battle, Accounts accounts) { + this.battle = battle; + this.accounts = accounts; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Rooms.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Rooms.java new file mode 100644 index 0000000..d4230fa --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/OnlineBattleGame2/Rooms.java @@ -0,0 +1,18 @@ +import java.util.*; + +public class Rooms { + private Map value = new HashMap<>(); + private Accounts accounts; + public Map getValue() { + return new HashMap<>(value); + } + public Room getRoom(String rid) { + return this.value.get(rid); + } + public void createRoom(String rid) { + this.value.put(rid,new Room(false, accounts)); + } + public Rooms(Accounts accounts) { + this.accounts = accounts; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/History.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/History.java new file mode 100644 index 0000000..75373bd --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/History.java @@ -0,0 +1,11 @@ +import java.util.*; + +public class History { + private List value = new ArrayList<>(); + public List getValue() { + return new ArrayList<>(value); + } + public void updateFromPayment(int payment) { + this.value.add(0, payment); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/POS.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/POS.java new file mode 100644 index 0000000..55d7d08 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/POS.java @@ -0,0 +1,29 @@ +import java.util.*; + +public class POS { + private History history; + private Total total; + private Payment payment; + private Points points; + public POS() { + history = new History(); + total = new Total(history); + payment = new Payment(history); + points = new Points(payment); + } + public List getHistory() { + return this.history.getValue(); + } + public int getTotal() { + return this.total.getValue(); + } + public int getPayment() { + return this.payment.getValue(); + } + public void purchase(int x) { + this.payment.purchase(x); + } + public int getPoints() { + return this.points.getValue(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/Payment.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/Payment.java new file mode 100644 index 0000000..23c1088 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/Payment.java @@ -0,0 +1,16 @@ +import java.util.*; + +public class Payment { + private int value = 0; + private History history; + public int getValue() { + return value; + } + public void purchase(int x) { + this.value = x; + this.history.updateFromPayment(value); + } + public Payment(History history) { + this.history = history; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/Points.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/Points.java new file mode 100644 index 0000000..2b11644 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/Points.java @@ -0,0 +1,11 @@ +import java.util.*; + +public class Points { + private Payment payment; + public int getValue() { + return (int)Math.floor((this.payment.getValue()*0.05)); + } + public Points(Payment payment) { + this.payment = payment; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/Total.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/Total.java new file mode 100644 index 0000000..62564ff --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PULL-first/Total.java @@ -0,0 +1,15 @@ +import java.util.*; + +public class Total { + private History history; + public int getValue() { + Integer temp_sum1 = 0; + for (Integer x: this.history.getValue()) { + temp_sum1 += x; + } + return temp_sum1; + } + public Total(History history) { + this.history = history; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/History.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/History.java new file mode 100644 index 0000000..6aa27b8 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/History.java @@ -0,0 +1,17 @@ +import java.util.*; + +public class History { + private List value = new ArrayList<>(); + private Total total; + public List getValue() { + return new ArrayList<>(value); + } + public void updateFromPayment(double payment) { + this.value.add(0, payment); + + this.total.updateFromHistory(value); + } + public History(Total total) { + this.total = total; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/POS.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/POS.java new file mode 100644 index 0000000..2d3e544 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/POS.java @@ -0,0 +1,29 @@ +import java.util.*; + +public class POS { + private Points points; + private Total total; + private History history; + private Payment payment; + public POS() { + points = new Points(); + total = new Total(); + history = new History(total); + payment = new Payment(points,history); + } + public int getPoints() { + return this.points.getValue(); + } + public int getTotal() { + return this.total.getValue(); + } + public List getHistory() { + return this.history.getValue(); + } + public double getPayment() { + return this.payment.getValue(); + } + public void purchase(double x) { + this.payment.purchase(x); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/Payment.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/Payment.java new file mode 100644 index 0000000..ebf56ac --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/Payment.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Payment { + private double value = 0.0; + private Points points; + private History history; + public double getValue() { + return value; + } + public void purchase(double x) { + this.value = x; + this.points.updateFromPayment(value); + this.history.updateFromPayment(value); + } + public Payment(Points points, History history) { + this.points = points; + this.history = history; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/Points.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/Points.java new file mode 100644 index 0000000..55cb552 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/Points.java @@ -0,0 +1,11 @@ +import java.util.*; + +public class Points { + private int value = 0; + public int getValue() { + return value; + } + public void updateFromPayment(double payment) { + this.value = (int)Math.floor((payment*0.05)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/Total.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/Total.java new file mode 100644 index 0000000..2a3c00e --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/POS/PUSH-first/Total.java @@ -0,0 +1,15 @@ +import java.util.*; + +public class Total { + private int value = 0; + public int getValue() { + return value; + } + public void updateFromHistory(List history) { + Integer temp_sum1 = 0; + for (Integer x: history) { + temp_sum1 += x; + } + this.value = temp_sum1; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/SimpleTwitter/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/SimpleTwitter/Account.java new file mode 100644 index 0000000..f007a58 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/SimpleTwitter/Account.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Account { + private List tweets; + public Map getValue() { + Map temp_nil27 = new HashMap<>(); + temp_nil27.put("tweets",this.getTweets()); + return temp_nil27; + } + public List getTweets() { + return this.tweets; + } + public void tweet(String accountId, String contents) { + this.tweets.add(contents); + } + public Account(List tweets) { + this.tweets = tweets; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/SimpleTwitter/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/SimpleTwitter/Accounts.java new file mode 100644 index 0000000..7f2a17b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/SimpleTwitter/Accounts.java @@ -0,0 +1,14 @@ +import java.util.*; + +public class Accounts { + private Map value = new HashMap<>(); + public Map getValue() { + return new HashMap<>(value); + } + public Account getAccount(String accountId) { + return this.value.get(accountId); + } + public void signUp(String name, String accountId) { + this.value.put(accountId,new Account(new ArrayList<>())); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/SimpleTwitter/SimpleTwitter.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/SimpleTwitter/SimpleTwitter.java new file mode 100644 index 0000000..36aaf77 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/SimpleTwitter/SimpleTwitter.java @@ -0,0 +1,23 @@ +import java.util.*; + +public class SimpleTwitter { + private Accounts accounts; + public SimpleTwitter() { + accounts = new Accounts(); + } + public List getTweets(String accountId) { + return this.accounts.getAccount(accountId).getTweets(); + } + public void tweet(String accountId, String contents) { + this.accounts.getAccount(accountId).tweet(accountId, contents); + } + public Map getAccount(String accountId) { + return this.accounts.getAccount(accountId).getValue(); + } + public Map getAccounts() { + return this.accounts.getValue(); + } + public void signUp(String name, String accountId) { + this.accounts.signUp(name, accountId); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/VotingSystem/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/VotingSystem/Account.java new file mode 100644 index 0000000..605d6c1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/VotingSystem/Account.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Account { + private String vote; + public Map getValue() { + Map temp_nil4 = new HashMap<>(); + temp_nil4.put("vote",this.getVote()); + return temp_nil4; + } + public String getVote() { + return this.vote; + } + public void cast(String aid, String v) { + this.vote = v; + } + public Account(String vote) { + this.vote = vote; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/VotingSystem/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/VotingSystem/Accounts.java new file mode 100644 index 0000000..d0b8bb3 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/VotingSystem/Accounts.java @@ -0,0 +1,14 @@ +import java.util.*; + +public class Accounts { + private Map value = new HashMap<>(); + public Map getValue() { + return new HashMap<>(value); + } + public Account getAccount(String aid) { + return this.value.get(aid); + } + public void signUp(String name, String aid) { + this.value.put(aid,new Account(null)); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/VotingSystem/Counts.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/VotingSystem/Counts.java new file mode 100644 index 0000000..a0d5b9f --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/VotingSystem/Counts.java @@ -0,0 +1,18 @@ +import java.util.*; + +public class Counts { + private Map value = new HashMap<>(); + private Account account; + private Accounts accounts; + public Map getValue() { + Map v0 = new HashMap<>(); + for (String aid: this.accounts.getValue().keySet()) { + String vote = this.accounts.getAccount(aid).getVote(); + v0.put(aid,vote); + } + return v0; + } + public Counts(Accounts accounts) { + this.accounts = accounts; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/VotingSystem/VotingSystem.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/VotingSystem/VotingSystem.java new file mode 100644 index 0000000..27950ce --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/VotingSystem/VotingSystem.java @@ -0,0 +1,28 @@ +import java.util.*; + +public class VotingSystem { + private Accounts accounts; + private Counts counts; + public VotingSystem() { + accounts = new Accounts(); + counts = new Counts(accounts); + } + public Map getAccount(String aid) { + return this.accounts.getAccount(aid).getValue(); + } + public Map getAccounts() { + return this.accounts.getValue(); + } + public void signUp(String name, String aid) { + this.accounts.signUp(name, aid); + } + public Map getCounts() { + return this.counts.getValue(); + } + public String getVote(String aid) { + return this.accounts.getAccount(aid).getVote(); + } + public void cast(String aid, String v) { + this.accounts.getAccount(aid).cast(aid, v); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PULL-first/Highest.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PULL-first/Highest.java new file mode 100644 index 0000000..407263c --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PULL-first/Highest.java @@ -0,0 +1,20 @@ +import java.util.*; + +public class Highest { + private double value = 0.0; + public double getValue() { + return value; + } + public void updateFromTemp_f(double temp_f) { + double temp_if5; + if ((temp_f>=this.value)) { + temp_if5 = temp_f; + } else { + temp_if5 = this.value; + } + this.value = temp_if5; + } + public void reset(double v) { + this.value = v; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PULL-first/Temp_c.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PULL-first/Temp_c.java new file mode 100644 index 0000000..7eb9df6 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PULL-first/Temp_c.java @@ -0,0 +1,11 @@ +import java.util.*; + +public class Temp_c { + private Temp_f temp_f; + public double getValue() { + return ((this.temp_f.getValue()-32)/1.8); + } + public Temp_c(Temp_f temp_f) { + this.temp_f = temp_f; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PULL-first/Temp_f.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PULL-first/Temp_f.java new file mode 100644 index 0000000..2b57682 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PULL-first/Temp_f.java @@ -0,0 +1,16 @@ +import java.util.*; + +public class Temp_f { + private double value = 0.0; + private Highest highest; + public double getValue() { + return value; + } + public void observe(double x) { + this.value = x; + this.highest.updateFromTemp_f(value); + } + public Temp_f(Highest highest) { + this.highest = highest; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PULL-first/WeatherObservationSystem.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PULL-first/WeatherObservationSystem.java new file mode 100644 index 0000000..940b5a7 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PULL-first/WeatherObservationSystem.java @@ -0,0 +1,27 @@ +import java.util.*; + +public class WeatherObservationSystem { + private Highest highest; + private Temp_f temp_f; + private Temp_c temp_c; + public WeatherObservationSystem() { + highest = new Highest(); + temp_f = new Temp_f(highest); + temp_c = new Temp_c(temp_f); + } + public double getHighest() { + return this.highest.getValue(); + } + public void reset(double v) { + this.highest.reset(v); + } + public double getTemp_f() { + return this.temp_f.getValue(); + } + public void observe(double x) { + this.temp_f.observe(x); + } + public double getTemp_c() { + return this.temp_c.getValue(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PUSH-first/Highest.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PUSH-first/Highest.java new file mode 100644 index 0000000..be085e2 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PUSH-first/Highest.java @@ -0,0 +1,20 @@ +import java.util.*; + +public class Highest { + private double value = 0.0; + public double getValue() { + return value; + } + public void updateFromTemp_f(double temp_f) { + double temp_if6; + if ((temp_f>=this.value)) { + temp_if6 = temp_f; + } else { + temp_if6 = this.value; + } + this.value = temp_if6; + } + public void reset(double v) { + this.value = v; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PUSH-first/Temp_c.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PUSH-first/Temp_c.java new file mode 100644 index 0000000..8aea709 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PUSH-first/Temp_c.java @@ -0,0 +1,11 @@ +import java.util.*; + +public class Temp_c { + private double value = 0.0; + public double getValue() { + return value; + } + public void updateFromTemp_f(double temp_f) { + this.value = ((temp_f-32)/1.8); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PUSH-first/Temp_f.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PUSH-first/Temp_f.java new file mode 100644 index 0000000..3a63072 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PUSH-first/Temp_f.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Temp_f { + private double value = 0.0; + private Temp_c temp_c; + private Highest highest; + public double getValue() { + return value; + } + public void observe(double x) { + this.value = x; + this.temp_c.updateFromTemp_f(value); + this.highest.updateFromTemp_f(value); + } + public Temp_f(Temp_c temp_c, Highest highest) { + this.temp_c = temp_c; + this.highest = highest; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PUSH-first/WeatherObservationSystem.java b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PUSH-first/WeatherObservationSystem.java new file mode 100644 index 0000000..9d43e68 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/prototypes/Java/WeatherObservationSystem/PUSH-first/WeatherObservationSystem.java @@ -0,0 +1,27 @@ +import java.util.*; + +public class WeatherObservationSystem { + private Temp_c temp_c; + private Highest highest; + private Temp_f temp_f; + public WeatherObservationSystem() { + temp_c = new Temp_c(); + highest = new Highest(); + temp_f = new Temp_f(temp_c,highest); + } + public double getTemp_c() { + return this.temp_c.getValue(); + } + public double getHighest() { + return this.highest.getValue(); + } + public void reset(double v) { + this.highest.reset(v); + } + public double getTemp_f() { + return this.temp_f.getValue(); + } + public void observe(double x) { + this.temp_f.observe(x); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java b/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java index 836227a..a392b11 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Set; import models.*; import models.algebra.*; @@ -24,41 +25,47 @@ */ static public DataFlowGraph createDataFlowGraphWithStateStoringAttribute(DataTransferModel model) { DataFlowGraph graph = model.getDataFlowGraph(); - Collection channels = new HashSet<>(model.getIOChannels()); + Collection channels = new HashSet<>(model.getInputChannels()); channels.addAll(model.getChannels()); for (Channel channel: channels) { for (ChannelMember member: ((DataTransferChannel) channel).getOutputChannelMembers()) { - boolean flag = !member.getStateTransition().isRightUnary(); // The state does not need to be stored if the state transition function is right unary. - for (Node node : graph.getNodes()) { - if (((ResourceNode) node).getResource().equals(member.getResource())) { - setStoreAttribute(flag, (ResourceNode) node); + boolean toBeStored = !member.getStateTransition().isRightUnary(); // The state does not need to be stored if the state transition function is right unary. + for (Node node : graph.getResourceNodes()) { + if (((ResourceNode) node).getInSideResources().contains(member.getResource())) { + setStoreAttribute((ResourceNode) node, toBeStored); } } } } - for (Node node : graph.getNodes()) { + for (Node node: graph.getResourceNodes()) { HashSet inChannels = new HashSet<>(); - for(Edge pre : ((ResourceNode) node).getInEdges()) { - inChannels.add(((DataFlowEdge) pre).getChannel()); + for(Edge inEdge: ((ResourceNode) node).getInEdges()) { + if (inEdge instanceof DataFlowEdge) { + DataFlowEdge dfEdge = (DataFlowEdge) inEdge; + if (dfEdge.isChannelToResource()) { + inChannels.add(((ChannelNode) dfEdge.getSource()).getChannel()); + } + } } if ((inChannels.size() > 1)) { - setStoreAttribute(true, (ResourceNode) node); + // If the resource has multiple input channels, then the state of the resource needs to be stored. + setStoreAttribute((ResourceNode) node, true); } else if (((ResourceNode) node).getAttribute() == null) { - setStoreAttribute(false, (ResourceNode) node); + setStoreAttribute((ResourceNode) node, false); } } return graph; } - static private void setStoreAttribute(boolean flag, ResourceNode node) { + static private void setStoreAttribute(ResourceNode node, boolean toBeStored) { NodeAttribute attr = node.getAttribute(); StoreAttribute store; if (attr != null && attr instanceof NodeAttribute) { store = (StoreAttribute) attr; - store.setNeeded(store.isNeeded() || flag); + store.setNeeded(store.isNeeded() || toBeStored); } else { store = new StoreAttribute(); - store.setNeeded(flag); + store.setNeeded(toBeStored); node.setAttribute(store); } } @@ -69,17 +76,60 @@ * @return annotated data flow graph */ static public DataFlowGraph annotateWithSelectableDataTransferAttiribute(DataFlowGraph graph) { - List nodes = new ArrayList<>(graph.getNodes()); - // set push only attributes - for (Node n: graph.getNodes()) { - if (nodes.contains(n) && ((StoreAttribute) ((ResourceNode) n).getAttribute()).isNeeded()) { - nodes.remove(n); - trackEdges(n, nodes); + HashSet unvisitedNodes = new HashSet<>(graph.getResourceNodes()); + // Turn push only + for (Node resNode: graph.getResourceNodes()) { + if (unvisitedNodes.contains(resNode) && ((StoreAttribute) ((ResourceNode) resNode).getAttribute()).isNeeded()) { + unvisitedNodes.remove(resNode); + trackEdgesBackwardForPush(resNode, unvisitedNodes); + } + } + // Turn push/pull only with respect to channel hierarchies. + while (!unvisitedNodes.isEmpty()) { + Node resNode = unvisitedNodes.iterator().next(); + unvisitedNodes.remove(resNode); + for (Edge chToRes : ((ResourceNode) resNode).getInEdges()) { + ChannelNode chNode = (ChannelNode) chToRes.getSource(); + // Should take into account the channel hierarchy. + boolean pullContained = false; + Set ancestorChannels = chNode.getAncestors(); + for (ChannelNode ancestorCh: ancestorChannels) { + for (Edge resToCh: ancestorCh.getInEdges()) { + ResourceNode srcResNode = (ResourceNode) resToCh.getSource(); + DataTransferChannel ch = (DataTransferChannel) ancestorCh.getChannel(); + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.isOutside()) { + PushPullAttribute ppat = new PushPullAttribute(); + ppat.addOption(PushPullValue.PULL); // To refer to outside resource. + ((DataFlowEdge) resToCh).setAttribute(ppat); + pullContained = true; + } else { + PushPullAttribute ppat = new PushPullAttribute(); + ppat.addOption(PushPullValue.PUSH); // For broadcasting transfer. + ((DataFlowEdge) resToCh).setAttribute(ppat); + unvisitedNodes.remove(srcResNode); + trackEdgesBackwardForPush(srcResNode, unvisitedNodes); + } + } + } + } + Set descendantChannels = chNode.getDescendants(); + for (ChannelNode descendantCh: descendantChannels) { + for (Edge resToCh: descendantCh.getInEdges()) { + PushPullAttribute ppat = new PushPullAttribute(); + ppat.addOption(PushPullValue.PULL); // For collecting transfer. + ((DataFlowEdge) resToCh).setAttribute(ppat); + pullContained = true; + } + } + if (pullContained) { + trackEdgesForwardForPull(resNode, unvisitedNodes); + } } } // set push/pull attributes to the remaining edges for (Edge e : graph.getEdges()) { - if (((DataFlowEdge) e).getAttribute() == null) { + if (!((DataFlowEdge) e).isChannelToResource() && ((DataFlowEdge) e).getAttribute() == null) { PushPullAttribute ppat = new PushPullAttribute(); ppat.addOption(PushPullValue.PUSHorPULL); ppat.addOption(PushPullValue.PUSH); @@ -90,16 +140,58 @@ return graph; } - static private void trackEdges(Node n, List nodes) { - // recursively set push only attributes to input side edges - for (Edge e : ((ResourceNode) n).getInEdges()) { + static private void trackEdgesBackwardForPush(Node resNode, HashSet unvisitedNodes) { + // recursively turn push only backward in data-flow. + for (Edge chToRes : ((ResourceNode) resNode).getInEdges()) { + ChannelNode chNode = (ChannelNode) chToRes.getSource(); + // Should take into account the channel hierarchy. + Set ancestorChannels = chNode.getAncestors(); + Set descendantChannels = chNode.getDescendants(); + Set inEdges = new HashSet<>(); + inEdges.addAll(chNode.getInEdges()); + for (ChannelNode ancestorCh: ancestorChannels) { + inEdges.addAll(ancestorCh.getInEdges()); + } + for (ChannelNode descendantCh: descendantChannels) { + inEdges.addAll(descendantCh.getInEdges()); + } + for (Edge resToCh: inEdges) { + PushPullAttribute ppat = new PushPullAttribute(); + ppat.addOption(PushPullValue.PUSH); + ((DataFlowEdge) resToCh).setAttribute(ppat); + Node resNode2 = resToCh.getSource(); + if (unvisitedNodes.contains(resNode2)) { + unvisitedNodes.remove(resNode2); + trackEdgesBackwardForPush(resNode2, unvisitedNodes); + } + } + } + } + + private static void trackEdgesForwardForPull(Node resNode, HashSet unvisitedNodes) { + // recursively turn pull only forward in data-flow. + for (Edge resToCh : ((ResourceNode) resNode).getOutEdges()) { PushPullAttribute ppat = new PushPullAttribute(); - ppat.addOption(PushPullValue.PUSH); - ((DataFlowEdge) e).setAttribute(ppat); - Node n2 = e.getSource(); - if (nodes.contains(n2)) { - nodes.remove(n2); - trackEdges(n2, nodes); + ppat.addOption(PushPullValue.PULL); + ((DataFlowEdge) resToCh).setAttribute(ppat); + ChannelNode chNode = (ChannelNode) resToCh.getDestination(); + // Should take into account the channel hierarchy. + Set ancestorChannels = chNode.getAncestors(); + Set descendantChannels = chNode.getDescendants(); + Set outEdges = new HashSet<>(); + outEdges.addAll(chNode.getOutEdges()); + for (ChannelNode ancestorCh: ancestorChannels) { + outEdges.addAll(ancestorCh.getOutEdges()); + } + for (ChannelNode descendantCh: descendantChannels) { + outEdges.addAll(descendantCh.getOutEdges()); + } + for (Edge chToRes: outEdges) { + Node resNode2 = chToRes.getDestination(); + if (unvisitedNodes.contains(resNode2)) { + unvisitedNodes.remove(resNode2); + trackEdgesForwardForPull(resNode2, unvisitedNodes); + } } } } diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java deleted file mode 100644 index d29070d..0000000 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java +++ /dev/null @@ -1,1713 +0,0 @@ -package algorithms; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.xml.crypto.Data; - -import models.Node; -import models.algebra.Expression; -import models.algebra.Position; -import models.algebra.Symbol; -import models.algebra.Term; -import models.algebra.Type; -import models.algebra.Variable; -import models.dataConstraintModel.Channel; -import models.dataConstraintModel.ChannelMember; -import models.dataConstraintModel.DataConstraintModel; -import models.dataConstraintModel.ResourcePath; -import models.dataConstraintModel.StateTransition; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.ResourceNode; - -/** - * Type inference for data transfer model - * - * @author Nitta - * - */ -public class TypeInference { - static private Map listTypes = new HashMap<>(); - static private Map listComponentTypes = new HashMap<>(); - static private Map, Type> tupleTypes = new HashMap<>(); - static private Map> tupleComponentTypes = new HashMap<>(); - static private Map pairTypes = new HashMap<>(); - static private Map pairComponentTypes = new HashMap<>(); - static private Map, Type> mapTypes = new HashMap<>(); - static private Map> mapComponentTypes = new HashMap<>(); - - public static Type getListType(Type compType) { - return listTypes.get(compType); - } - - public static Type getListComponentType(Type listType) { - return listComponentTypes.get(listType); - } - - public static Collection getListTypes() { - return listTypes.values(); - } - - public static Type getTupleType(List compTypes) { - return tupleTypes.get(compTypes); - } - - public static List getTupleComponentTypes(Type tupleType) { - return tupleComponentTypes.get(tupleType); - } - - public static Collection getTupleTypes() { - return tupleTypes.values(); - } - - public static Type getPairType(Type compType) { - return pairTypes.get(compType); - } - - public static Type getPairComponentType(Type pairType) { - return pairComponentTypes.get(pairType); - } - - public static Type getMapType(List compTypes) { - return mapTypes.get(compTypes); - } - - public static List getMapComponentTypes(Type mapType) { - return mapComponentTypes.get(mapType); - } - - static public void infer(DataTransferModel model) { - Map> resources = new HashMap<>(); - Map variables = new HashMap<>(); - Map, Type>>> messages = new HashMap<>(); - Map consOrSet = new HashMap<>(); - Map tuple = new HashMap<>(); - Map pair = new HashMap<>(); - Map map = new HashMap<>(); - Map> expToResource = new HashMap<>(); - Map> expToVariable = new HashMap<>(); - Map> expToMessage = new HashMap<>(); - Map>> expToConsOrSet = new HashMap<>(); - Map>> expToTuple = new HashMap<>(); - Map>> expToPair = new HashMap<>(); - Map>> expToMap = new HashMap<>(); - - Map> updateFromResource = new HashMap<>(); - Map> updateFromVariable = new HashMap<>(); - Map> updateFromMessage = new HashMap<>(); - Map> updateFromConsOrSet = new HashMap<>(); - Map> updateFromTuple = new HashMap<>(); - Map> updateFromPair = new HashMap<>(); - Map> updateFromMap = new HashMap<>(); - - listComponentTypes.put(DataConstraintModel.typeList, null); - listComponentTypes.put(DataConstraintModel.typeListInt, DataConstraintModel.typeInt); - listComponentTypes.put(DataConstraintModel.typeListStr, DataConstraintModel.typeString); - listTypes.put(DataConstraintModel.typeInt, DataConstraintModel.typeListInt); - listTypes.put(DataConstraintModel.typeString, DataConstraintModel.typeListStr); - pairComponentTypes.put(DataConstraintModel.typePair, null); - pairComponentTypes.put(DataConstraintModel.typePairInt, DataConstraintModel.typeInt); - pairComponentTypes.put(DataConstraintModel.typePairStr, DataConstraintModel.typeString); - pairComponentTypes.put(DataConstraintModel.typePairDouble, DataConstraintModel.typeDouble); - pairTypes.put(DataConstraintModel.typeInt, DataConstraintModel.typePairInt); - pairTypes.put(DataConstraintModel.typeString, DataConstraintModel.typePairStr); - pairTypes.put(DataConstraintModel.typeDouble, DataConstraintModel.typePairDouble); - tupleComponentTypes.put(DataConstraintModel.typeTuple, Arrays.asList(new Type[] { null, null })); - mapComponentTypes.put(DataConstraintModel.typeMap, Arrays.asList(new Type[] { null, null })); - - // 1. Collect type information from the architecture model. - Collection channels = new HashSet<>(model.getIOChannels()); - channels.addAll(model.getChannels()); - for (Channel c : channels) { - for (ChannelMember cm : c.getChannelMembers()) { - StateTransition st = cm.getStateTransition(); - ResourcePath id = cm.getResource(); - - // 1.1 Group expressions by resources. - List sameResource = resources.get(id); - if (sameResource == null) { - sameResource = new ArrayList<>(); - resources.put(id, sameResource); - } - sameResource.add(st.getCurStateExpression()); - if (st.getNextStateExpression() != null) sameResource.add(st.getNextStateExpression()); - expToResource.put(System.identityHashCode(st.getCurStateExpression()), sameResource); - if (st.getNextStateExpression() != null) expToResource.put(System.identityHashCode(st.getNextStateExpression()), sameResource); - Map updatedExps = getUpdateSet(updateFromResource, sameResource); - Type resType = id.getResourceStateType(); - Expression exp = st.getCurStateExpression(); - Type expType = getExpTypeIfUpdatable(resType, exp); - if (expType != null) { - id.setResourceStateType(expType); - for (Expression resExp : sameResource) { - if (resExp != exp) { - if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { - ((Variable) resExp).setType(expType); - updatedExps.put(System.identityHashCode(resExp), resExp); - } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { - ((Term) resExp).setType(expType); - updatedExps.put(System.identityHashCode(resExp), resExp); - } - } - } - } else if (exp instanceof Variable) { - if (compareTypes(((Variable) exp).getType(), resType)) { - ((Variable) exp).setType(resType); - updatedExps.put(System.identityHashCode(exp), exp); - } - } else if (exp instanceof Term) { - if (compareTypes(((Term) exp).getType(), resType)) { - ((Term) exp).setType(resType); - updatedExps.put(System.identityHashCode(exp), exp); - } - } - resType = id.getResourceStateType(); - exp = st.getNextStateExpression(); - if (exp != null) { - expType = getExpTypeIfUpdatable(resType, exp); - if (expType != null) { - id.setResourceStateType(expType); - for (Expression resExp : sameResource) { - if (resExp != exp) { - if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { - ((Variable) resExp).setType(expType); - updatedExps.put(System.identityHashCode(resExp), resExp); - } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { - ((Term) resExp).setType(expType); - updatedExps.put(System.identityHashCode(resExp), resExp); - } - } - } - } else if (exp instanceof Variable) { - if (compareTypes(((Variable) exp).getType(), resType)) { - ((Variable) exp).setType(resType); - updatedExps.put(System.identityHashCode(exp), exp); - } - } else if (exp instanceof Term) { - if (compareTypes(((Term) exp).getType(), resType)) { - ((Term) exp).setType(resType); - updatedExps.put(System.identityHashCode(exp), exp); - } - } - } - - // 1.2 Group expressions by variable. - Map> locals = new HashMap<>(); - Map localTypes = new HashMap<>(); - List allVariables = new ArrayList<>(); - allVariables.addAll(st.getCurStateExpression().getVariables().values()); - allVariables.addAll(st.getMessageExpression().getVariables().values()); - if (st.getNextStateExpression() != null) - allVariables.addAll(st.getNextStateExpression().getVariables().values()); - for (Variable var : allVariables) { - List sameVariable = locals.get(var.getName()); - if (sameVariable == null) { - sameVariable = new ArrayList<>(); - sameVariable.add(var); - expToVariable.put(System.identityHashCode(var), sameVariable); - locals.put(var.getName(), sameVariable); - localTypes.put(var.getName(), var.getType()); - } else { - sameVariable.add(var); - expToVariable.put(System.identityHashCode(var), sameVariable); - Type varType = localTypes.get(var.getName()); - Map updatedVars = getUpdateSet(updateFromVariable, sameVariable); - if (compareTypes(varType, var.getType())) { - localTypes.put(var.getName(), var.getType()); - for (Expression v : sameVariable) { - if (v != var) { - if (compareTypes(((Variable) v).getType(), var.getType())) { - ((Variable) v).setType(var.getType()); - updatedVars.put(System.identityHashCode(v), v); - } - } - } - } else if (compareTypes(var.getType(), varType)) { - var.setType(varType); - updatedVars.put(System.identityHashCode(var), var); - } - } - } - for (String varName : locals.keySet()) { - variables.put(System.identityHashCode(locals.get(varName)), localTypes.get(varName)); - } - - // 1.3 Group expressions by message. - Expression message = st.getMessageExpression(); - if (message instanceof Variable) { - Type msgType = ((Variable) message).getType(); - Map, Type>> msgTypeMap = messages.get(c); - if (msgTypeMap == null) { - msgTypeMap = new HashMap<>(); - messages.put(c, msgTypeMap); - } - Map.Entry, Type> typeAndExps = msgTypeMap.get(0); - if (typeAndExps == null) { - List exps = new ArrayList<>(); - exps.add(message); - typeAndExps = new AbstractMap.SimpleEntry<>(exps, msgType); - msgTypeMap.put(0, typeAndExps); - expToMessage.put(System.identityHashCode(message), exps); - } else { - typeAndExps.getKey().add(message); - expToMessage.put(System.identityHashCode(message), typeAndExps.getKey()); - Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); - if (compareTypes(typeAndExps.getValue(), msgType)) { - typeAndExps.setValue(msgType); - for (Expression e : typeAndExps.getKey()) { - if (e != message) { - if (e instanceof Variable) { - ((Variable) e).setType(msgType); - updateExps.put(System.identityHashCode(e), e); - } - } - } - } else if (compareTypes(msgType, typeAndExps.getValue())) { - ((Variable) message).setType(typeAndExps.getValue()); - updateExps.put(System.identityHashCode(message), message); - } - } - } else if (message instanceof Term) { - Map, Type>> msgTypeMap = messages.get(c); - if (msgTypeMap == null) { - msgTypeMap = new HashMap<>(); - messages.put(c, msgTypeMap); - } - for (int i = 0; i < ((Term) message).getArity(); i++) { - Expression arg = ((Term) message).getChild(i); - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } else { - continue; - } - Map.Entry, Type> typeAndExps = msgTypeMap.get(i); - if (typeAndExps == null) { - List exps = new ArrayList<>(); - exps.add(arg); - typeAndExps = new AbstractMap.SimpleEntry<>(exps, argType); - msgTypeMap.put(i, typeAndExps); - expToMessage.put(System.identityHashCode(arg), exps); - } else { - typeAndExps.getKey().add(arg); - expToMessage.put(System.identityHashCode(arg), typeAndExps.getKey()); - Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); - if (compareTypes(typeAndExps.getValue(), argType)) { - typeAndExps.setValue(argType); - for (Expression e : typeAndExps.getKey()) { - if (e != arg) { - if (e instanceof Variable) { - ((Variable) e).setType(argType); - updateExps.put(System.identityHashCode(e), e); - } - } - } - } else if (compareTypes(argType, typeAndExps.getValue())) { - if (arg instanceof Variable) { - ((Variable) arg).setType(typeAndExps.getValue()); - updateExps.put(System.identityHashCode(arg), arg); - } else if (arg instanceof Term) { - ((Term) arg).setType(typeAndExps.getValue()); - updateExps.put(System.identityHashCode(arg), arg); - } - } - } - } - } - - // 1.4 Extract constraints on expressions in each term. - List terms = new ArrayList<>(); - if (st.getCurStateExpression() instanceof Term) { - Map subTerms = ((Term) st.getCurStateExpression()).getSubTerms(Term.class); - terms.addAll(subTerms.values()); - } - if (st.getMessageExpression() instanceof Term) { - Map subTerms = ((Term) st.getMessageExpression()).getSubTerms(Term.class); - terms.addAll(subTerms.values()); - } - if (st.getNextStateExpression() != null && st.getNextStateExpression() instanceof Term) { - Map subTerms = ((Term) st.getNextStateExpression()).getSubTerms(Term.class); - terms.addAll(subTerms.values()); - } - for (Term t : terms) { - Symbol symbol = t.getSymbol(); - if (symbol.equals(DataConstraintModel.cons) || symbol.equals(DataConstraintModel.set)) { - // If the root symbol of the term is cons or set. - List consExps = new ArrayList<>(); - consExps.add(t); - updateExpressionBelonging(expToConsOrSet, t, consExps); - if (symbol.equals(DataConstraintModel.cons)) { - // If the root symbol of the term is cons. - for (Expression e : t.getChildren()) { - consExps.add(e); - updateExpressionBelonging(expToConsOrSet, e, consExps); - } - } else { - // If the root symbol of the term is set. - Expression e = t.getChildren().get(2); - consExps.add(e); - updateExpressionBelonging(expToConsOrSet, e, consExps); - e = t.getChildren().get(0); - consExps.add(e); - updateExpressionBelonging(expToConsOrSet, e, consExps); - } - Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); - if (newType != null) { - // If the type of the 2nd argument of cons (1st argument of set) is more concrete than the type of the term. - t.setType(newType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - } else { - Type arg2Type = null; - if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { - arg2Type = ((Variable) consExps.get(2)).getType(); - if (compareTypes(arg2Type, t.getType())) { - // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set). - ((Variable) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { - arg2Type = ((Term) consExps.get(2)).getType(); - if (compareTypes(arg2Type, t.getType())) { - // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set). - ((Term) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } - } - Type newCompType = getExpTypeIfUpdatable(listComponentTypes.get(t.getType()), consExps.get(1)); - if (newCompType != null) { - // If the type of the 1st argument of cons (3rd argument of set) is more concrete than the type of list component. - Type newListType = listTypes.get(newCompType); - if (newListType == null) { - // Create new list type. - newListType = createNewListType(newCompType, DataConstraintModel.typeList); - } - t.setType(newListType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { - ((Variable) consExps.get(2)).setType(newListType); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { - ((Term) consExps.get(2)).setType(newListType); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } - consOrSet.put(System.identityHashCode(consExps), t.getType()); - } else if (symbol.equals(DataConstraintModel.head) || symbol.equals(DataConstraintModel.get)) { - // If the root symbol of the term is head or get. - List consExps = new ArrayList<>(); - Expression e = t.getChildren().get(0); - consExps.add(e); - updateExpressionBelonging(expToConsOrSet, e, consExps); - consExps.add(t); - updateExpressionBelonging(expToConsOrSet, t, consExps); - consExps.add(null); - Type listType = listTypes.get(t.getType()); - if (listType == null && t.getType() != null) { - // Create a new list type. - listType = createNewListType(t.getType(), DataConstraintModel.typeList); - } - Type newListType = getExpTypeIfUpdatable(listType, consExps.get(0)); - if (newListType != null) { - // If the type of the component of the 1st argument is more concrete than the type of the term. - Type newCompType = listComponentTypes.get(newListType); - if (newCompType != null) { - t.setType(newCompType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - } - consOrSet.put(System.identityHashCode(consExps), newListType); - } else { - // If the type of the term is more concrete than the type of the component of the 1st argument. - if (consExps.get(0) != null && consExps.get(0) instanceof Variable) { - ((Variable) consExps.get(0)).setType(listType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); - } else if (consExps.get(0) != null && consExps.get(0) instanceof Term) { - ((Term) consExps.get(0)).setType(listType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); - } - consOrSet.put(System.identityHashCode(consExps), listType); - } - } else if (symbol.equals(DataConstraintModel.tail)) { - // If the root symbol of the term is tail. - List consExps = new ArrayList<>(); - consExps.add(t); - updateExpressionBelonging(expToConsOrSet, t, consExps); - consExps.add(null); - Expression e = t.getChildren().get(0); - consExps.add(e); - updateExpressionBelonging(expToConsOrSet, e, consExps); - Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); - if (newType != null) { - // If the type of the argument is more concrete than the type of the term. - t.setType(newType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - } else { - Type argType = null; - if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { - argType = ((Variable) consExps.get(2)).getType(); - if (compareTypes(argType, t.getType())) { - // If the type of the term is more concrete than the type of the argument. - ((Variable) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { - argType = ((Term) consExps.get(2)).getType(); - if (compareTypes(argType, t.getType())) { - // If the type of the term is more concrete than the type of the argument. - ((Term) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } - } - consOrSet.put(System.identityHashCode(consExps), t.getType()); - } else if (symbol.equals(DataConstraintModel.tuple)) { - // If the root symbol of the term is tuple. - List tupleExps = new ArrayList<>(); - List argsTypeList = new ArrayList<>(); - tupleExps.add(t); - updateExpressionBelonging(expToTuple, t, tupleExps); - for (Expression e : t.getChildren()) { - tupleExps.add(e); - updateExpressionBelonging(expToTuple, e, tupleExps); - if (e instanceof Variable) { - argsTypeList.add(((Variable) e).getType()); - } else if (e instanceof Term) { - argsTypeList.add(((Term) e).getType()); - } else { - argsTypeList.add(null); - } - } - if (t.getType() == DataConstraintModel.typeTuple) { - Type newTupleType = tupleTypes.get(argsTypeList); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(argsTypeList, DataConstraintModel.typeTuple); - } - t.setType(newTupleType); - Map updateExps = getUpdateSet(updateFromTuple, tupleExps); - updateExps.put(System.identityHashCode(t), t); - } - tuple.put(System.identityHashCode(tupleExps), t.getType()); - } else if (symbol.equals(DataConstraintModel.pair)) { - // If the root symbol of the term is pair. - List pairExps = new ArrayList<>(); - pairExps.add(t); - updateExpressionBelonging(expToPair, t, pairExps); - if (t.getType() == DataConstraintModel.typePair) { - for (Expression e : t.getChildren()) { - pairExps.add(e); - updateExpressionBelonging(expToPair, e, pairExps); - Type argType = null; - if (e instanceof Variable) { - argType = (((Variable) e).getType()); - - } else if (e instanceof Term) { - argType = (((Term) e).getType()); - } - - if (argType != null) { - Type newPairType = pairTypes.get(argType); - if (newPairType != null) { - t.setType(newPairType); - Map updateExps = getUpdateSet(updateFromPair, pairExps); - updateExps.put(System.identityHashCode(t), t); - } - } - } - pair.put(System.identityHashCode(pairExps), t.getType()); - - } - } else if (symbol.equals(DataConstraintModel.fst)) { - // If the root symbol of the term is fst. - List tupleExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - tupleExps.add(arg); - updateExpressionBelonging(expToTuple, arg, tupleExps); - tupleExps.add(t); - updateExpressionBelonging(expToTuple, t, tupleExps); - tupleExps.add(null); - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newTupleType = DataConstraintModel.typeTuple; - if (argType == DataConstraintModel.typeTuple && t.getType() != null) { - List compTypeList = new ArrayList<>(); - compTypeList.add(t.getType()); - compTypeList.add(null); - newTupleType = tupleTypes.get(compTypeList); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(compTypeList, DataConstraintModel.typeTuple); - } - } - if (argType != newTupleType && newTupleType != null) { - if (arg instanceof Variable) { - ((Variable) arg).setType(newTupleType); - argType = newTupleType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newTupleType); - argType = newTupleType; - } - Map updateExps = getUpdateSet(updateFromTuple, tupleExps); - updateExps.put(System.identityHashCode(arg), arg); - } - tuple.put(System.identityHashCode(tupleExps), argType); - } else if (symbol.equals(DataConstraintModel.snd)) { - // If the root symbol of the term is snd. - List tupleExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - tupleExps.add(arg); - updateExpressionBelonging(expToTuple, arg, tupleExps); - tupleExps.add(null); - tupleExps.add(t); - updateExpressionBelonging(expToTuple, t, tupleExps); - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newTupleType = DataConstraintModel.typeTuple; - if (argType == DataConstraintModel.typeTuple && t.getType() != null) { - List compTypeList = new ArrayList<>(); - compTypeList.add(null); - if (DataConstraintModel.typeTuple.isAncestorOf(t.getType())) { - List sndTypes = tupleComponentTypes.get(t.getType()); - if (sndTypes != null) { - for (Type t2: sndTypes) { - compTypeList.add(t2); - } - } else { - compTypeList.add(t.getType()); - } - } else { - compTypeList.add(t.getType()); - } - newTupleType = tupleTypes.get(compTypeList); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(compTypeList, DataConstraintModel.typeTuple); - } - } - if (argType != newTupleType && newTupleType != null) { - if (arg instanceof Variable) { - ((Variable) arg).setType(newTupleType); - argType = newTupleType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newTupleType); - argType = newTupleType; - } - Map updateExps = getUpdateSet(updateFromTuple, tupleExps); - updateExps.put(System.identityHashCode(arg), arg); - } - tuple.put(System.identityHashCode(tupleExps), argType); - } else if (symbol.equals(DataConstraintModel.left)) { - // If the root symbol of the term is left. - List pairExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - pairExps.add(arg); - updateExpressionBelonging(expToPair, arg, pairExps); - pairExps.add(t); - updateExpressionBelonging(expToPair, t, pairExps); - pairExps.add(null); - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newPairType = DataConstraintModel.typePair; - if (argType == DataConstraintModel.typePair && t.getType() != null) { - List compTypeList = new ArrayList<>(); - compTypeList.add(t.getType()); - compTypeList.add(null); - newPairType = pairTypes.get(compTypeList); - if (newPairType == null) { - // Create new tuple type; - newPairType = createNewTupleType(compTypeList, DataConstraintModel.typePair); - } - } - if (argType != newPairType && newPairType != null) { - if (arg instanceof Variable) { - ((Variable) arg).setType(newPairType); - argType = newPairType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newPairType); - argType = newPairType; - } - Map updateExps = getUpdateSet(updateFromPair, pairExps); - updateExps.put(System.identityHashCode(arg), arg); - } - pair.put(System.identityHashCode(pairExps), argType); - } else if (symbol.equals(DataConstraintModel.right)) { - // If the root symbol of the term is right. - List pairExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - pairExps.add(arg); - updateExpressionBelonging(expToPair, arg, pairExps); - pairExps.add(null); - pairExps.add(t); - updateExpressionBelonging(expToPair, t, pairExps); - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newPairType = DataConstraintModel.typePair; - if (argType == DataConstraintModel.typePair && t.getType() != null) { - List compTypeList = new ArrayList<>(); - compTypeList.add(null); - compTypeList.add(t.getType()); - newPairType = pairTypes.get(compTypeList); - if (newPairType == null) { - // Create new tuple type; - newPairType = createNewTupleType(compTypeList, DataConstraintModel.typePair); - } - } - if (argType != newPairType && newPairType != null) { - if (arg instanceof Variable) { - ((Variable) arg).setType(newPairType); - argType = newPairType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newPairType); - argType = newPairType; - } - Map updateExps = getUpdateSet(updateFromPair, pairExps); - updateExps.put(System.identityHashCode(arg), arg); - } - pair.put(System.identityHashCode(pairExps), argType); - } else if (symbol.equals(DataConstraintModel.lookup)) { - // If the root symbol of the term is lookup. - List mapExps = new ArrayList<>(); - Expression arg1 = t.getChildren().get(0); // map - mapExps.add(arg1); - updateExpressionBelonging(expToMap, arg1, mapExps); - Expression arg2 = t.getChildren().get(1); // key - mapExps.add(arg2); - updateExpressionBelonging(expToMap, arg2, mapExps); - mapExps.add(t); // value - updateExpressionBelonging(expToMap, t, mapExps); - Type arg1Type = null; - if (arg1 instanceof Variable) { - arg1Type = ((Variable) arg1).getType(); - } else if (arg1 instanceof Term) { - arg1Type = ((Term) arg1).getType(); - } - List compTypeList = new ArrayList<>(); - if (arg2 instanceof Variable) { - compTypeList.add(((Variable) arg2).getType()); - } else if (arg2 instanceof Term) { - compTypeList.add(((Term) arg2).getType()); - } else { - compTypeList.add(null); - } - compTypeList.add(t.getType()); - if (arg1Type == DataConstraintModel.typeMap || arg1Type == null) { - Type newMapType = mapTypes.get(compTypeList); - if (newMapType == null) { - // Create new tuple type; - newMapType = createNewMapType(compTypeList, DataConstraintModel.typeMap); - } - if (arg1 instanceof Variable) { - ((Variable) arg1).setType(newMapType); - arg1Type = newMapType; - } else if (arg1 instanceof Term) { - ((Term) arg1).setType(newMapType); - arg1Type = newMapType; - } - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(arg1), arg1); - } - map.put(System.identityHashCode(mapExps), arg1Type); - } else if (symbol.equals(DataConstraintModel.insert)) { - // If the root symbol of the term is insert. - List mapExps = new ArrayList<>(); - mapExps.add(t); // map - updateExpressionBelonging(expToMap, t, mapExps); - Expression arg1 = t.getChildren().get(1); // key - mapExps.add(arg1); - updateExpressionBelonging(expToMap, arg1, mapExps); - Expression arg2 = t.getChildren().get(2); // value - mapExps.add(arg2); - updateExpressionBelonging(expToMap, arg2, mapExps); - Expression arg0 = t.getChildren().get(0); // map - mapExps.add(arg0); - updateExpressionBelonging(expToMap, arg0, mapExps); - Type termType = t.getType(); - List compTypeList = new ArrayList<>(); - if (arg1 instanceof Variable) { - compTypeList.add(((Variable) arg1).getType()); - } else if (arg1 instanceof Term) { - compTypeList.add(((Term) arg1).getType()); - } else { - compTypeList.add(null); - } - if (arg2 instanceof Variable) { - compTypeList.add(((Variable) arg2).getType()); - } else if (arg2 instanceof Term) { - compTypeList.add(((Term) arg2).getType()); - } else { - compTypeList.add(null); - } - if (termType == DataConstraintModel.typeMap || termType == null) { - Type newMapType = mapTypes.get(compTypeList); - if (newMapType == null) { - // Create new tuple type; - newMapType = createNewMapType(compTypeList, DataConstraintModel.typeMap); - } - t.setType(newMapType); - termType = newMapType; - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(t), t); - } - map.put(System.identityHashCode(mapExps), termType); - } else if (symbol.equals(DataConstraintModel.cond)) { - // If the root symbol of the term is if function. - Expression c1 = t.getChild(1); - Expression c2 = t.getChild(2); - List condTerms = new ArrayList<>(); - condTerms.add(t); - condTerms.add(c1); - condTerms.add(c2); - expToVariable.put(System.identityHashCode(t), condTerms); - expToVariable.put(System.identityHashCode(c1), condTerms); - expToVariable.put(System.identityHashCode(c2), condTerms); - Type condType = t.getType(); - Map updatedVars = getUpdateSet(updateFromVariable, condTerms); - Type child1Type = getExpTypeIfUpdatable(condType, c1); - if (child1Type != null) { - condType = child1Type; - t.setType(child1Type); - updatedVars.put(System.identityHashCode(t), t); - } else { - if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), condType)) { - ((Variable) c1).setType(condType); - updatedVars.put(System.identityHashCode(c1), c1); - } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), condType)) { - ((Term) c1).setType(condType); - updatedVars.put(System.identityHashCode(c1), c1); - } - } - Type child2Type = getExpTypeIfUpdatable(condType, c2); - if (child2Type != null) { - condType = child2Type; - t.setType(child2Type); - updatedVars.put(System.identityHashCode(t), t); - if (c1 instanceof Variable) { - ((Variable) c1).setType(child2Type); - updatedVars.put(System.identityHashCode(c1), c1); - } else if (c1 instanceof Term) { - ((Term) c1).setType(child2Type); - updatedVars.put(System.identityHashCode(c1), c1); - } - } else { - if (c2 instanceof Variable && compareTypes(((Variable) c2).getType(), condType)) { - ((Variable) c2).setType(condType); - updatedVars.put(System.identityHashCode(c2), c2); - } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), condType)) { - ((Term) c2).setType(condType); - updatedVars.put(System.identityHashCode(c2), c2); - } - } - variables.put(System.identityHashCode(condTerms), condType); - } else if (symbol.equals(DataConstraintModel.add) || symbol.equals(DataConstraintModel.sub) - || symbol.equals(DataConstraintModel.mul) || symbol.equals(DataConstraintModel.div)) { - // If the root symbol of the term is arithmetic operators. - Expression c1 = t.getChild(0); - Expression c2 = t.getChild(1); - List operands = new ArrayList<>(); - operands.add(t); - operands.add(c1); - operands.add(c2); - expToVariable.put(System.identityHashCode(t), operands); - expToVariable.put(System.identityHashCode(c1), operands); - expToVariable.put(System.identityHashCode(c2), operands); - Type opType = t.getType(); - Map updatedVars = getUpdateSet(updateFromVariable, operands); - Type child1Type = getExpTypeIfUpdatable(opType, c1); - if (child1Type != null) { - opType = child1Type; - t.setType(child1Type); - updatedVars.put(System.identityHashCode(t), t); - } else { - if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), opType)) { - ((Variable) c1).setType(opType); - updatedVars.put(System.identityHashCode(c1), c1); - } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), opType)) { - ((Term) c1).setType(opType); - updatedVars.put(System.identityHashCode(c1), c1); - } - } - Type child2Type = getExpTypeIfUpdatable(opType, c2); - if (child2Type != null) { - opType = child2Type; - t.setType(child2Type); - updatedVars.put(System.identityHashCode(t), t); - if (c1 instanceof Variable) { - ((Variable) c1).setType(child2Type); - updatedVars.put(System.identityHashCode(c1), c1); - } else if (c1 instanceof Term) { - ((Term) c1).setType(child2Type); - updatedVars.put(System.identityHashCode(c1), c1); - } - } else { - if (c2 instanceof Variable && compareTypes(((Variable) c2).getType(), opType)) { - ((Variable) c2).setType(opType); - updatedVars.put(System.identityHashCode(c2), c2); - } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), opType)) { - ((Term) c2).setType(opType); - updatedVars.put(System.identityHashCode(c2), c2); - } - } - variables.put(System.identityHashCode(operands), opType); - } else if (symbol.getSignature() != null - && symbol.getSignature()[0] == DataConstraintModel.typeList) { - // If the root symbol of the term is the list type (except for the cons - // function). - List consExps = new ArrayList<>(); - consExps.add(t); - expToVariable.put(System.identityHashCode(t), consExps); - Type condType = t.getType(); - Map updatedVars = getUpdateSet(updateFromVariable, consExps); - for (int i = 1; i < symbol.getSignature().length; i++) { - Type tc = symbol.getSignature()[i]; - if (tc == DataConstraintModel.typeList) { - Expression e = t.getChildren().get(i - 1); - Type newType = getExpTypeIfUpdatable(condType, e); - if (newType != null) { - condType = newType; - for (Expression e2 : consExps) { - if (e2 instanceof Variable) { - ((Variable) e2).setType(newType); - updatedVars.put(System.identityHashCode(e2), e2); - } else if (e2 instanceof Term) { - ((Term) e2).setType(newType); - updatedVars.put(System.identityHashCode(e2), e2); - } - } - } else { - if (e instanceof Variable && compareTypes(((Variable) e).getType(), condType)) { - ((Variable) e).setType(condType); - updatedVars.put(System.identityHashCode(e), e); - } else if (e instanceof Term && compareTypes(((Term) e).getType(), condType)) { - ((Term) e).setType(condType); - updatedVars.put(System.identityHashCode(e), e); - } - } - consExps.add(e); - expToVariable.put(System.identityHashCode(e), consExps); - } - } - variables.put(System.identityHashCode(consExps), condType); - } - } - } - } - - // 2. Propagate type information. - while (updateFromResource.size() > 0 || updateFromVariable.size() > 0 || updateFromMessage.size() > 0 - || updateFromConsOrSet.size() > 0 || updateFromTuple.size() > 0 || updateFromPair.size() > 0 || updateFromMap.size() > 0) { - if (updateFromResource.size() > 0) { - Set resourceKeys = updateFromResource.keySet(); - Integer resourceKey = resourceKeys.iterator().next(); - Map resourceValue = updateFromResource.get(resourceKey); - updateFromResource.remove(resourceKey); - for (int i : resourceValue.keySet()) { - Expression resExp = resourceValue.get(i); - updateVaribleTypes(resExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(resExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(resExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(resExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(resExp, pair, expToPair, updateFromPair); - updateMapTypes(resExp, map, expToMap, updateFromMap); - } - } - if (updateFromVariable.size() > 0) { - Set variableKeys = updateFromVariable.keySet(); - Integer variableKey = variableKeys.iterator().next(); - Map variableValue = updateFromVariable.get(variableKey); - updateFromVariable.remove(variableKey); - for (int i : variableValue.keySet()) { - Expression var = variableValue.get(i); - updateResourceTypes(var, resources, expToResource, updateFromResource); - updateVaribleTypes(var, variables, expToVariable, updateFromVariable); - updateMessageTypes(var, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(var, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(var, tuple, expToTuple, updateFromTuple); - updatePairTypes(var, pair, expToPair, updateFromPair); - updateMapTypes(var, map, expToMap, updateFromMap); - } - } - if (updateFromMessage.size() > 0) { - Set messageKeys = updateFromMessage.keySet(); - Integer messageKey = messageKeys.iterator().next(); - Map messageValue = updateFromMessage.get(messageKey); - updateFromMessage.remove(messageKey); - for (int i : messageValue.keySet()) { - Expression mesExp = messageValue.get(i); - updateResourceTypes(mesExp, resources, expToResource, updateFromResource); - updateVaribleTypes(mesExp, variables, expToVariable, updateFromVariable); - updateConsOrSetTypes(mesExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(mesExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(mesExp, pair, expToPair, updateFromPair); - updateMapTypes(mesExp, map, expToMap, updateFromMap); - } - } - if (updateFromConsOrSet.size() > 0) { - Set consKeys = updateFromConsOrSet.keySet(); - Integer consKey = consKeys.iterator().next(); - Map consValue = updateFromConsOrSet.get(consKey); - updateFromConsOrSet.remove(consKey); - for (int i : consValue.keySet()) { - Expression consExp = consValue.get(i); - updateResourceTypes(consExp, resources, expToResource, updateFromResource); - updateVaribleTypes(consExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(consExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(consExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(consExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(consExp, pair, expToPair, updateFromPair); - updateMapTypes(consExp, map, expToMap, updateFromMap); - } - } - if (updateFromTuple.size() > 0) { - Set tupleKeys = updateFromTuple.keySet(); - Integer tupleKey = tupleKeys.iterator().next(); - Map tupleValue = updateFromTuple.get(tupleKey); - updateFromTuple.remove(tupleKey); - for (int i : tupleValue.keySet()) { - Expression tupleExp = tupleValue.get(i); - updateResourceTypes(tupleExp, resources, expToResource, updateFromResource); - updateVaribleTypes(tupleExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(tupleExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(tupleExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(tupleExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(tupleExp, pair, expToPair, updateFromPair); - updateMapTypes(tupleExp, map, expToMap, updateFromMap); - } - } - if (updateFromPair.size() > 0) { - Set pairKeys = updateFromPair.keySet(); - Integer pairKey = pairKeys.iterator().next(); - Map pairValue = updateFromPair.get(pairKey); - updateFromPair.remove(pairKey); - for (int i : pairValue.keySet()) { - Expression pairExp = pairValue.get(i); - updateResourceTypes(pairExp, resources, expToResource, updateFromResource); - updateVaribleTypes(pairExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(pairExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(pairExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(pairExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(pairExp, pair, expToPair, updateFromPair); - updateMapTypes(pairExp, map, expToMap, updateFromMap); - } - } - if (updateFromMap.size() > 0) { - Set mapKeys = updateFromMap.keySet(); - Integer mapKey = mapKeys.iterator().next(); - Map mapValue = updateFromMap.get(mapKey); - updateFromMap.remove(mapKey); - for (int i : mapValue.keySet()) { - Expression mapExp = mapValue.get(i); - updateResourceTypes(mapExp, resources, expToResource, updateFromResource); - updateVaribleTypes(mapExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(mapExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(mapExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(mapExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(mapExp, pair, expToPair, updateFromPair); - updateMapTypes(mapExp, map, expToMap, updateFromMap); - } - } - } - } - - private static void updateExpressionBelonging(Map>> belonging, Expression exp, List group) { - Set> groups = belonging.get(System.identityHashCode(exp)); - if (groups == null) { - groups = new HashSet<>(); - belonging.put(System.identityHashCode(exp), groups); - groups.add(group); - return; - } - if (!groups.contains(group)) { - groups.add(group); - } - } - - private static void updateResourceTypes(Expression exp, Map> resources, - Map> expToResource, Map> updateFromResource) { - List sameResource = expToResource.get(System.identityHashCode(exp)); - if (sameResource == null) return; - for (ResourcePath id : resources.keySet()) { - if (resources.get(id) == sameResource) { - Type resType = id.getResourceStateType(); - Type newResType = getExpTypeIfUpdatable(resType, exp); - if (newResType != null) { - id.setResourceStateType(newResType); - Map updateExps = getUpdateSet(updateFromResource, sameResource); - for (Expression resExp : sameResource) { - if (resExp != exp) { - if (resExp instanceof Variable) { - ((Variable) resExp).setType(newResType); - updateExps.put(System.identityHashCode(resExp), resExp); - } else if (resExp instanceof Term) { - ((Term) resExp).setType(newResType); - updateExps.put(System.identityHashCode(resExp), resExp); - } - } - } - } - } - } - } - - private static void updateVaribleTypes(Expression exp, Map variables, - Map> expToVariable, Map> updateFromVariable) { - List sameVariable = expToVariable.get(System.identityHashCode(exp)); - if (sameVariable == null) return; - Type varType = variables.get(System.identityHashCode(sameVariable)); - Type newVarType = getExpTypeIfUpdatable(varType, exp); - if (newVarType != null) { - variables.put(System.identityHashCode(sameVariable), newVarType); - Map updateVars = getUpdateSet(updateFromVariable, sameVariable); - for (Expression v : sameVariable) { - if (v != exp) { - if (v instanceof Variable) { - ((Variable) v).setType(newVarType); - updateVars.put(System.identityHashCode(v), v); - } else if (v instanceof Term) { - ((Term) v).setType(newVarType); - updateVars.put(System.identityHashCode(v), v); - } - } - } - } else { - Map updateVars = getUpdateSet(updateFromVariable, sameVariable); - for (Expression v : sameVariable) { - if (v instanceof Variable) { - Type orgVarType = ((Variable) v).getType(); - if (orgVarType != varType && compareTypes(orgVarType, varType)) { - ((Variable) v).setType(varType); - updateVars.put(System.identityHashCode(v), v); - } - } else if (v instanceof Term) { - Type orgVarType = ((Term) v).getType(); - if (orgVarType != varType && compareTypes(orgVarType, varType)) { - ((Term) v).setType(varType); - updateVars.put(System.identityHashCode(v), v); - } - } - } - } - } - - private static void updateMessageTypes(Expression exp, - Map, Type>>> messages, - Map> expToMessage, Map> updateFromMessage) { - List messageExps = expToMessage.get(System.identityHashCode(exp)); - if (messageExps == null) return; - Type msgType = null; - Map.Entry, Type> expsAndType = null; - for (Channel c : messages.keySet()) { - for (int i : messages.get(c).keySet()) { - expsAndType = messages.get(c).get(i); - if (expsAndType.getKey() == messageExps) { - msgType = expsAndType.getValue(); - break; - } - } - if (msgType != null) break; - } - if (msgType == null) return; - Type newMsgType = getExpTypeIfUpdatable(msgType, exp); - if (newMsgType != null) { - expsAndType.setValue(newMsgType); - Map updateExps = getUpdateSet(updateFromMessage, messageExps); - for (Expression e : messageExps) { - if (e != exp) { - if (e instanceof Variable) { - ((Variable) e).setType(newMsgType); - updateExps.put(System.identityHashCode(e), e); - } else if (e instanceof Term) { - ((Term) e).setType(newMsgType); - updateExps.put(System.identityHashCode(e), e); - } - } - } - } - } - - private static void updateConsOrSetTypes(Expression exp, Map consOrSet, - Map>> expToConsOrSet, Map> updateFromConsOrSet) { - Set> consComponentGroups = expToConsOrSet.get(System.identityHashCode(exp)); - if (consComponentGroups == null) return; - for (List consOrSetComponentGroup: consComponentGroups) { - int idx = consOrSetComponentGroup.indexOf(exp); - switch (idx) { - case 0: - if (!(exp instanceof Term)) break; - Type listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); - Type expType = getExpTypeIfUpdatable(listType, exp); - if (expType != null) { - consOrSet.put(System.identityHashCode(consOrSetComponentGroup), expType); - Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); - if (consOrSetComponentGroup.get(2) instanceof Variable) { - ((Variable) consOrSetComponentGroup.get(2)).setType(expType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); - } else if (consOrSetComponentGroup.get(2) instanceof Term) { - ((Term) consOrSetComponentGroup.get(2)).setType(expType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); - } - Type compType = listComponentTypes.get(expType); - if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Variable) { - ((Variable) consOrSetComponentGroup.get(1)).setType(compType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); - } else if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Term) { - ((Term) consOrSetComponentGroup.get(1)).setType(compType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); - } - } - break; - case 1: - listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); - Type compType = listComponentTypes.get(listType); - Type newCompType = getExpTypeIfUpdatable(compType, exp); - if (newCompType != null) { - Type newListType = listTypes.get(newCompType); - if (newListType == null) { - // Create new list type. - newListType = createNewListType(newCompType, listType); - } - consOrSet.put(System.identityHashCode(consOrSetComponentGroup), newListType); - Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); - if (consOrSetComponentGroup.get(0) instanceof Term) { - ((Term) consOrSetComponentGroup.get(0)).setType(newListType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(0)), consOrSetComponentGroup.get(0)); - } - if (consOrSetComponentGroup.get(2) instanceof Variable) { - ((Variable) consOrSetComponentGroup.get(2)).setType(newListType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); - } else if (consOrSetComponentGroup.get(2) instanceof Term) { - ((Term) consOrSetComponentGroup.get(2)).setType(newListType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); - } - } - break; - case 2: - listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); - expType = getExpTypeIfUpdatable(listType, exp); - if (expType != null) { - consOrSet.put(System.identityHashCode(consOrSetComponentGroup), expType); - Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); - if (consOrSetComponentGroup.get(0) instanceof Term) { - ((Term) consOrSetComponentGroup.get(0)).setType(expType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(0)), consOrSetComponentGroup.get(0)); - } - compType = listComponentTypes.get(expType); - if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Variable) { - ((Variable) consOrSetComponentGroup.get(1)).setType(compType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); - } else if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Term) { - ((Term) consOrSetComponentGroup.get(1)).setType(compType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); - } - } - } - } - } - - private static void updateTupleTypes(Expression exp, Map tuple, - Map>> expToTuple, Map> updateFromTuple) { - Set> tupleComponentGroups = expToTuple.get(System.identityHashCode(exp)); - if (tupleComponentGroups == null) return; - for (List tupleComponentGroup: tupleComponentGroups) { - int idx = tupleComponentGroup.indexOf(exp); - if (idx == 0) { - Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); - Type newTupleType = getExpTypeIfUpdatable(tupleType, exp); - if (newTupleType != null) { - // Propagate an update of a tuple's type to its components' types. - tuple.put(System.identityHashCode(tupleComponentGroup), newTupleType); - List componentTypes = tupleComponentTypes.get(newTupleType); - Map updateExps = getUpdateSet(updateFromTuple, tupleComponentGroup); - for (int i = 1; i < tupleComponentGroup.size(); i++) { - Expression compExp = tupleComponentGroup.get(i); - if (compExp instanceof Variable) { - Type compType = ((Variable) compExp).getType(); - if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { - // If the type of one component (compExp) is also tuple. - Type newExpType = tupleTypes.get(componentTypes.subList(i - 1, componentTypes.size())); - if (newExpType == null) { - // Create new tuple type; - newExpType = createNewTupleType(componentTypes.subList(i - 1, componentTypes.size()), compType); - } - if (compareTypes(compType, newExpType)) { - ((Variable) compExp).setType(newExpType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else { - if (i - 1 < componentTypes.size()) { - if (compareTypes(compType, componentTypes.get(i - 1))) { - ((Variable) compExp).setType(componentTypes.get(i - 1)); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else { - // for insert - if (compareTypes(compType, newTupleType)) { - ((Variable) compExp).setType(newTupleType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } - } - } else if (compExp instanceof Term) { - Type compType = ((Term) compExp).getType(); - if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { - // If the type of one component (compExp) is also tuple. - Type newExpType = tupleTypes.get(componentTypes.subList(i - 1, componentTypes.size())); - if (newExpType == null) { - // Create new tuple type; - newExpType = createNewTupleType(componentTypes.subList(i - 1, componentTypes.size()), compType); - } - if (compareTypes(compType, newExpType)) { - ((Term) compExp).setType(newExpType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else { - if (i - 1 < componentTypes.size()) { - if (compareTypes(compType, componentTypes.get(i - 1))) { - ((Term) compExp).setType(componentTypes.get(i - 1)); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else { - // for insert - if (compareTypes(compType, newTupleType)) { - ((Term) compExp).setType(newTupleType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } - } - } - } - } - } else { - Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); - List componentTypes = tupleComponentTypes.get(tupleType); - boolean updated = false; - if (idx == 1) { - Type compType = componentTypes.get(idx - 1); - Type newCompType = getExpTypeIfUpdatable(compType, exp); - if (newCompType != null) { - componentTypes = new ArrayList<>(componentTypes); - componentTypes.set(idx - 1, newCompType); - updated = true; - } - } else { - Type expType = null; - if (exp instanceof Term) { - expType = ((Term) exp).getType(); - } else if (exp instanceof Variable) { - expType = ((Variable) exp).getType(); - } - if (expType != null && DataConstraintModel.typeTuple.isAncestorOf(expType)) { - // If the type of the updated component (exp) is also tuple. - List subCompTypes = tupleComponentTypes.get(expType); - componentTypes = new ArrayList<>(componentTypes); - for (int i = 0; i < subCompTypes.size(); i++) { - if (componentTypes.size() < i + 2) { - componentTypes.add(subCompTypes.get(i)); - updated = true; - } else if (compareTypes(componentTypes.get(i + 1), subCompTypes.get(i))) { - componentTypes.set(i + 1, subCompTypes.get(i)); - updated = true; - } - } - } else { - Type compType = componentTypes.get(idx - 1); - Type newCompType = getExpTypeIfUpdatable(compType, exp); - if (newCompType != null) { - componentTypes = new ArrayList<>(componentTypes); - componentTypes.set(idx - 1, newCompType); - updated = true; - } - } - } - if (updated) { - // Propagate an update of a component's type to its container's (tuple's) type. - Type newTupleType = tupleTypes.get(componentTypes); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(componentTypes, tupleType); - } - Map updateExps = getUpdateSet(updateFromTuple, tupleComponentGroup); - Expression tupleExp = tupleComponentGroup.get(0); - if (tupleExp instanceof Variable) { - ((Variable) tupleExp).setType(newTupleType); - updateExps.put(System.identityHashCode(tupleExp), tupleExp); - } else if (tupleExp instanceof Term) { - ((Term) tupleExp).setType(newTupleType); - updateExps.put(System.identityHashCode(tupleExp), tupleExp); - } - tuple.put(System.identityHashCode(tupleComponentGroup), newTupleType); - } - } - } - } - - private static void updatePairTypes(Expression exp, Map pair, - Map>> expToPair, Map> updateFromPair) { - Set> pairComponentGroups = expToPair.get(System.identityHashCode(exp)); - if (pairComponentGroups == null) return; - for (List pairComponentGroup: pairComponentGroups) { - int idx = pairComponentGroup.indexOf(exp); - if (idx == 0) { - Type pairType = pair.get(System.identityHashCode(pairComponentGroup)); - Type newPairType = getExpTypeIfUpdatable(pairType, exp); - if (newPairType != null) { - // Propagate an update of a pair's type to its components' types. - pair.put(System.identityHashCode(pairComponentGroup), newPairType); - Type componentType = pairComponentTypes.get(newPairType); - Map updateExps = getUpdateSet(updateFromPair, pairComponentGroup); - for (int i = 1; i < pairComponentGroup.size(); i++) { - Expression compExp = pairComponentGroup.get(i); - if (compExp instanceof Variable) { - if (compareTypes(((Variable) compExp).getType(), componentType)) { - ((Variable) compExp).setType(componentType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else if (compExp instanceof Term) { - if (compareTypes(((Term) compExp).getType(), componentType)) { - ((Term) compExp).setType(componentType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } - } - } - } else { - Type pairType = pair.get(System.identityHashCode(pairComponentGroup)); - Type compType = pairComponentTypes.get(pairType); - Type newCompType = getExpTypeIfUpdatable(compType, exp); - if (newCompType != null) { - // Propagate an update of a component's type to its container's (pair's) type. - Type newPairType = pairTypes.get(compType); - if (newPairType != null) { - Map updateExps = getUpdateSet(updateFromPair, pairComponentGroup); - Expression pairExp = pairComponentGroup.get(0); - if (pairExp instanceof Variable) { - ((Variable) pairExp).setType(newPairType); - updateExps.put(System.identityHashCode(pairExp), pairExp); - } else if (pairExp instanceof Term) { - ((Term) pairExp).setType(newPairType); - updateExps.put(System.identityHashCode(pairExp), pairExp); - } - pair.put(System.identityHashCode(pairComponentGroup), newPairType); - } - } - } - } - } - - private static void updateMapTypes(Expression exp, Map map, - Map>> expToMap, Map> updateFromMap) { - Set> mapComponentGroups = expToMap.get(System.identityHashCode(exp)); - if (mapComponentGroups == null) return; - for (List mapComponentGroup: mapComponentGroups) { - int idx = mapComponentGroup.indexOf(exp); - if (idx == 0 || idx == 3) { - Type mapType = map.get(System.identityHashCode(mapComponentGroup)); - Type newMapType = getExpTypeIfUpdatable(mapType, exp); - if (newMapType != null) { - // Propagate an update of a map's type to its components' types. - map.put(System.identityHashCode(mapComponentGroup), newMapType); - List componentTypes = mapComponentTypes.get(newMapType); - Map updateExps = getUpdateSet(updateFromMap, mapComponentGroup); - for (int i = 1; i < mapComponentGroup.size() && i < 3; i++) { - Expression compExp = mapComponentGroup.get(i); - if (compExp instanceof Variable) { - if (compareTypes(((Variable) compExp).getType(), componentTypes.get(i - 1))) { - ((Variable) compExp).setType(componentTypes.get(i - 1)); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else if (compExp instanceof Term) { - if (compareTypes(((Term) compExp).getType(), componentTypes.get(i - 1))) { - ((Term) compExp).setType(componentTypes.get(i - 1)); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } - } - // Propagate an update of a map's type to another map's type. - Expression compExp = null; - if (idx == 0 && mapComponentGroup.size() == 4) { // for insert - compExp = mapComponentGroup.get(3); - } else if (idx == 3) { - compExp = mapComponentGroup.get(0); - } - if (compExp != null) { - if (compExp instanceof Variable) { - if (compareTypes(((Variable) compExp).getType(), newMapType)) { - ((Variable) compExp).setType(newMapType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else if (compExp instanceof Term) { - if (compareTypes(((Term) compExp).getType(), newMapType)) { - ((Term) compExp).setType(newMapType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } - } - } - } else { - Type mapType = map.get(System.identityHashCode(mapComponentGroup)); - List componentTypes = mapComponentTypes.get(mapType); - Type compType = componentTypes.get(idx - 1); - Type newCompType = getExpTypeIfUpdatable(compType, exp); - if (newCompType != null) { - // Propagate an update of a component's type to its container's (map's) type. - componentTypes = new ArrayList<>(componentTypes); - componentTypes.set(idx - 1, newCompType); - Type newMapType = mapTypes.get(componentTypes); - if (newMapType == null) { - // Create new map type; - newMapType = createNewMapType(componentTypes, mapType); - } - Map updateExps = getUpdateSet(updateFromMap, mapComponentGroup); - Expression mapExp = mapComponentGroup.get(0); - if (mapExp instanceof Variable) { - ((Variable) mapExp).setType(newMapType); - updateExps.put(System.identityHashCode(mapExp), mapExp); - } else if (mapExp instanceof Term) { - ((Term) mapExp).setType(newMapType); - updateExps.put(System.identityHashCode(mapExp), mapExp); - } - if (mapComponentGroup.size() == 4) { // for insert - mapExp = mapComponentGroup.get(3); - if (mapExp instanceof Variable) { - ((Variable) mapExp).setType(newMapType); - updateExps.put(System.identityHashCode(mapExp), mapExp); - } else if (mapExp instanceof Term) { - ((Term) mapExp).setType(newMapType); - updateExps.put(System.identityHashCode(mapExp), mapExp); - } - } - map.put(System.identityHashCode(mapComponentGroup), newMapType); - } - } - } - } - - private static Type createNewListType(Type compType, Type parentType) { - String compTypeName = getInterfaceTypeName(compType); - List childrenTypes = getChildrenTypes(parentType, listComponentTypes.keySet()); - Type newListType = new Type("List", "ArrayList<>", "List<" + compTypeName + ">", parentType); - listTypes.put(compType, newListType); - listComponentTypes.put(newListType, compType); - for (Type childType : childrenTypes) { - if (compareTypes(childType, newListType)) { - if (newListType.getParentTypes().contains(parentType)) { - newListType.replaceParentType(parentType, childType); - } else { - newListType.addParentType(childType); - } - } else if (compareTypes(newListType, childType)) { - childType.replaceParentType(parentType, newListType); - } - } - return newListType; - } - - private static Type createNewTupleType(List componentTypes, Type parentTupleType) { - String implTypeName = "AbstractMap.SimpleEntry<>"; - String interfaceTypeName = "Map.Entry<$x>"; - if (componentTypes.size() >= 2) { - implTypeName = implTypeName.replace("$x", getImplementationTypeName(componentTypes.get(0)) + "$x"); - interfaceTypeName = interfaceTypeName.replace("$x", getInterfaceTypeName(componentTypes.get(0)) + "$x"); - for (Type argType : componentTypes.subList(1, componentTypes.size() - 1)) { - implTypeName = implTypeName.replace("$x", - ", AbstractMap.SimpleEntry<" + getImplementationTypeName(argType) + "$x>"); - interfaceTypeName = interfaceTypeName.replace("$x", - ", Map.Entry<" + getInterfaceTypeName(argType) + "$x>"); - } - implTypeName = implTypeName.replace("$x", - ", " + getImplementationTypeName(componentTypes.get(componentTypes.size() - 1))); - interfaceTypeName = interfaceTypeName.replace("$x", - ", " + getInterfaceTypeName(componentTypes.get(componentTypes.size() - 1))); - } - List childrenTypes = getChildrenTypes(parentTupleType, tupleComponentTypes.keySet()); - Type newTupleType = new Type("Tuple", implTypeName, interfaceTypeName, parentTupleType); - tupleTypes.put(componentTypes, newTupleType); - tupleComponentTypes.put(newTupleType, componentTypes); - for (Type childType : childrenTypes) { - if (compareTypes(childType, newTupleType)) { - if (newTupleType.getParentTypes().contains(parentTupleType)) { - newTupleType.replaceParentType(parentTupleType, childType); - } else { - newTupleType.addParentType(childType); - } - } else if (compareTypes(newTupleType, childType)) { - childType.replaceParentType(parentTupleType, newTupleType); - } - } - return newTupleType; - } - - private static Type createNewMapType(List componentTypes, Type parentMapType) { - String implTypeName = "HashMap<>"; - String interfaceTypeName = "Map<$x, $y>"; - if (componentTypes.size() == 2) { - implTypeName = implTypeName.replace("$x", getImplementationTypeName(componentTypes.get(0))); - interfaceTypeName = interfaceTypeName.replace("$x", getInterfaceTypeName(componentTypes.get(0))); - implTypeName = implTypeName.replace("$y", getImplementationTypeName(componentTypes.get(1))); - interfaceTypeName = interfaceTypeName.replace("$y", getInterfaceTypeName(componentTypes.get(1))); - } - List childrenTypes = getChildrenTypes(parentMapType, mapComponentTypes.keySet()); - Type newMapType = new Type("Map", implTypeName, interfaceTypeName, parentMapType); - mapTypes.put(componentTypes, newMapType); - mapComponentTypes.put(newMapType, componentTypes); - for (Type childType : childrenTypes) { - if (compareTypes(childType, newMapType)) { - if (newMapType.getParentTypes().contains(parentMapType)) { - newMapType.replaceParentType(parentMapType, childType); - } else { - newMapType.addParentType(childType); - } - } else if (compareTypes(newMapType, childType)) { - childType.replaceParentType(parentMapType, newMapType); - } - } - return newMapType; - } - - private static List getChildrenTypes(Type parentType, Set componentTypes) { - List childrenTypes = new ArrayList<>(); - for (Type childType : componentTypes) { - if (childType.getParentTypes().contains(parentType)) { - childrenTypes.add(childType); - } - } - return childrenTypes; - } - - private static String getImplementationTypeName(Type type) { - if (type == null) - return "Object"; - String wrapperType = DataConstraintModel.getWrapperType(type); - if (wrapperType != null) - return wrapperType; - return type.getImplementationTypeName(); - } - - private static String getInterfaceTypeName(Type type) { - if (type == null) - return "Object"; - String wrapperType = DataConstraintModel.getWrapperType(type); - if (wrapperType != null) - return wrapperType; - return type.getInterfaceTypeName(); - } - - private static > Map getUpdateSet( - Map> updateSets, U keySet) { - Map updatedExps = updateSets.get(System.identityHashCode(keySet)); - if (updatedExps == null) { - updatedExps = new HashMap<>(); - updateSets.put(System.identityHashCode(keySet), updatedExps); - } - return updatedExps; - } - - private static Type getExpTypeIfUpdatable(Type originalType, Expression newExp) { - Type expType = null; - if (newExp instanceof Term) { - expType = ((Term) newExp).getType(); - } else if (newExp instanceof Variable) { - expType = ((Variable) newExp).getType(); - } - if (compareTypes(originalType, expType)) { - return expType; - } - return null; - } - - /** - * Is an given original type an ancestor of a given new type? - * - * @param originalType original type - * @param newType new type (may not have been registered) - * @return true: if the original type equals to the new type or is an ancestor - * of the new type, false: otherwise - */ - private static boolean compareTypes(Type originalType, Type newType) { - if (originalType == null) return true; - if (originalType != newType && newType != null) { - if (originalType.isAncestorOf(newType)) return true; - if (newType.isAncestorOf(originalType)) return false; - if (DataConstraintModel.typeMap.isAncestorOf(originalType) - && DataConstraintModel.typeMap.isAncestorOf(newType)) { - List originalCompTypes = mapComponentTypes.get(originalType); - List newCompTypes = mapComponentTypes.get(newType); - if (originalCompTypes == null) return true; - for (int i = 0; i < originalCompTypes.size(); i++) { - if (originalCompTypes.get(i) != null && - (newCompTypes.get(i) == null || !originalCompTypes.get(i).isAncestorOf(newCompTypes.get(i)))) return false; - } - return true; - } - if (DataConstraintModel.typeTuple.isAncestorOf(originalType) - && DataConstraintModel.typeTuple.isAncestorOf(newType)) { - List originalCompTypes = tupleComponentTypes.get(originalType); - List newCompTypes = tupleComponentTypes.get(newType); - if (originalCompTypes == null) return true; - originalCompTypes = new ArrayList<>(originalCompTypes); - newCompTypes = new ArrayList<>(newCompTypes); - for (int i = 0; i < originalCompTypes.size(); i++) { - if (originalCompTypes.get(i) != null) { - if (DataConstraintModel.typeTuple.isAncestorOf(originalCompTypes.get(i))) { - Type tupleType = originalCompTypes.remove(i); - for (Type t: tupleComponentTypes.get(tupleType)) { - originalCompTypes.add(t); - } - } - if (newCompTypes.size() - 1 < i) return false; - if (newCompTypes.get(i) != null && DataConstraintModel.typeTuple.isAncestorOf(newCompTypes.get(i))) { - Type tupleType = newCompTypes.remove(i); - for (Type t: tupleComponentTypes.get(tupleType)) { - newCompTypes.add(t); - } - } - if (newCompTypes.get(i) == null || !originalCompTypes.get(i).isAncestorOf(newCompTypes.get(i))) return false; - } - } - return true; - } - if (DataConstraintModel.typeList.isAncestorOf(originalType) - && DataConstraintModel.typeList.isAncestorOf(newType)) { - Type originalCompType = listComponentTypes.get(originalType); - Type newCompType = listComponentTypes.get(newType); - if (originalCompType != null && (newCompType == null || !originalCompType.isAncestorOf(newCompType))) return false; - return true; - } - } - return false; - } -} diff --git a/AlgebraicDataflowArchitectureModel/src/application/ApplicationMenuBar.java b/AlgebraicDataflowArchitectureModel/src/application/ApplicationMenuBar.java index 38e2370..8ee36b5 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/ApplicationMenuBar.java +++ b/AlgebraicDataflowArchitectureModel/src/application/ApplicationMenuBar.java @@ -1,94 +1,86 @@ package application; -import javax.swing.JMenu; -import javax.swing.JMenuBar; - -import application.actions.CircleLayoutAction; -import application.actions.DAGLayoutAction; -import application.actions.DeleteAction; -import application.actions.ExitAction; -import application.actions.JavaPrototypeGenerateAction; -import application.actions.JerseyPrototypeGenerateAction; -import application.actions.NewChannelAction; -import application.actions.NewFormulaChannelAction; -import application.actions.NewIOChannelAction; -import application.actions.NewModelAction; -import application.actions.NewResourceAction; -import application.actions.OpenAction; -import application.actions.SaveAction; -import application.actions.SaveAsAction; -import application.actions.TreeLayoutAction; -import application.actions.ZoomInAction; -import application.actions.ZoomOutAction; +import application.actions.*; import application.editor.Editor; +import javax.swing.*; + public class ApplicationMenuBar extends JMenuBar { - private static final long serialVersionUID = 4811536194182272888L; + private static final long serialVersionUID = 4811536194182272888L; - private ApplicationWindow applicationWindow = null; - - private NewResourceAction newResourceAction = null; - private NewChannelAction newChannelAction = null; - private NewIOChannelAction newIOChannelAction = null; - private NewFormulaChannelAction newFormulaChannelAction = null; - private DeleteAction deleteAction = null; - private JavaPrototypeGenerateAction javaPrototypeGenerateAction = null; - private JerseyPrototypeGenerateAction jerseyPrototypeGenerateAction = null; - private DAGLayoutAction dagLayoutAction = null; - private TreeLayoutAction treeLayoutAction = null; - private CircleLayoutAction circleLayoutAction = null; + private ApplicationWindow applicationWindow = null; - public ApplicationMenuBar(ApplicationWindow applicationWindow) { - this.applicationWindow = applicationWindow; - JMenu newMenu = new JMenu("New"); - - newMenu.add(new NewModelAction(applicationWindow)); - - newMenu.add(newResourceAction = new NewResourceAction(applicationWindow.getEditor())); - newMenu.add(newChannelAction = new NewChannelAction(applicationWindow.getEditor())); - newMenu.add(newIOChannelAction = new NewIOChannelAction(applicationWindow.getEditor())); - newMenu.add(newFormulaChannelAction = new NewFormulaChannelAction(applicationWindow.getEditor())); - - JMenu menu = null; - menu = add(new JMenu("File")); - menu.add(newMenu); - menu.add(new OpenAction(applicationWindow)); - menu.addSeparator(); - menu.add(new SaveAction(applicationWindow)); - menu.add(new SaveAsAction(applicationWindow)); - menu.addSeparator(); - menu.add(new ExitAction()); - - menu = add(new JMenu("Edit")); - menu.add(deleteAction = new DeleteAction(applicationWindow.getEditor())); + private NewResourceAction newResourceAction = null; + private NewChannelAction newChannelAction = null; + private NewEventChannelAction newIOChannelAction = null; + private NewFormulaChannelAction newFormulaChannelAction = null; + private DeleteAction deleteAction = null; + private JavaPrototypeGenerateAction javaPrototypeGenerateAction = null; + private JerseyPrototypeGenerateAction jerseyPrototypeGenerateAction = null; + private DAGLayoutAction dagLayoutAction = null; + private TreeLayoutAction treeLayoutAction = null; + private CircleLayoutAction circleLayoutAction = null; + private ShowNavigationAction showNavigationAction; + //private SimulateAction simulateAction = null; - menu = add(new JMenu("Layout")); - menu.add(dagLayoutAction = new DAGLayoutAction(applicationWindow.getEditor())); - menu.add(treeLayoutAction = new TreeLayoutAction(applicationWindow.getEditor())); - menu.add(circleLayoutAction = new CircleLayoutAction(applicationWindow.getEditor())); + public ApplicationMenuBar(ApplicationWindow applicationWindow) { + this.applicationWindow = applicationWindow; + JMenu newMenu = new JMenu("New"); - menu = add(new JMenu("View")); - menu.add(new ZoomInAction(applicationWindow.getGraphComponent())); - menu.add(new ZoomOutAction(applicationWindow.getGraphComponent())); + newMenu.add(new NewModelAction(applicationWindow)); - menu = add(new JMenu("Generate")); - menu.add(javaPrototypeGenerateAction = new JavaPrototypeGenerateAction(applicationWindow.getEditor())); - menu.add(jerseyPrototypeGenerateAction = new JerseyPrototypeGenerateAction(applicationWindow.getEditor())); - } + newMenu.add(newResourceAction = new NewResourceAction(applicationWindow.getEditor())); + newMenu.add(newChannelAction = new NewChannelAction(applicationWindow.getEditor())); + newMenu.add(newIOChannelAction = new NewEventChannelAction(applicationWindow.getEditor())); + newMenu.add(newFormulaChannelAction = new NewFormulaChannelAction(applicationWindow.getEditor())); - public Editor getEditor() { - return applicationWindow.getEditor(); - } + JMenu menu = null; + menu = add(new JMenu("File")); + menu.add(newMenu); + menu.add(new OpenAction(applicationWindow)); + menu.addSeparator(); + menu.add(new SaveAction(applicationWindow)); + menu.add(new SaveAsAction(applicationWindow)); + menu.addSeparator(); + menu.add(new ExitAction()); - public void setEditor(Editor editor) { - newResourceAction.setEditor(editor); - newChannelAction.setEditor(editor); - newIOChannelAction.setEditor(editor); - deleteAction.setEditor(editor); - javaPrototypeGenerateAction.setEditor(editor); - jerseyPrototypeGenerateAction.setEditor(editor); - treeLayoutAction.setEditor(editor); - circleLayoutAction.setEditor(editor); - } + menu = add(new JMenu("Edit")); + menu.add(deleteAction = new DeleteAction(applicationWindow.getEditor())); + + + menu = add(new JMenu("Layout")); + menu.add(dagLayoutAction = new DAGLayoutAction(applicationWindow.getEditor())); + menu.add(treeLayoutAction = new TreeLayoutAction(applicationWindow.getEditor())); + menu.add(circleLayoutAction = new CircleLayoutAction(applicationWindow.getEditor())); + + menu = add(new JMenu("View")); + menu.add(new ZoomInAction(applicationWindow.getGraphComponent())); + menu.add(new ZoomOutAction(applicationWindow.getGraphComponent())); + + menu = add(new JMenu("Simulate")); + menu.add(new SimulateAction(applicationWindow)); + + menu = add(new JMenu("Generate")); + menu.add(javaPrototypeGenerateAction = new JavaPrototypeGenerateAction(applicationWindow.getEditor())); + menu.add(jerseyPrototypeGenerateAction = new JerseyPrototypeGenerateAction(applicationWindow.getEditor())); + + menu = add(new JMenu("Window")); + menu.add(showNavigationAction = new ShowNavigationAction(applicationWindow)); + } + + public Editor getEditor() { + return applicationWindow.getEditor(); + } + + public void setEditor(Editor editor) { + newResourceAction.setEditor(editor); + newChannelAction.setEditor(editor); + newIOChannelAction.setEditor(editor); + deleteAction.setEditor(editor); + javaPrototypeGenerateAction.setEditor(editor); + jerseyPrototypeGenerateAction.setEditor(editor); + treeLayoutAction.setEditor(editor); + circleLayoutAction.setEditor(editor); + } } diff --git a/AlgebraicDataflowArchitectureModel/src/application/ApplicationWindow.java b/AlgebraicDataflowArchitectureModel/src/application/ApplicationWindow.java index 63324d0..794a44d 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/ApplicationWindow.java +++ b/AlgebraicDataflowArchitectureModel/src/application/ApplicationWindow.java @@ -1,97 +1,83 @@ package application; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.JFrame; - +import application.editor.Editor; +import application.views.NavigationWindow; import com.mxgraph.model.mxCell; import com.mxgraph.model.mxGeometry; import com.mxgraph.model.mxGraphModel; -import com.mxgraph.swing.mxGraphComponent; import com.mxgraph.swing.handler.mxRubberband; -import com.mxgraph.swing.view.mxICellEditor; +import com.mxgraph.swing.mxGraphComponent; import com.mxgraph.util.mxEvent; import com.mxgraph.util.mxEventObject; import com.mxgraph.util.mxEventSource.mxIEventListener; import com.mxgraph.view.mxGraph; -import application.editor.Editor; -import application.editor.DataTransferModelingCellEditor; +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; public class ApplicationWindow extends JFrame { - private static final long serialVersionUID = -8690140317781055614L; - public static final String title = "Visual Modeling Tool"; - - private Editor editor = null; - private mxGraph graph = null; - private mxGraphComponent graphComponent = null; - - private ApplicationMenuBar menuBar = null; + private static final long serialVersionUID = -8690140317781055614L; + public static final String title = "Visual Modeling Tool"; - public ApplicationWindow() { - setTitle(title); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - - this.graph = new mxGraph() { - public boolean isPort(Object cell) { - mxGeometry geo = getCellGeometry(cell); - - return (geo != null) ? geo.isRelative() : false; - } - - public boolean isCellFoldable(Object cell, boolean collapse) { - return false; - } - }; - - this.graphComponent = new mxGraphComponent(graph); - - this.editor = new Editor(graphComponent); - - graph.getModel().addListener(mxEvent.CHANGE, new mxIEventListener() { - public void invoke(Object sender, mxEventObject evt) { - List terminals = new ArrayList<>(); - mxCell cell = null; - for (Object change: ((List) evt.getProperties().get("changes"))) { - if (change instanceof mxGraphModel.mxTerminalChange) { - mxGraphModel.mxTerminalChange terminalChange = (mxGraphModel.mxTerminalChange) change; - cell = (mxCell) terminalChange.getCell(); - mxCell terminal = (mxCell) terminalChange.getTerminal(); - terminals.add(terminal); - } - } - if (terminals.size() == 2) { - if (!editor.connectEdge(cell, terminals.get(0), terminals.get(1))) { - graph.removeCells(new mxCell[] {cell}); - } - } - } - }); - getContentPane().add(graphComponent); - new mxRubberband(graphComponent); - graph.setAllowDanglingEdges(false); - graph.setCellsDisconnectable(true); - - menuBar = new ApplicationMenuBar(this); - setJMenuBar(menuBar); - setSize(870, 640); - } + private Editor editor = null; + private mxGraph graph = null; + private mxGraphComponent graphComponent = null; - public mxGraph getGraph() { - return graph; - } + private ApplicationMenuBar menuBar = null; + private NavigationWindow navigationWindow; - public mxGraphComponent getGraphComponent() { - return graphComponent; - } + public ApplicationWindow() { + setTitle(title); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - public Editor getEditor() { - return editor; - } + this.graph = new mxGraph() { + public boolean isPort(Object cell) { + mxGeometry geo = getCellGeometry(cell); + return (geo != null) ? geo.isRelative() : false; + } - public void setEditor(Editor editor) { - this.editor = editor; - } + public boolean isCellFoldable(Object cell, boolean collapse) { + return false; + } + }; + this.graphComponent = new mxGraphComponent(graph); + + this.editor = new Editor(graphComponent); + + getContentPane().add(graphComponent); + new mxRubberband(graphComponent); + graph.setAllowDanglingEdges(false); + graph.setCellsDisconnectable(true); + + menuBar = new ApplicationMenuBar(this); + setJMenuBar(menuBar); + setSize(870, 640); + setLocationRelativeTo(null); // Center on screen + + navigationWindow = new NavigationWindow(this, editor); + navigationWindow.setVisible(true); + editor.addStageChangeListener(navigationWindow); + } + + public mxGraph getGraph() { + return graph; + } + + public mxGraphComponent getGraphComponent() { + return graphComponent; + } + + public Editor getEditor() { + return editor; + } + + public void setEditor(Editor editor) { + this.editor = editor; + } + + public void showNavigationWindow() { + navigationWindow.setVisible(true); + } } diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java index 83acc69..62320f9 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java @@ -13,10 +13,13 @@ import algorithms.*; import application.editor.Editor; import code.ast.*; +import generators.CodeGeneratorFromDataFlowGraph; import generators.DataTransferMethodAnalyzer; -import generators.JavaCodeGenerator; -import generators.JavaMethodBodyGenerator; -import models.dataConstraintModel.ResourcePath; +import generators.ILanguageSpecific; +import generators.JavaSpecific; +import generators.StandaloneSpecific; +import generators.TypeInference; +import models.dataConstraintModel.ResourceHierarchy; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.ModelExtension; import models.dataFlowModel.DataFlowGraph; @@ -37,26 +40,29 @@ public void actionPerformed(ActionEvent e) { DataFlowGraph graph = editor.getDataFlowGraph(); if (graph != null) { + ILanguageSpecific langSpec = new JavaSpecific(); DataTransferModel model = editor.getModel(); ModelExtension.extendModel(model); - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(langSpec); + typeInference.infer(model); DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); String fileName = editor.getCurFileName(); if (fileName == null) fileName = "Main"; String mainTypeName = fileName.split("\\.")[0]; boolean exist = false; - for (ResourcePath id: model.getResourcePaths()) { - String resourceName = id.getResourceName().substring(0, 1).toUpperCase() + id.getResourceName().substring(1); + for (ResourceHierarchy res: model.getResourceHierarchies()) { + String resourceName = res.getResourceName().substring(0, 1).toUpperCase() + res.getResourceName().substring(1); if (mainTypeName.equals(resourceName)) { exist = true; } } + CodeGeneratorFromDataFlowGraph codeGenerator = new CodeGeneratorFromDataFlowGraph(new StandaloneSpecific(), langSpec); if (!exist) { - JavaCodeGenerator.setMainTypeName(mainTypeName); // use model's file name as the main type's name. + codeGenerator.setMainTypeName(mainTypeName); // use model's file name as the main type's name. } else { - JavaCodeGenerator.resetMainTypeName(); // use the default main type's name. + codeGenerator.resetMainTypeName(); // use the default main type's name. } - editor.setCodes(JavaMethodBodyGenerator.doGenerate(graph, model, JavaCodeGenerator.doGenerate(graph, model))); + editor.setCodes(codeGenerator.generateCode(model, graph)); ModelExtension.recoverModel(model); for (CompilationUnit file : editor.getCodes()) { System.out.println(file); diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java index 766c384..151028d 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java @@ -1,10 +1,8 @@ package application.actions; import java.awt.event.ActionEvent; -import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; -import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; @@ -13,11 +11,13 @@ import algorithms.*; import application.editor.Editor; import code.ast.*; +import generators.CodeGeneratorFromDataFlowGraph; import generators.DataTransferMethodAnalyzer; -import generators.JerseyCodeGenerator; -import generators.JerseyMethodBodyGenerator; -import models.algebra.Type; -import models.dataConstraintModel.ResourcePath; +import generators.ILanguageSpecific; +import generators.JavaSpecific; +import generators.JerseySpecific; +import generators.TypeInference; +import models.dataConstraintModel.ResourceHierarchy; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.ModelExtension; import models.dataFlowModel.DataFlowGraph; @@ -38,26 +38,30 @@ public void actionPerformed(ActionEvent e) { DataFlowGraph graph = editor.getDataFlowGraph(); if (graph != null) { + ILanguageSpecific langSpec = new JavaSpecific(); DataTransferModel model = editor.getModel(); ModelExtension.extendModel(model); - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(langSpec); + typeInference.infer(model); DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); String fileName = editor.getCurFileName(); if (fileName == null) fileName = "Main"; String mainTypeName = fileName.split("\\.")[0]; boolean exist = false; - for (ResourcePath id: model.getResourcePaths()) { - String resourceName = id.getResourceName().substring(0, 1).toUpperCase() + id.getResourceName().substring(1); + for (ResourceHierarchy res: model.getResourceHierarchies()) { + String resourceName = res.getResourceName().substring(0, 1).toUpperCase() + res.getResourceName().substring(1); if (mainTypeName.equals(resourceName)) { exist = true; } } + CodeGeneratorFromDataFlowGraph codeGenerator = new CodeGeneratorFromDataFlowGraph(new JerseySpecific(), langSpec); if (!exist) { - JerseyCodeGenerator.setMainTypeName(mainTypeName); // use model's file name as the main type's name. + codeGenerator.setMainTypeName(mainTypeName); // use model's file name as the main type's name. } else { - JerseyCodeGenerator.resetMainTypeName(); // use the default main type's name. + codeGenerator.resetMainTypeName(); // use the default main type's name. } - editor.setCodes(JerseyMethodBodyGenerator.doGenerate(graph, model, JerseyCodeGenerator.doGenerate(graph, model))); +// editor.setCodes(JerseyMethodBodyGenerator.doGenerate(graph, model, JerseyCodeGenerator.doGenerate(graph, model))); + editor.setCodes(codeGenerator.generateCode(model, graph)); ModelExtension.recoverModel(model); for (CompilationUnit file : editor.getCodes()) { System.out.println(file); diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/NewChannelAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/NewChannelAction.java index 6ee664c..1006055 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/NewChannelAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/NewChannelAction.java @@ -22,7 +22,7 @@ public void actionPerformed(ActionEvent e) { String channelName = JOptionPane.showInputDialog("Channel Name:"); if (channelName == null) return; - editor.addChannel(new DataTransferChannel(channelName)); + editor.addChannel(channelName); } } diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/NewEventChannelAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/NewEventChannelAction.java new file mode 100644 index 0000000..df10657 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/NewEventChannelAction.java @@ -0,0 +1,28 @@ +package application.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.JOptionPane; + +import application.editor.Editor; +import models.dataFlowModel.DataTransferChannel; + +public class NewEventChannelAction extends AbstractEditorAction { + + /** + * + */ + private static final long serialVersionUID = -1657072017390171313L; + + public NewEventChannelAction(Editor editor) { + super("Event Channel...", editor); + } + + @Override + public void actionPerformed(ActionEvent e) { + String channelName = JOptionPane.showInputDialog("Event Channel Name:"); + if (channelName == null) return; + editor.addEventChannel(channelName); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/NewFormulaChannelAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/NewFormulaChannelAction.java index 068c758..245be58 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/NewFormulaChannelAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/NewFormulaChannelAction.java @@ -56,7 +56,7 @@ String channelName = channelText.getText(); String symbol = symbolText.getText(); if(r == JOptionPane.OK_OPTION) { - editor.addFormulaChannel(new FormulaChannel(channelName, editor.getModel().getSymbol(symbol))); + editor.addFormulaChannel(channelName, editor.getModel().getSymbol(symbol)); } } } diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/NewIOChannelAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/NewIOChannelAction.java deleted file mode 100644 index 85e48de..0000000 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/NewIOChannelAction.java +++ /dev/null @@ -1,28 +0,0 @@ -package application.actions; - -import java.awt.event.ActionEvent; - -import javax.swing.JOptionPane; - -import application.editor.Editor; -import models.dataFlowModel.DataTransferChannel; - -public class NewIOChannelAction extends AbstractEditorAction { - - /** - * - */ - private static final long serialVersionUID = -1657072017390171313L; - - public NewIOChannelAction(Editor editor) { - super("I/O Channel", editor); - } - - @Override - public void actionPerformed(ActionEvent e) { - String channelName = JOptionPane.showInputDialog("I/O Channel Name:"); - if (channelName == null) return; - editor.addIOChannel(new DataTransferChannel(channelName)); - } - -} diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/NewResourceAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/NewResourceAction.java index 50b1512..3fb3f38 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/NewResourceAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/NewResourceAction.java @@ -1,28 +1,42 @@ package application.actions; -import java.awt.event.ActionEvent; - -import javax.swing.JOptionPane; - import application.editor.Editor; import models.dataConstraintModel.ResourcePath; +import models.dataFlowModel.ResourceNode; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.util.List; public class NewResourceAction extends AbstractEditorAction { - /** - * - */ - private static final long serialVersionUID = -4439207504700741286L; + private static final long serialVersionUID = -4439207504700741286L; - public NewResourceAction(Editor editor) { - super("Resource...", editor); - } + public NewResourceAction(Editor editor) { + super("Resource...", editor); + } - @Override - public void actionPerformed(ActionEvent e) { - String resName = JOptionPane.showInputDialog("Resourece Name:"); - if (resName == null) return; - editor.addResourcePath(new ResourcePath(resName, 0)); - } - + @Override + public void actionPerformed(ActionEvent e) { + List selectedResNodes = editor.getSelectedResourceNodes(); + String initialName = ""; + if (selectedResNodes != null && selectedResNodes.size() == 1) { + initialName = selectedResNodes.get(0).getPrimaryResourcePath().toString(); + } + String resName = JOptionPane.showInputDialog("Resource Name:", initialName); + if (resName == null) { + return; + } + if (selectedResNodes == null || selectedResNodes.size() == 0) { + editor.addResourceNode(null, resName); + } else if (selectedResNodes.size() == 1) { + if (initialName.length() > 0 && resName.startsWith(initialName)) { + resName = resName.substring(initialName.length()); + if (resName.startsWith(".")) { + resName = resName.substring(1); + } + } + editor.addResourceNode(selectedResNodes.get(0), resName); + } + } } diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/OpenAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/OpenAction.java index d01c518..90f3ca1 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/OpenAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/OpenAction.java @@ -1,62 +1,63 @@ package application.actions; -import java.awt.event.ActionEvent; -import java.io.File; - -import javax.swing.JFileChooser; -import javax.swing.filechooser.FileFilter; -import javax.swing.filechooser.FileNameExtensionFilter; - import application.ApplicationWindow; import application.editor.Editor; +import javax.swing.*; +import javax.swing.filechooser.FileFilter; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.awt.event.ActionEvent; +import java.io.File; + public class OpenAction extends AbstractSystemAction { - /** - * - */ - private static final long serialVersionUID = -8290761032629599683L; - - private String lastDir = null; - - public OpenAction(ApplicationWindow frame) { - super("Open...", frame); - } - @Override - public void actionPerformed(ActionEvent e) { - Editor editor = frame.getEditor(); - if (editor != null) { - String wd = (lastDir != null) ? lastDir : System.getProperty("user.dir"); + private static final long serialVersionUID = -8290761032629599683L; - JFileChooser fc = new JFileChooser(wd); + private String lastDir = null; - FileFilter model = new FileNameExtensionFilter("model","model"); - FileFilter dtram = new FileNameExtensionFilter("dtram", "dtram"); - - // Adds file filter for supported file format - FileFilter defaultFilter = new FileFilter() { + public OpenAction(ApplicationWindow frame) { + super("Open...", frame); + } - public boolean accept(File file) { - String lcase = file.getName().toLowerCase(); - return lcase.endsWith(".model"); - } + @Override + public void actionPerformed(ActionEvent e) { + Editor editor = frame.getEditor(); + if (editor == null) { + return; + } + String wd = (lastDir != null) ? lastDir : System.getProperty("user.dir"); - @Override - public String getDescription() { - return null; - } - }; - - fc.addChoosableFileFilter(defaultFilter); - fc.addChoosableFileFilter(model); - fc.addChoosableFileFilter(dtram); - int rc = fc.showDialog(null, "Open Model File"); - if (rc == JFileChooser.APPROVE_OPTION) { - lastDir = fc.getSelectedFile().getParent(); - editor.open(fc.getSelectedFile()); - frame.setTitle(frame.title + " - " + fc.getSelectedFile().getAbsolutePath()); - } - } - } + JFileChooser fc = buildFileChooser(wd); + int option = fc.showDialog(null, "Open Model File"); + if (option == JFileChooser.APPROVE_OPTION) { + lastDir = fc.getSelectedFile().getParent(); + editor.open(fc.getSelectedFile()); + frame.setTitle(ApplicationWindow.title + " - " + fc.getSelectedFile().getAbsolutePath()); + } + } + private static JFileChooser buildFileChooser(String wd) { + JFileChooser fc = new JFileChooser(wd); + + FileFilter model = new FileNameExtensionFilter("model", "model"); + FileFilter dtram = new FileNameExtensionFilter("dtram", "dtram"); + + // Adds file filter for supported file format + FileFilter defaultFilter = new FileFilter() { + public boolean accept(File file) { + String lowerCase = file.getName().toLowerCase(); + return lowerCase.endsWith(".model"); + } + + @Override + public String getDescription() { + return null; + } + }; + + fc.addChoosableFileFilter(defaultFilter); + fc.addChoosableFileFilter(model); + fc.addChoosableFileFilter(dtram); + return fc; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/SaveAsAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/SaveAsAction.java index 1a38b08..9542cdb 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/SaveAsAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/SaveAsAction.java @@ -65,9 +65,7 @@ lastDir = fc.getSelectedFile().getParent(); String fileName = fc.getSelectedFile().getAbsolutePath() + extension; - - // checking file duplicates - if(! (fc.getSelectedFile().exists())) editor.setCurFilePath(fileName); + editor.setCurFilePath(fileName); // overwriting file editor.save(); diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/ShowNavigationAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/ShowNavigationAction.java new file mode 100644 index 0000000..0dc4b9e --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/ShowNavigationAction.java @@ -0,0 +1,17 @@ +package application.actions; + +import application.ApplicationWindow; + +import java.awt.event.ActionEvent; + +public class ShowNavigationAction extends AbstractSystemAction { + + public ShowNavigationAction(ApplicationWindow frame) { + super("Show Navigation", frame); + } + + @Override + public void actionPerformed(ActionEvent e) { + frame.showNavigationWindow(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/SimulateAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/SimulateAction.java new file mode 100644 index 0000000..26a1779 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/SimulateAction.java @@ -0,0 +1,38 @@ +package application.actions; + +import java.awt.event.ActionEvent; +import java.io.File; + +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.filechooser.FileFilter; +import javax.swing.filechooser.FileNameExtensionFilter; + +import application.ApplicationWindow; +import application.editor.Editor; +import application.simulator.SimulatorWindow; +import models.dataFlowModel.DataTransferChannel; + +public class SimulateAction extends AbstractSystemAction { + + private SimulatorWindow simulatorWindow = null; + + /** + * + */ + private static final long serialVersionUID = -995609232489316795L; + + public SimulateAction(ApplicationWindow frame) { + super("Simulate", frame); + //this.simulatorWindow = new SimulatorWindow(frame.getEditor()); + } + + + @Override + public void actionPerformed(ActionEvent e) { + this.simulatorWindow = new SimulatorWindow(frame.getEditor()); + } + +} + diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/DataTransferModelingCellEditor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/DataTransferModelingCellEditor.java deleted file mode 100644 index b4d81a6..0000000 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/DataTransferModelingCellEditor.java +++ /dev/null @@ -1,248 +0,0 @@ -package application.editor; - -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Rectangle; -import java.util.EventObject; -import java.util.List; - -import javax.swing.BorderFactory; -import javax.swing.JComboBox; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JTextArea; -import javax.swing.JTextField; - -import com.mxgraph.model.mxCell; -import com.mxgraph.model.mxIGraphModel; -import com.mxgraph.swing.mxGraphComponent; -import com.mxgraph.swing.view.mxICellEditor; -import com.mxgraph.util.mxConstants; -import com.mxgraph.util.mxUtils; -import com.mxgraph.view.mxCellState; - -import models.algebra.Expression; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.DataTransferChannel; -import models.dataFlowModel.PushPullAttribute; -import models.dataFlowModel.PushPullValue; -import models.visualModel.FormulaChannel; -import parser.Parser; -import parser.Parser.TokenStream; -import parser.exceptions.ExpectedRightBracket; - -public class DataTransferModelingCellEditor implements mxICellEditor { - public int DEFAULT_MIN_WIDTH = 70; - public int DEFAULT_MIN_HEIGHT = 30; - public double DEFAULT_MINIMUM_EDITOR_SCALE = 1; - - protected double minimumEditorScale = DEFAULT_MINIMUM_EDITOR_SCALE; - protected int minimumWidth = DEFAULT_MIN_WIDTH; - protected int minimumHeight = DEFAULT_MIN_HEIGHT; - - private Object editingCell; - private EventObject trigger; - private JComboBox comboBox; - private mxGraphComponent graphComponent; - private Editor editor; - - public DataTransferModelingCellEditor(mxGraphComponent graphComponent, Editor editor) { - this.graphComponent = graphComponent; - this.editor = editor; - } - - @Override - public Object getEditingCell() { - return editingCell; - } - - @Override - public void startEditing(Object cell, EventObject evt) { - if (editingCell != null) { - stopEditing(true); - } - - if (!graphComponent.getGraph().getModel().isEdge(cell)) { - DataTransferModel model = editor.getModel(); - DataTransferChannel ch = (DataTransferChannel) model.getChannel((String) ((mxCell) cell).getValue()); - if (ch == null) { - ch = (DataTransferChannel) model.getIOChannel((String) ((mxCell) cell).getValue()); - if(ch == null) { - //resource - return; - } - } - - if(ch instanceof FormulaChannel) { - - JPanel panel = new JPanel(); - JLabel label1 = new JLabel("Formula: "); - JLabel label2 = new JLabel("Source: "); - GridBagLayout layout = new GridBagLayout(); - panel.setLayout(layout); - GridBagConstraints gbc = new GridBagConstraints(); - - gbc.gridx = 0; - gbc.gridy = 0; - layout.setConstraints(label1, gbc); - panel.add(label1); - - gbc.gridx = 1; - gbc.gridy = 0; - JTextField formulaText = new JTextField(((FormulaChannel) ch).getFormula(),15); - layout.setConstraints(formulaText, gbc); - panel.add(formulaText); - - gbc.gridx = 0; - gbc.gridy = 1; - layout.setConstraints(label2, gbc); - panel.add(label2); - - gbc.gridx = 1; - gbc.gridy = 1; - JTextArea textArea = new JTextArea(ch.getSourceText(),7,15); - textArea.setEditable(false); - layout.setConstraints(textArea, gbc); - panel.add(textArea); - - int r = JOptionPane.showConfirmDialog( - null, // owner window - panel, // message - "Edit Formula Channel", // window's title - JOptionPane.OK_CANCEL_OPTION, // option (button types) - JOptionPane.QUESTION_MESSAGE); // message type (icon types) - if(r == JOptionPane.OK_OPTION) { - TokenStream stream = new Parser.TokenStream(); - Parser parser = new Parser(stream); - - String formula = formulaText.getText(); - stream.addLine(formula.split(Parser.EQUALS)[1]); - - try { - Expression exp = parser.parseTerm(stream, editor.getModel()); - ((FormulaChannel) ch).setFormula(formula); - ((FormulaChannel) ch).setFormulaTerm(exp); - } catch (ExpectedRightBracket e) { - e.printStackTrace(); - } - } - }else { - JPanel panel = new JPanel(); - JTextArea textArea = new JTextArea(ch.getSourceText(), 10, 20); - panel.add(textArea); - // JEditorPane panel = new JEditorPane("text/plain", ch.toString()); - // panel.setEditable(true); - int ret = JOptionPane.showConfirmDialog(null, panel, "Channel Code", JOptionPane.OK_CANCEL_OPTION); - if (ret == JOptionPane.OK_OPTION) { - editor.setChannelCode(ch, textArea.getText()); - } - } - return; - } - - mxCellState state = graphComponent.getGraph().getView().getState(cell); - if (state != null && state.getLabel() != null && !state.getLabel().equals("")) { - editingCell = cell; - trigger = evt; - - double scale = Math.max(minimumEditorScale, graphComponent.getGraph().getView().getScale()); - Object value = graphComponent.getGraph().getModel().getValue(cell); - if (value != null && value instanceof PushPullAttribute) { - PushPullAttribute attr = (PushPullAttribute) value; - comboBox = new JComboBox<>(attr.getOptionStrings()); - comboBox.setBorder(BorderFactory.createEmptyBorder()); - comboBox.setOpaque(false); - comboBox.setBounds(getEditorBounds(state, scale)); - comboBox.setVisible(true); - graphComponent.getGraphControl().add(comboBox, 0); - comboBox.updateUI(); - } - } - } - - @Override - public void stopEditing(boolean cancel) { - if (editingCell != null) { - comboBox.transferFocusUpCycle(); - Object cell = editingCell; - editingCell = null; - if (!cancel) { - EventObject trig = trigger; - trigger = null; - Object value = graphComponent.getGraph().getModel().getValue(cell); - if (value != null && value instanceof PushPullAttribute) { - PushPullAttribute attr = (PushPullAttribute) value; - List options = attr.getOptions(); - PushPullValue selected = null; - for (PushPullValue option: options) { - if (option.toString().equals(getCurrentValue())) { - selected = option; - break; - } - } - if (selected != null) { - options.remove(selected); - options.add(0, selected); - } - graphComponent.labelChanged(cell, attr, trig); - } - } else { - mxCellState state = graphComponent.getGraph().getView().getState(cell); - graphComponent.redraw(state); - } - - if (comboBox.getParent() != null) { - comboBox.setVisible(false); - comboBox.getParent().remove(comboBox); - } - - graphComponent.requestFocusInWindow(); - } - } - - public String getCurrentValue() { - return (String) comboBox.getSelectedItem(); - } - - /** - * Returns the bounds to be used for the editor. - */ - public Rectangle getEditorBounds(mxCellState state, double scale) { - mxIGraphModel model = state.getView().getGraph().getModel(); - Rectangle bounds = null; - - bounds = state.getLabelBounds().getRectangle(); - bounds.height += 10; - - // Applies the horizontal and vertical label positions - if (model.isVertex(state.getCell())) { - String horizontal = mxUtils.getString(state.getStyle(), mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER); - - if (horizontal.equals(mxConstants.ALIGN_LEFT)) { - bounds.x -= state.getWidth(); - } else if (horizontal.equals(mxConstants.ALIGN_RIGHT)) { - bounds.x += state.getWidth(); - } - - String vertical = mxUtils.getString(state.getStyle(), - mxConstants.STYLE_VERTICAL_LABEL_POSITION, - mxConstants.ALIGN_MIDDLE); - - if (vertical.equals(mxConstants.ALIGN_TOP)) { - bounds.y -= state.getHeight(); - } else if (vertical.equals(mxConstants.ALIGN_BOTTOM)) { - bounds.y += state.getHeight(); - } - } - - bounds.setSize( - (int) Math.max(bounds.getWidth(), - Math.round(minimumWidth * scale)), - (int) Math.max(bounds.getHeight(), - Math.round(minimumHeight * scale))); - - return bounds; - } - -} diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java index b285ce0..22c8ff0 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java @@ -1,678 +1,557 @@ package application.editor; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - +import application.editor.stages.DataFlowModelingStage; +import application.editor.stages.PushPullSelectionStage; +import application.layouts.DAGLayout; +import code.ast.CompilationUnit; import com.mxgraph.layout.mxCircleLayout; import com.mxgraph.layout.mxCompactTreeLayout; import com.mxgraph.model.mxCell; -import com.mxgraph.model.mxGeometry; -import com.mxgraph.model.mxGraphModel; -import com.mxgraph.model.mxIGraphModel; import com.mxgraph.swing.mxGraphComponent; -import com.mxgraph.util.mxConstants; -import com.mxgraph.util.mxPoint; +import com.mxgraph.util.mxEvent; +import com.mxgraph.util.mxEventSource.mxIEventListener; import com.mxgraph.view.mxCellState; -import com.mxgraph.util.mxRectangle; import com.mxgraph.view.mxGraph; import com.mxgraph.view.mxGraphView; - -import algorithms.DataTransferModelAnalyzer; -import algorithms.Validation; -import application.layouts.*; -import code.ast.CompilationUnit; -import models.Edge; import models.EdgeAttribute; -import models.Node; +import models.algebra.Expression; +import models.algebra.Symbol; +import models.algebra.Variable; import models.dataConstraintModel.Channel; -import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.ResourcePath; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.DataTransferChannel; -import models.dataFlowModel.PushPullAttribute; -import models.dataFlowModel.DataFlowEdge; import models.dataFlowModel.DataFlowGraph; +import models.dataFlowModel.DataTransferChannel; +import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.ResourceNode; import models.visualModel.FormulaChannel; import parser.Parser; -import parser.Parser.TokenStream; -import parser.exceptions.ExpectedAssignment; -import parser.exceptions.ExpectedChannel; -import parser.exceptions.ExpectedChannelName; -import parser.exceptions.ExpectedEquals; -import parser.exceptions.ExpectedFormulaChannel; -import parser.exceptions.ExpectedGeometry; -import parser.exceptions.ExpectedInOrOutOrRefKeyword; -import parser.exceptions.ExpectedIoChannel; -import parser.exceptions.ExpectedLeftCurlyBracket; -import parser.exceptions.ExpectedModel; -import parser.exceptions.ExpectedNode; -import parser.exceptions.ExpectedRHSExpression; -import parser.exceptions.ExpectedResource; -import parser.exceptions.ExpectedRightBracket; -import parser.exceptions.ExpectedStateTransition; -import parser.exceptions.WrongLHSExpression; -import parser.exceptions.WrongRHSExpression; import parser.ParserDTRAM; +import parser.exceptions.*; + +import java.awt.event.MouseListener; +import java.io.*; +import java.util.ArrayList; +import java.util.List; public class Editor { - final int PORT_DIAMETER = 8; - final int PORT_RADIUS = PORT_DIAMETER / 2; - protected DataTransferModel model = null; - protected mxGraph graph = null; - private mxGraphComponent graphComponent = null; + protected DataTransferModel model = null; - protected DataFlowGraph dataFlowGraph = null; + protected mxGraph graph; + private final mxGraphComponent graphComponent; - protected String curFileName = null; - protected String curFilePath = null; - protected ArrayList codes = null; + protected Stage curStage; + private final List stageChangeListeners; - public Editor(mxGraphComponent graphComponent) { - this.graphComponent = graphComponent; - this.graph = graphComponent.getGraph(); - - graphComponent.setCellEditor(new DataTransferModelingCellEditor(graphComponent, this)); - } + private mxIEventListener curChangeEventListener = null; + private MouseListener curMouseEventListener = null; - public mxGraph getGraph() { - return graph; - } + protected String curFileName = null; + protected String curFilePath = null; + protected ArrayList codes = null; - public mxGraphComponent getGraphComponent() { - return this.graphComponent; - } + public static DataFlowModelingStage STAGE_DATA_FLOW_MODELING = null; + public static PushPullSelectionStage STAGE_PUSH_PULL_SELECTION = null; - public DataTransferModel getModel() { - if (model == null) { - model = new DataTransferModel(); - } - return model; - } + public Editor(mxGraphComponent graphComponent) { + this.graphComponent = graphComponent; + this.graph = graphComponent.getGraph(); - public DataFlowGraph getDataFlowGraph() { - if (dataFlowGraph == null) { - analyzeDataTransferModel(getModel()); - } - return dataFlowGraph; - } + STAGE_DATA_FLOW_MODELING = new DataFlowModelingStage(graphComponent); + STAGE_PUSH_PULL_SELECTION = new PushPullSelectionStage(graphComponent); - public DataFlowGraph analyzeDataTransferModel(DataTransferModel model) { - DataFlowGraph flowGraph = DataTransferModelAnalyzer.createDataFlowGraphWithStateStoringAttribute(model); - dataFlowGraph = DataTransferModelAnalyzer.annotateWithSelectableDataTransferAttiribute(flowGraph); - updateEdgeAttiributes(dataFlowGraph); - return dataFlowGraph; - } + graphComponent.setCellEditor(STAGE_DATA_FLOW_MODELING.createCellEditor(graphComponent)); - public void resetDataFlowGraph() { - dataFlowGraph = null; - } + curStage = STAGE_DATA_FLOW_MODELING; - public void setDataFlowGraph(DataFlowGraph dataFlowGraph) { - this.dataFlowGraph = dataFlowGraph; - } + stageChangeListeners = new ArrayList<>(); + } - public ArrayList getCodes() { - return codes; - } + public boolean canChange(Stage nextStage) { + return nextStage.canChangeFrom(curStage); + } - public void setCodes(ArrayList codes) { - this.codes = codes; - } + public boolean changeStage(Stage nextStage) { + if (!nextStage.canChangeFrom(curStage)) { + return false; + } + nextStage.init(curStage); + graphComponent.setCellEditor(nextStage.createCellEditor(graphComponent)); - public String getCurFileName() { - return curFileName; - } + // add listeners + // "curChangeEventListener" will be called when updating the mxGraph. + if (curChangeEventListener != null) { + graph.getModel().removeListener(curChangeEventListener); + } + curChangeEventListener = nextStage.createChangeEventListener(this); + if (curChangeEventListener != null) { + graph.getModel().addListener(mxEvent.CHANGE, curChangeEventListener); + } - public String getCurFilePath() { - return curFilePath; - } + // A handler of a mouse event. + if (curMouseEventListener != null) { + graphComponent.getGraphControl().removeMouseListener(curMouseEventListener); + } + curMouseEventListener = nextStage.createMouseEventListener(this); + if (curMouseEventListener != null) { + graphComponent.getGraphControl().addMouseListener(curMouseEventListener); + } + curStage = nextStage; + notifyStageChangeListeners(); + return true; + } - public void setCurFilePath(String curFilePath) { - this.curFilePath = curFilePath; - this.curFileName = new File(curFilePath).getName(); - } + public void addStageChangeListener(IStageChangeListener stageChangeListener) { + stageChangeListeners.add(stageChangeListener); + } - public void clear() { - model = null; - ((mxGraphModel) graph.getModel()).clear(); - dataFlowGraph = null; - curFilePath = null; - curFileName = null; - codes = null; - } + private void notifyStageChangeListeners() { + for (IStageChangeListener l : stageChangeListeners) { + l.stageChanged(curStage); + } + } - /** - * Open a given file, parse the file, construct a DataFlowModel and a mxGraph - * @param file given file - * @return a constructed DataFlowModel - */ - public DataTransferModel open(File file) { - try { + public DataFlowGraph getDataFlowGraph() { + if (curStage instanceof PushPullSelectionStage) { + return ((PushPullSelectionStage) curStage).getDataFlowGraph(); + } + return null; + } - String extension =""; - if(file != null && file.exists()) { - // get a file's name - String name = file.getName(); + public void setCurFilePath(String curFilePath) { + this.curFilePath = curFilePath; + this.curFileName = new File(curFilePath).getName(); + } - // get a file's extension - extension = name.substring(name.lastIndexOf(".")); - } - if(extension.contains(".model")) { - openModel(file); - } else { - ParserDTRAM parserDTRAM = new ParserDTRAM(new BufferedReader(new FileReader(file))); - try { - model = parserDTRAM.doParseModel(); - graph = constructGraph(model); - parserDTRAM.doParseGeometry(graph); - curFilePath = file.getAbsolutePath(); - curFileName = file.getName(); - if (!Validation.checkUpdateConflict(model)) return null; - analyzeDataTransferModel(model); - return model; - } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword - | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedModel | ExpectedGeometry | ExpectedNode | ExpectedResource | ExpectedFormulaChannel | ExpectedIoChannel e) { - e.printStackTrace(); - } - } - } catch (FileNotFoundException e) { - e.printStackTrace(); - } + public void clear() { + // Force to change to the data-flow modeling stage + boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); + if (!stageChanged) { + return; + } + ((DataFlowModelingStage) curStage).clear(); - return null; - } + model = null; + curFilePath = null; + curFileName = null; + codes = null; + } - public DataTransferModel openModel(File file) { - try { + /** + * Open a given file, parse the file, construct a DataFlowModel and a mxGraph + * + * @param file given file + */ + public void open(File file) { + // Force to change to data-modeling stage + boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); + if (!stageChanged) { + return; + } + if (file == null || !file.exists()) { + return; + } + // get a file's extension + String extension = file.getName().substring(file.getName().lastIndexOf(".")); + if (extension.contains(".model")) { + openModel(file); + } + if (extension.contains(".dtram")) { + openDTRAM(file); + } + } - Parser parser = new Parser(new BufferedReader(new FileReader(file))); + private void openModel(File file) { + try { + Parser parser = new Parser(new BufferedReader(new FileReader(file))); + try { + // Parse the .model file. + model = parser.doParse(); - try { - // Parse the .model file. - model = parser.doParse(); - - curFilePath = file.getAbsolutePath(); - curFileName = file.getName(); - - // Analyze the model. - if (!Validation.checkUpdateConflict(model)) return null; - graph = constructGraph(model); - analyzeDataTransferModel(model); - - // Set DAG layout. - setDAGLayout(); - return model; - } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword - | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment e) { - e.printStackTrace(); - } - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - return null; - } + // Update stage's model to new parsed one + if (curStage instanceof DataFlowModelingStage) { + ((DataFlowModelingStage) curStage).setModel(model); + } - /**-------------------------------------------------------------------------------- - * save - /**-------------------------------------------------------------------------------- - * - */ - public void save() { - if (curFilePath != null) { - try { - File file = new File(curFilePath); - String extension = ""; - if(file != null && file.exists()) { - // get a file's name - String name = file.getName(); + // Force to change PushPullSelectionStage to construct mxGraph + boolean stageChanged = changeStage(STAGE_PUSH_PULL_SELECTION); - // get a file's extension - extension = name.substring(name.lastIndexOf(".")); - } - if(extension.contains(".model")) { - saveModel(file); - } else { - FileWriter filewriter = new FileWriter(file); - filewriter.write(toOutputString()); - filewriter.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } + // Set layout + setDAGLayout(); - public void saveModel(File file) { - if (curFilePath != null) { - try { - FileWriter filewriter = new FileWriter(file); - filewriter.write(model.getSourceText()); - filewriter.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } + // Update current file info + curFilePath = file.getAbsolutePath(); + curFileName = file.getName(); + } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | + ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | + ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedRightBracket | + ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression | + ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } - /**-------------------------------------------------------------------------------- - * get writing texts "dtram" file information is written. - * - * @return formatted "dtram" info texts. - */ - protected String toOutputString() { - String fileString = ""; - - fileString += "model {\n"; - fileString += this.model.getSourceText(); - fileString += "}\n"; + private void openDTRAM(File file) { + try { + ParserDTRAM parser = new ParserDTRAM(new BufferedReader(new FileReader(file))); + try { + // Parse the .dtram file. + model = parser.doParseModel(); - fileString += "geometry {\n"; + // Update stage's model to new parsed one + if (curStage instanceof DataFlowModelingStage) { + ((DataFlowModelingStage) curStage).setModel(model); + } - Object root = graph.getDefaultParent(); - for (int i = 0; i < graph.getModel().getChildCount(root); i++) { - Object cell = graph.getModel().getChildAt(root, i); - if (graph.getModel().isVertex(cell)) { - mxGraphView view = graph.getView(); - mxCellState state = view.getState(cell); - int x = (int) state.getX(); - int y = (int) state.getY(); - int w = (int) state.getWidth(); - int h = (int) state.getHeight(); + // Force to change PushPullSelectionStage to construct mxGraph + boolean stageChanged = changeStage(STAGE_PUSH_PULL_SELECTION); - for(Channel ch: model.getChannels()) { - if(ch instanceof FormulaChannel && state.getLabel().equals(ch.getChannelName())) { - fileString += "\tnode fc " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h+"\n"; - } else if(ch instanceof Channel && state.getLabel().equals(ch.getChannelName())) { - fileString +="\tnode c " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h+"\n"; - } - } + // Restore the geometry + parser.doParseGeometry(graph); - for (ResourcePath res: model.getResourcePaths()){ - if(res instanceof ResourcePath && state.getLabel().equals(res.getResourceName())) - fileString += "\tnode r " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h + "\n"; - } + // Update current file info + curFilePath = file.getAbsolutePath(); + curFileName = file.getName(); + } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | + ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | + ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedRightBracket | + ExpectedAssignment | ExpectedModel | ExpectedGeometry | ExpectedNode | ExpectedResource | + ExpectedFormulaChannel | ExpectedIoChannel | ExpectedRightCurlyBracket | WrongPathExpression | + WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } - for (Channel ioC: model.getIOChannels()) { - if(ioC instanceof Channel && state.getLabel().equals(ioC.getChannelName())) { - fileString += "\tnode ioc " + state.getLabel() + ":" + x + "," + y + "," + w + "," + h + "\n"; - } - } - } - } - fileString += "}\n"; - - return fileString; - } - - /** - * Construct a mxGraph from DataFlowModel and DataFlowModel - * @param model - * @param dataFlowGraph - * @return constructed mxGraph - */ - public mxGraph constructGraph(DataTransferModel model) { - ((mxGraphModel) graph.getModel()).clear(); - Object parent = graph.getDefaultParent(); - graph.getModel().beginUpdate(); - try { - mxGeometry geo1 = new mxGeometry(0, 0.5, PORT_DIAMETER, PORT_DIAMETER); - geo1.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); - geo1.setRelative(true); + public void save() { + if (curFilePath == null) { + return; + } + File file = new File(curFilePath); + // get a file's extension + String extension = file.getName().substring(file.getName().lastIndexOf(".")); + if (extension.contains(".model")) { + saveModel(file); + } else if (extension.contains(".dtram")) { + saveDTRAM(file); + } + } - mxGeometry geo2 = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); - geo2.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); - geo2.setRelative(true); + private void saveModel(File file) { + try { + FileWriter filewriter = new FileWriter(file); + filewriter.write(model.getSourceText()); + filewriter.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } - Map channelsIn = new HashMap<>(); - Map channelsOut = new HashMap<>(); - Map resources = new HashMap<>(); + private void saveDTRAM(File file) { + try { + FileWriter filewriter = new FileWriter(file); + filewriter.write(toOutputString()); + filewriter.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } - // create channel vertices - for (Channel c: model.getChannels()) { - DataTransferChannel channelGen = (DataTransferChannel) c; - if (channelsIn.get(channelGen) == null || channelsOut.get(channelGen) == null) { - Object channel = graph.insertVertex(parent, null, channelGen.getChannelName(), 150, 20, 30, 30); // insert a channel as a vertex - mxCell port_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); - port_in.setVertex(true); - graph.addCell(port_in, channel); // insert the input port of a channel - mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); - port_out.setVertex(true); - graph.addCell(port_out, channel); // insert the output port of a channel - channelsIn.put(channelGen, port_in); - channelsOut.put(channelGen, port_out); - } - } + /** + * get writing texts "dtram" file information is written. + * + * @return formatted "dtram" info texts. + */ + private String toOutputString() { + StringBuilder fileString = new StringBuilder(); - // create resource vertices - for (ResourcePath res: model.getResourcePaths()) { - Object resource = graph.insertVertex(parent, null, - res.getResourceName(), 20, 20, 80, 30, - "shape=ellipse;perimeter=ellipsePerimeter"); // insert a resource as a vertex - resources.put(res, resource); - } + fileString.append("model {\n"); + fileString.append(model.getSourceText()); + fileString.append("}\n"); - // add input, output and reference edges - for (Channel ch: model.getChannels()) { - DataTransferChannel channelGen = (DataTransferChannel) ch; - // input edge - for (ResourcePath srcRes: channelGen.getInputResources()) { - graph.insertEdge(parent, null, new SrcDstAttribute(srcRes, channelGen), resources.get(srcRes), channelsIn.get(channelGen), "movable=false"); - } - // output edge - for (ResourcePath dstRes: channelGen.getOutputResources()) { - graph.insertEdge(parent, null, new SrcDstAttribute(channelGen, dstRes), channelsOut.get(channelGen), resources.get(dstRes), "movable=false"); - } - // reference edges - for (ResourcePath refRes: channelGen.getReferenceResources()) { - graph.insertEdge(parent, null, null, resources.get(refRes), channelsIn.get(channelGen), "dashed=true;movable=false"); - } - } + fileString.append("geometry {\n"); - for (Channel ioChannelGen: model.getIOChannels()) { - if (channelsOut.get(ioChannelGen) == null) { - Object channel = graph.insertVertex(parent, null, ioChannelGen.getChannelName(), 150, 20, 30, 30); // insert an I/O channel as a vertex - mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); - port_out.setVertex(true); - graph.addCell(port_out, channel); // insert the output port of a channel - channelsOut.put((DataTransferChannel) ioChannelGen, port_out); - for (ResourcePath outRes: ((DataTransferChannel) ioChannelGen).getOutputResources()) { - graph.insertEdge(parent, null, null, port_out, resources.get(outRes), "movable=false"); - } - } - } - } finally { - graph.getModel().endUpdate(); - } - setTreeLayout(); + Object root = graph.getDefaultParent(); + for (int i = 0; i < graph.getModel().getChildCount(root); i++) { + Object cell = graph.getModel().getChildAt(root, i); + if (graph.getModel().isVertex(cell)) { + mxGraphView view = graph.getView(); + mxCellState state = view.getState(cell); + int x = (int) state.getX(); + int y = (int) state.getY(); + int w = (int) state.getWidth(); + int h = (int) state.getHeight(); - return graph; - } + for (Channel ch : model.getChannels()) { + if (ch instanceof FormulaChannel && state.getLabel().equals(ch.getChannelName())) { + fileString.append("\tnode fc ").append(state.getLabel()).append(":").append(x).append(",").append(y).append(",").append(w).append(",").append(h).append("\n"); + } else if (ch != null && state.getLabel().equals(ch.getChannelName())) { + fileString.append("\tnode c ").append(state.getLabel()).append(":").append(x).append(",").append(y).append(",").append(w).append(",").append(h).append("\n"); + } + } - public void setDAGLayout() { - Object parent = graph.getDefaultParent(); - graph.getModel().beginUpdate(); - try { - DAGLayout ctl = new DAGLayout(graph); - ctl.execute(parent); - } finally { - graph.getModel().endUpdate(); - } - } + for (ResourcePath res : model.getResourcePaths()) { + if (res != null && state.getLabel().equals(res.getLeafResourceName())) + fileString.append("\tnode r ").append(state.getLabel()).append(":").append(x).append(",").append(y).append(",").append(w).append(",").append(h).append("\n"); + } - public void updateEdgeAttiributes(DataFlowGraph dataFlowGraph) { - Object parent = graph.getDefaultParent(); - graph.getModel().beginUpdate(); - try { - // add input, output and reference edges - for (Edge e : dataFlowGraph.getEdges()) { - if (e instanceof DataFlowEdge) { - DataFlowEdge dataFlow = (DataFlowEdge) e; - DataTransferChannel channelGen = dataFlow.getChannel(); - ResourceNode srcRes = (ResourceNode) dataFlow.getSource(); - // input edge - for (Object edge: graph.getChildEdges(parent)) { - mxCell edgeCell = (mxCell) edge; - if (edgeCell.getValue() instanceof SrcDstAttribute) { - SrcDstAttribute edgeAttr = (SrcDstAttribute) edgeCell.getValue(); - if (edgeAttr.getSrouce() == srcRes.getResource() && edgeAttr.getDestination() == channelGen) { - edgeCell.setValue(dataFlow.getAttribute()); - break; - } - } - } - } - } - } finally { - graph.getModel().endUpdate(); - } - graph.refresh(); - } + for (Channel ioC : model.getInputChannels()) { + if (ioC != null && state.getLabel().equals(ioC.getChannelName())) { + fileString.append("\tnode ioc ").append(state.getLabel()).append(":").append(x).append(",").append(y).append(",").append(w).append(",").append(h).append("\n"); + } + } + } + } + fileString.append("}\n"); + return fileString.toString(); + } - public void setTreeLayout() { - Object parent = graph.getDefaultParent(); - graph.getModel().beginUpdate(); - try { - mxCompactTreeLayout ctl = new mxCompactTreeLayout(graph); - ctl.setLevelDistance(100); - // ctl.setHorizontal(false); - ctl.setEdgeRouting(false); - ctl.execute(parent); - } finally { - graph.getModel().endUpdate(); - } - } + public void setDAGLayout() { + mxCell root = (mxCell) graph.getDefaultParent(); - public void setCircleLayout() { - Object parent = graph.getDefaultParent(); - graph.getModel().beginUpdate(); - try { - mxCircleLayout ctl = new mxCircleLayout(graph); - ctl.execute(parent); - } finally { - graph.getModel().endUpdate(); - } - } + graph.getModel().beginUpdate(); + try { + DAGLayout ctl = new DAGLayout(graph); + ctl.execute(root); + } finally { + graph.getModel().endUpdate(); + } + } - public void addResourcePath(ResourcePath res) { - getModel().addResourcePath(res); - resetDataFlowGraph(); - graph.getModel().beginUpdate(); - Object parent = graph.getDefaultParent(); - try { - graph.insertVertex(parent, null, res.getResourceName(), 20, 20, 80, 30, - "shape=ellipse;perimeter=ellipsePerimeter"); // insert a resource as a vertex - } finally { - graph.getModel().endUpdate(); - } - } + public void setTreeLayout() { + mxCell root = (mxCell) graph.getDefaultParent(); - public void addChannel(DataTransferChannel channelGen) { - getModel().addChannel(channelGen); - resetDataFlowGraph(); - graph.getModel().beginUpdate(); - Object parent = graph.getDefaultParent(); - try { - mxGeometry geo1 = new mxGeometry(0, 0.5, PORT_DIAMETER, PORT_DIAMETER); - geo1.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); - geo1.setRelative(true); + graph.getModel().beginUpdate(); + try { + mxCompactTreeLayout ctl = new mxCompactTreeLayout(graph); + ctl.setLevelDistance(100); + // ctl.setHorizontal(false); + ctl.setEdgeRouting(false); + for (int i = 0; i < root.getChildCount(); i++) { + ctl.execute(root.getChildAt(i)); + } + } finally { + graph.getModel().endUpdate(); + } + } - mxGeometry geo2 = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); - geo2.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); - geo2.setRelative(true); + public void setCircleLayout() { + mxCell root = (mxCell) graph.getDefaultParent(); - Object channel = graph.insertVertex(parent, null, channelGen.getChannelName(), 150, 20, 30, 30); // insert a channel as a vertex - mxCell port_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); - port_in.setVertex(true); - graph.addCell(port_in, channel); // insert the input port of a channel - mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); - port_out.setVertex(true); - graph.addCell(port_out, channel); // insert the output port of a channel - } finally { - graph.getModel().endUpdate(); - } - } + graph.getModel().beginUpdate(); + try { + mxCircleLayout ctl = new mxCircleLayout(graph); + for (int i = 0; i < root.getChildCount(); i++) { + ctl.execute(root.getChildAt(i)); + } + } finally { + graph.getModel().endUpdate(); + } + } + + public List getSelectedResourceNodes() { + Object[] sels = graph.getSelectionCells(); + List resNodes = new ArrayList<>(); + if (curStage instanceof DataFlowModelingStage) { + for (Object sel: sels) { + if (sel instanceof mxCell && ((mxCell) sel).isVertex()) { + mxCell cell = ((mxCell) sel); + ResourceNode resNode = ((DataFlowModelingStage) curStage).getResourceNode(cell); + if (resNode != null) { + resNodes.add(resNode); + } + } + } + } + return resNodes; + } + + public List getSelectedChannels() { + Object[] sels = graph.getSelectionCells(); + List channels = new ArrayList<>(); + for (Object sel: sels) { + if (sel instanceof mxCell && ((mxCell) sel).isVertex()) { + mxCell cell = ((mxCell) sel); + Channel channel = model.getChannel((String) cell.getValue()); + if (channel != null) { + channels.add(channel); + } else { + channel = model.getInputChannel((String) cell.getValue()); + if (channel != null) { + channels.add(channel); + } + } + } + } + return channels; + } - public void addIOChannel(DataTransferChannel ioChannelGen) { - getModel().addIOChannel(ioChannelGen); - resetDataFlowGraph(); - graph.getModel().beginUpdate(); - Object parent = graph.getDefaultParent(); - try { - mxGeometry geo2 = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); - geo2.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); - geo2.setRelative(true); + public void delete() { + boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); + if (!stageChanged) { + return; + } + ((DataFlowModelingStage) curStage).delete(); + } - Object channel = graph.insertVertex(parent, null, ioChannelGen.getChannelName(), 150, 20, 30, 30); // insert an I/O channel as a vertex - mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); - port_out.setVertex(true); - graph.addCell(port_out, channel); // insert the output port of a channel - } finally { - graph.getModel().endUpdate(); - } - } + public void addResourceNode(ResourceNode parentNode, String resName) { + // Force to change to data-flow modeling stage + boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); + if (!stageChanged) { + return; + } + ((DataFlowModelingStage) curStage).addResourceNode(parentNode, resName); + model = curStage.getModel(); + } - public void addFormulaChannel(FormulaChannel formulaChannelGen) { - getModel().addChannel(formulaChannelGen); - resetDataFlowGraph(); - graph.getModel().beginUpdate(); - Object parent = graph.getDefaultParent(); - try { - mxGeometry geo1 = new mxGeometry(0, 0.5, PORT_DIAMETER, PORT_DIAMETER); - geo1.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); - geo1.setRelative(true); + public void addChannel(String channelName) { + // Force to change to data-flow modeling stage + boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); + if (!stageChanged) { + return; + } + DataTransferChannel channel = null; + if (channelName.contains(Parser.LEFT_BRACKET) && channelName.contains(Parser.RIGHT_BRACKET)) { + channel = new DataTransferChannel(channelName.substring(0, channelName.indexOf(Parser.LEFT_BRACKET))); + Parser.TokenStream stream = new Parser.TokenStream(); + Parser parser = new Parser(stream); + stream.addLine(channelName.substring(channelName.indexOf(Parser.LEFT_BRACKET), channelName.length())); + try { + String leftBracket = stream.next(); + if (leftBracket.equals(Parser.LEFT_BRACKET)) { + // has selectors + String rightBracket = null; + do { + String selector = stream.next(); + Variable var = parser.parseVariable(stream, model, selector); + channel.addSelector(var); + rightBracket = stream.next(); + } while (rightBracket.equals(Parser.COMMA)); + if (!rightBracket.equals(Parser.RIGHT_BRACKET)) throw new ExpectedRightBracket(stream.getLine()); + leftBracket = stream.next(); + } + } catch (ExpectedRightBracket e) { + e.printStackTrace(); + } + } else { + channel = new DataTransferChannel(channelName); + } + ((DataFlowModelingStage) curStage).addChannel(channel); + model = curStage.getModel(); + } - mxGeometry geo2 = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); - geo2.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); - geo2.setRelative(true); + public void addEventChannel(String channelName) { + // Force to change to data-flow modeling stage + boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); + if (!stageChanged) { + return; + } + DataTransferChannel eventChannel = null; + if (channelName.contains(Parser.LEFT_BRACKET) && channelName.contains(Parser.RIGHT_BRACKET)) { + eventChannel = new DataTransferChannel(channelName.substring(0, channelName.indexOf(Parser.LEFT_BRACKET))); + Parser.TokenStream stream = new Parser.TokenStream(); + Parser parser = new Parser(stream); + stream.addLine(channelName.substring(channelName.indexOf(Parser.LEFT_BRACKET), channelName.length())); + try { + String leftBracket = stream.next(); + if (leftBracket.equals(Parser.LEFT_BRACKET)) { + // has selectors + String rightBracket = null; + do { + String selector = stream.next(); + Variable var = parser.parseVariable(stream, model, selector); + eventChannel.addSelector(var); + rightBracket = stream.next(); + } while (rightBracket.equals(Parser.COMMA)); + if (!rightBracket.equals(Parser.RIGHT_BRACKET)) throw new ExpectedRightBracket(stream.getLine()); + leftBracket = stream.next(); + } + } catch (ExpectedRightBracket e) { + e.printStackTrace(); + } + } else { + eventChannel = new DataTransferChannel(channelName); + } + ((DataFlowModelingStage) curStage).addEventChannel(eventChannel); + model = curStage.getModel(); + } - Object channel = graph.insertVertex(parent, null, formulaChannelGen.getChannelName(), 150, 20, 30, 30); // insert a channel as a vertex - mxCell port_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); - port_in.setVertex(true); - graph.addCell(port_in, channel); // insert the input port of a channel - mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); - port_out.setVertex(true); - graph.addCell(port_out, channel); // insert the output port of a channel - } finally { - graph.getModel().endUpdate(); - } - } + public void addFormulaChannel(String channelName, Symbol op) { + // Force to change to data-flow modeling stage + boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); + if (!stageChanged) { + return; + } + FormulaChannel formulaChannel = new FormulaChannel(channelName, op); + ((DataFlowModelingStage) curStage).addFormulaChannel(formulaChannel); + model = curStage.getModel(); + } - public boolean connectEdge(mxCell edge, mxCell src, mxCell dst) { - DataTransferModel model = getModel(); - Channel srcCh = model.getChannel((String) src.getValue()); - if (srcCh == null) { - srcCh = model.getIOChannel((String) src.getValue()); - if (srcCh == null) { - ResourcePath srcRes = model.getResourcePath((String) src.getValue()); - Channel dstCh = model.getChannel((String) dst.getValue()); - if (srcRes == null || dstCh == null) return false; - // resource to channel edge - ChannelMember srcCm = new ChannelMember(srcRes); - ((DataTransferChannel ) dstCh).addChannelMemberAsInput(srcCm); - edge.setValue(new SrcDstAttribute(srcRes, dstCh)); - resetDataFlowGraph(); - return true; - } - } - ResourcePath dstRes = model.getResourcePath((String) dst.getValue()); - if (dstRes == null) return false; - // channel to resource edge - ChannelMember dstCm = new ChannelMember(dstRes); - ((DataTransferChannel) srcCh).addChannelMemberAsOutput(dstCm); - edge.setValue(new SrcDstAttribute(srcCh, dstRes)); - resetDataFlowGraph(); - return true; - } + public boolean connectEdge(mxCell edge, mxCell src, mxCell dst) { + boolean stageChanged = changeStage(STAGE_DATA_FLOW_MODELING); + if (!stageChanged) { + return false; + } + return ((DataFlowModelingStage) curStage).connectEdge(edge, src, dst); + } - public void delete() { - for (Object obj: graph.getSelectionCells()) { - mxCell cell = (mxCell) obj; - if (cell.isEdge()) { - String srcName = (String) cell.getSource().getValue(); - String dstName = (String) cell.getTarget().getValue(); - if (model.getResourcePath(srcName) != null) { - // resource to channel edge - Channel ch = model.getChannel(dstName); - ch.removeChannelMember(model.getResourcePath(srcName)); - } else if (model.getResourcePath(dstName) != null) { - // channel to resource edge - Channel ch = model.getChannel(srcName); - if (ch == null) { - ch = model.getIOChannel(srcName); - } - ch.removeChannelMember(model.getResourcePath(dstName)); - } - } else if (cell.isVertex()) { - String name = (String) cell.getValue(); - if (model.getChannel(name) != null) { - model.removeChannel(name); - } else if (model.getIOChannel(name) != null) { - model.removeIOChannel(name); - } else if (model.getResourcePath(name) != null) { - model.removeResourcePath(name); - } - } - } - graph.removeCells(graph.getSelectionCells()); - resetDataFlowGraph(); - } + public mxGraph getGraph() { + return graph; + } - public void setChannelCode(DataTransferChannel ch, String code) { - ch.setSourceText(code); - TokenStream stream = new Parser.TokenStream(); - Parser parser = new Parser(stream); - - for (String line: code.split("\n")) { - stream.addLine(line); - } - try { - DataTransferChannel ch2 = parser.parseChannel(getModel()); - for (ChannelMember chm2: ch2.getInputChannelMembers()) { - for (ChannelMember chm: ch.getInputChannelMembers()) { - if (chm2.getResource() == chm.getResource()) { - chm.setStateTransition(chm2.getStateTransition()); - break; - } - } - } - for (ChannelMember chm2: ch2.getOutputChannelMembers()) { - for (ChannelMember chm: ch.getOutputChannelMembers()) { - if (chm2.getResource() == chm.getResource()) { - chm.setStateTransition(chm2.getStateTransition()); - break; - } - } - } - for (ChannelMember chm2: ch2.getReferenceChannelMembers()) { - for (ChannelMember chm: ch.getReferenceChannelMembers()) { - if (chm2.getResource() == chm.getResource()) { - chm.setStateTransition(chm2.getStateTransition()); - break; - } - } - } - resetDataFlowGraph(); - } catch (ExpectedRightBracket | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket - | ExpectedInOrOutOrRefKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression - | WrongLHSExpression | WrongRHSExpression | ExpectedAssignment e) { - e.printStackTrace(); - } - } + public mxGraphComponent getGraphComponent() { + return graphComponent; + } - private class SrcDstAttribute extends EdgeAttribute { - private Object src; - private Object dst; + public DataTransferModel getModel() { + model = curStage.getModel(); + return model; + } - public SrcDstAttribute(Object src, Object dst) { - this.src = src; - this.dst = dst; - } + public Stage getCurStage() { + return curStage; + } - public Object getSrouce() { - return src; - } + public ArrayList getCodes() { + return codes; + } - public Object getDestination() { - return dst; - } + public void setCodes(ArrayList codes) { + this.codes = codes; + } - public String toString() { - return ""; - } - } + public String getCurFileName() { + return curFileName; + } + + public String getCurFilePath() { + return curFilePath; + } + + public static class SrcDstAttribute extends EdgeAttribute { + private final Object src; + private final Object dst; + + public SrcDstAttribute(Object src, Object dst) { + this.src = src; + this.dst = dst; + } + + public Object getSource() { + return src; + } + + public Object getDestination() { + return dst; + } + + public String toString() { + return ""; + } + } } diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/FlowCellEditor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/FlowCellEditor.java new file mode 100644 index 0000000..b4d7176 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/FlowCellEditor.java @@ -0,0 +1,27 @@ +package application.editor; + +import com.mxgraph.swing.mxGraphComponent; +import com.mxgraph.swing.view.mxICellEditor; + +import java.util.EventObject; + +public abstract class FlowCellEditor implements mxICellEditor { + + protected Stage stage; + protected mxGraphComponent graphComponent; + + protected Object editingCell = null; + + protected FlowCellEditor(Stage stage, mxGraphComponent graphComponent) { + this.stage = stage; + this.graphComponent = graphComponent; + } + + public abstract void startEditing(Object cellObj, EventObject eventObj); + + public abstract void stopEditing(boolean cancel); + + public Object getEditingCell() { + return this.editingCell; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/IStageChangeListener.java b/AlgebraicDataflowArchitectureModel/src/application/editor/IStageChangeListener.java new file mode 100644 index 0000000..f2cf45c --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/IStageChangeListener.java @@ -0,0 +1,5 @@ +package application.editor; + +public interface IStageChangeListener { + void stageChanged(Stage newStage); +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/Stage.java b/AlgebraicDataflowArchitectureModel/src/application/editor/Stage.java new file mode 100644 index 0000000..33114bd --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/Stage.java @@ -0,0 +1,39 @@ +package application.editor; + +import com.mxgraph.swing.mxGraphComponent; +import com.mxgraph.swing.view.mxICellEditor; +import com.mxgraph.util.mxEventSource.mxIEventListener; +import com.mxgraph.view.mxGraph; +import models.dataFlowModel.DataTransferModel; + +import java.awt.event.MouseListener; + +public abstract class Stage { + + public static final int PORT_DIAMETER = 8; + public static final int PORT_RADIUS = PORT_DIAMETER / 2; + + protected DataTransferModel model = null; + + protected mxGraphComponent graphComponent; + protected mxGraph graph; + + public Stage(mxGraphComponent graphComponent) { + this.graphComponent = graphComponent; + this.graph = graphComponent.getGraph(); + } + + public abstract void init(Stage prevStage); + + public abstract mxICellEditor createCellEditor(mxGraphComponent graphComponent); + + public abstract mxIEventListener createChangeEventListener(Editor editor); + + public abstract MouseListener createMouseEventListener(Editor editor); + + public abstract boolean canChangeFrom(Stage prevStage); + + public DataTransferModel getModel() { + return model; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DataFlowCellEditor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DataFlowCellEditor.java new file mode 100644 index 0000000..f8e85fc --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DataFlowCellEditor.java @@ -0,0 +1,105 @@ +package application.editor.stages; + +import application.editor.FlowCellEditor; +import com.mxgraph.model.mxCell; +import com.mxgraph.model.mxIGraphModel; +import com.mxgraph.swing.mxGraphComponent; +import com.mxgraph.util.mxConstants; +import com.mxgraph.util.mxUtils; +import models.algebra.Expression; +import models.dataFlowModel.DataTransferChannel; +import models.dataFlowModel.DataTransferModel; +import models.visualModel.FormulaChannel; +import parser.Parser; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; +import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.WrongJsonExpression; + +import javax.swing.*; +import java.awt.*; +import java.util.EventObject; + +public class DataFlowCellEditor extends FlowCellEditor { + + public DataFlowCellEditor(DataFlowModelingStage stage, mxGraphComponent graphComponent) { + super(stage, graphComponent); + } + + @Override + public void startEditing(Object cellObj, EventObject eventObj) { + if (editingCell != null) { + stopEditing(true); + } + if (graphComponent.getGraph().getModel().isEdge(cellObj)) { + return; + } + DataTransferChannel ch = (DataTransferChannel) ((DataFlowModelingStage) stage).getChannel((mxCell) cellObj); + if (ch == null) { + // selected cell is a resource + return; + } + JPanel panel = new JPanel(); + if (ch instanceof FormulaChannel) { + JLabel label1 = new JLabel("Formula: "); + JLabel label2 = new JLabel("Source: "); + GridBagLayout layout = new GridBagLayout(); + panel.setLayout(layout); + GridBagConstraints gbc = new GridBagConstraints(); + + gbc.gridx = 0; + gbc.gridy = 0; + layout.setConstraints(label1, gbc); + panel.add(label1); + + gbc.gridx = 1; + gbc.gridy = 0; + JTextField formulaText = new JTextField(((FormulaChannel) ch).getFormula(), 15); + layout.setConstraints(formulaText, gbc); + panel.add(formulaText); + + gbc.gridx = 0; + gbc.gridy = 1; + layout.setConstraints(label2, gbc); + panel.add(label2); + + gbc.gridx = 1; + gbc.gridy = 1; + JTextArea textArea = new JTextArea(ch.getSourceText(), 7, 15); + textArea.setEditable(false); + layout.setConstraints(textArea, gbc); + panel.add(textArea); + + int option = JOptionPane.showConfirmDialog(null, panel, "Edit Formula Channel", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + if (option == JOptionPane.OK_OPTION) { + Parser.TokenStream stream = new Parser.TokenStream(); + Parser parser = new Parser(stream); + + String formula = formulaText.getText(); + stream.addLine(formula.split(Parser.EQUALS)[1]); + + try { + Expression exp = parser.parseTerm(stream, stage.getModel()); + ((FormulaChannel) ch).setFormula(formula); + ((FormulaChannel) ch).setFormulaTerm(exp); + } catch (ExpectedRightBracket | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + } else { + JTextArea textArea = new JTextArea(ch.getSourceText(), 15, 50); + textArea.setLineWrap(true); + textArea.setTabSize(4); + panel.add(textArea); + + int option = JOptionPane.showConfirmDialog(null, panel, "Channel Code", JOptionPane.OK_CANCEL_OPTION); + if (option == JOptionPane.OK_OPTION) { + ((DataFlowModelingStage) stage).setChannelCode(ch, textArea.getText()); + } + } + } + + @Override + public void stopEditing(boolean cancel) { + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DataFlowModelingStage.java b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DataFlowModelingStage.java new file mode 100644 index 0000000..6c97196 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DataFlowModelingStage.java @@ -0,0 +1,414 @@ +package application.editor.stages; + +import algorithms.Validation; +import application.editor.Editor; +import application.editor.FlowCellEditor; +import application.editor.Stage; +import com.mxgraph.model.mxCell; +import com.mxgraph.model.mxGeometry; +import com.mxgraph.model.mxGraphModel; +import com.mxgraph.model.mxGraphModel.mxTerminalChange; +import com.mxgraph.swing.mxGraphComponent; +import com.mxgraph.util.mxEventSource.mxIEventListener; +import com.mxgraph.util.mxPoint; +import models.algebra.Expression; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; +import models.dataFlowModel.DataFlowGraph; +import models.dataFlowModel.DataTransferChannel; +import models.dataFlowModel.DataTransferModel; +import models.dataFlowModel.ResourceNode; +import models.visualModel.FormulaChannel; +import parser.Parser; +import parser.exceptions.*; + +import java.awt.event.MouseListener; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class DataFlowModelingStage extends Stage { + private HashMap resNodeToCell = new HashMap<>(); + private HashMap channelToCell = new HashMap<>(); + private HashMap cellToResNode = new HashMap<>(); + private HashMap cellToChannel = new HashMap<>(); + + public DataFlowModelingStage(mxGraphComponent graphComponent) { + super(graphComponent); + } + + @Override + public void init(Stage prevStage) { + if (prevStage instanceof PushPullSelectionStage) { + if (((PushPullSelectionStage) prevStage).getResNodeToCell() != null) { + resNodeToCell = ((PushPullSelectionStage) prevStage).getResNodeToCell(); + } + if (((PushPullSelectionStage) prevStage).getChannelToCell() != null) { + channelToCell = ((PushPullSelectionStage) prevStage).getChannelToCell(); + } + for (ResourceNode resNode: resNodeToCell.keySet()) { + cellToResNode.put(resNodeToCell.get(resNode), resNode); + } + for (DataTransferChannel ch: channelToCell.keySet()) { + cellToChannel.put(channelToCell.get(ch), ch); + } + } + } + + @Override + public FlowCellEditor createCellEditor(mxGraphComponent graphComponent) { + return new DataFlowCellEditor(this, graphComponent); + } + + @Override + public mxIEventListener createChangeEventListener(Editor editor) { + return (sender, event) -> { + List terminals = new ArrayList<>(); + mxCell cell = null; + for (Object change : ((List) event.getProperties().get("changes"))) { + if (change instanceof mxTerminalChange) { + mxTerminalChange terminalChange = (mxTerminalChange) change; + cell = (mxCell) terminalChange.getCell(); + mxCell terminal = (mxCell) terminalChange.getTerminal(); + terminals.add(terminal); + } + } + if (terminals.size() == 2) { + if (!editor.connectEdge(cell, terminals.get(0), terminals.get(1))) { + graph.removeCells(new mxCell[]{cell}); + graph.clearSelection(); + } + } + }; + } + + @Override + public MouseListener createMouseEventListener(Editor editor) { + return null; + } + + @Override + public boolean canChangeFrom(Stage prevStage) { + return true; + } + + public void clear() { + model = null; + + ((mxGraphModel) graph.getModel()).clear(); + } + + public DataTransferModel getModel() { + if (model == null) { + model = new DataTransferModel(); + } + return model; + } + + public void setModel(DataTransferModel model) { + // Clear the mxGraph + clear(); + + this.model = model; + } + + public boolean isValid() { + if (model == null) { + return false; + } + return Validation.checkUpdateConflict(model); + } + + public ResourceNode getResourceNode(mxCell cell) { + return cellToResNode.get(cell); + } + + public Channel getChannel(mxCell cell) { + return cellToChannel.get(cell); + } + + public void addResourceNode(ResourceNode parentNode, String resName) { + ResourceNode resourceNode = null; + ResourcePath resourcePath = null; + if (parentNode == null) { + resourcePath = new ResourcePath(resName); + resourceNode = new ResourceNode(null, resourcePath); + getModel().addResourcePath(resourcePath); + } else { + ResourcePath parentPath = parentNode.getPrimaryResourcePath(); + if (resName.startsWith(Parser.LEFT_CURLY_BRACKET) && resName.endsWith(Parser.RIGHT_CURLY_BRACKET)) { + Parser.TokenStream stream = new Parser.TokenStream(); + Parser parser = new Parser(stream); + stream.addLine(resName.substring(1, resName.length() - 1)); + try { + Expression exp = parser.parseTerm(stream, getModel()); + resourcePath = new ResourcePath(parentPath, exp); + resourceNode = new ResourceNode(parentNode, resourcePath); + getModel().addResourcePath(resourcePath); + } catch (ExpectedRightBracket | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } else { + resourcePath = new ResourcePath(parentPath, resName); + resourceNode = new ResourceNode(parentNode, resourcePath); + getModel().addResourcePath(resourcePath); + } + } + + graph.getModel().beginUpdate(); + mxCell root = (mxCell) graph.getDefaultParent(); + try { + if (parentNode == null) { + mxCell resCell = (mxCell) graph.insertVertex(root, null, resourceNode.getPrimaryResourcePath().getName(), 20, 20, 80, 30, "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top"); // insert a resource as a vertex + resNodeToCell.put(resourceNode, resCell); + cellToResNode.put(resCell, resourceNode); + } else { + mxCell parentCell = resNodeToCell.get(parentNode); + double pw = parentCell.getGeometry().getWidth(); + double ph = parentCell.getGeometry().getHeight(); + mxCell resCell = (mxCell) graph.insertVertex(parentCell, null, resourceNode.getPrimaryResourcePath().getName(), 20, 20, pw * 0.8, ph * 0.8, "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top"); // insert a resource as a vertex + resNodeToCell.put(resourceNode, resCell); + cellToResNode.put(resCell, resourceNode); + } + } finally { + graph.getModel().endUpdate(); + } + } + + public void addChannel(DataTransferChannel channel) { + getModel().addChannel(channel); + + graph.getModel().beginUpdate(); + mxCell root = (mxCell) graph.getDefaultParent(); + try { + mxGeometry geo1 = new mxGeometry(0, 0.5, PORT_DIAMETER, PORT_DIAMETER); + geo1.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); + geo1.setRelative(true); + + mxGeometry geo2 = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); + geo2.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); + geo2.setRelative(true); + + String channelName = channel.getChannelName(); + if (channel.getSelectors().size() > 0) { + channelName += "("; + String delimiter = ""; + for (Selector s: channel.getSelectors()) { + Expression exp = s.getExpression(); + String selectorName = exp.toString(); + channelName += delimiter + selectorName; + delimiter = ", "; + } + channelName += ")"; + } + Object chCell = graph.insertVertex(root, null, channelName, 150, 20, 30, 30, "verticalAlign=top"); // insert a channel as a vertex + mxCell port_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); + port_in.setVertex(true); + graph.addCell(port_in, chCell); // insert the input port of a channel + mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); + port_out.setVertex(true); + graph.addCell(port_out, chCell); // insert the output port of a channel + channelToCell.put(channel, (mxCell) chCell); + cellToChannel.put((mxCell) chCell, channel); + cellToChannel.put(port_in, channel); + cellToChannel.put(port_out, channel); + } finally { + graph.getModel().endUpdate(); + } + } + + public void addEventChannel(DataTransferChannel eventChannel) { + getModel().addInputChannel(eventChannel); + + graph.getModel().beginUpdate(); + mxCell root = (mxCell) graph.getDefaultParent(); + try { + mxGeometry geo2 = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); + geo2.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); + geo2.setRelative(true); + + String channelName = eventChannel.getChannelName(); + if (eventChannel.getSelectors().size() > 0) { + channelName += "("; + String delimiter = ""; + for (Selector s: eventChannel.getSelectors()) { + Expression exp = s.getExpression(); + String selectorName = exp.toString(); + channelName += delimiter + selectorName; + delimiter = ", "; + } + channelName += ")"; + } + Object chCell = graph.insertVertex(root, null, channelName, 150, 20, 30, 30, "verticalAlign=top"); // insert an I/O channel as a vertex + mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); + port_out.setVertex(true); + graph.addCell(port_out, chCell); // insert the output port of a channel + channelToCell.put(eventChannel, (mxCell) chCell); + cellToChannel.put((mxCell) chCell, eventChannel); + cellToChannel.put(port_out, eventChannel); + } finally { + graph.getModel().endUpdate(); + } + } + + public void addFormulaChannel(FormulaChannel formulaChannel) { + getModel().addChannel(formulaChannel); + + graph.getModel().beginUpdate(); + mxCell root = (mxCell) graph.getDefaultParent(); + try { + mxGeometry geo1 = new mxGeometry(0, 0.5, PORT_DIAMETER, PORT_DIAMETER); + geo1.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); + geo1.setRelative(true); + + mxGeometry geo2 = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); + geo2.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); + geo2.setRelative(true); + + String channelName = formulaChannel.getChannelName(); + if (formulaChannel.getSelectors().size() > 0) { + channelName += "("; + String delimiter = ""; + for (Selector s: formulaChannel.getSelectors()) { + Expression exp = s.getExpression(); + String selectorName = exp.toString(); + channelName += delimiter + selectorName; + delimiter = ", "; + } + channelName += ")"; + } + Object chCell = graph.insertVertex(root, null, channelName, 150, 20, 30, 30, "verticalAlign=top"); // insert a channel as a vertex + mxCell port_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); + port_in.setVertex(true); + graph.addCell(port_in, chCell); // insert the input port of a channel + mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); + port_out.setVertex(true); + graph.addCell(port_out, chCell); // insert the output port of a channel + channelToCell.put(formulaChannel, (mxCell) chCell); + cellToChannel.put((mxCell) chCell, formulaChannel); + cellToChannel.put(port_in, formulaChannel); + cellToChannel.put(port_out, formulaChannel); + } finally { + graph.getModel().endUpdate(); + } + } + + public boolean connectEdge(mxCell edge, mxCell src, mxCell dst) { + DataTransferChannel srcCh = cellToChannel.get(src); + if (srcCh == null) { + ResourceNode srcResNode = cellToResNode.get(src); + DataTransferChannel dstCh = cellToChannel.get(dst); + if (srcResNode == null || dstCh == null) { + return false; + } + // resource to channel edge + ResourcePath srcRes = srcResNode.getPrimaryResourcePath(); + if (srcResNode.getIndegree() + srcResNode.getOutdegree() == 0) { + srcResNode.addOutSideResource(dstCh, srcRes); + } else { + srcRes = new ResourcePath(srcRes.getName(), srcRes.getResourceHierarchy()); + model.addResourcePath(srcRes); + } + ChannelMember srcCm = new ChannelMember(srcRes); + dstCh.addChannelMemberAsInput(srcCm); + edge.setValue(new Editor.SrcDstAttribute(srcRes, dstCh)); + return true; + } + ResourceNode dstResNode = cellToResNode.get(dst); + if (dstResNode == null) { + return false; + } + // channel to resource edge + ResourcePath dstRes = dstResNode.getPrimaryResourcePath(); + if (dstResNode.getIndegree() + dstResNode.getOutdegree() == 0) { + dstResNode.addInSideResource(srcCh, dstRes); + } else { + dstRes = new ResourcePath(dstRes.getName(), dstRes.getResourceHierarchy()); + model.addResourcePath(dstRes); + } + ChannelMember dstCm = new ChannelMember(dstRes); + srcCh.addChannelMemberAsOutput(dstCm); + edge.setValue(new Editor.SrcDstAttribute(srcCh, dstRes)); + return true; + } + + public void delete() { + for (Object obj : graph.getSelectionCells()) { + mxCell cell = (mxCell) obj; + if (cell.isEdge()) { + mxCell srcCell = (mxCell) cell.getSource(); + mxCell dstCell = (mxCell) cell.getTarget(); + if (cellToResNode.get(srcCell) != null) { + // resource to channel edge + DataTransferChannel ch = cellToChannel.get(dstCell); + ch.removeChannelMember(cellToResNode.get(srcCell).getOutSideResource(ch)); + } else if (cellToResNode.get(dstCell) != null) { + // channel to resource edge + DataTransferChannel ch = cellToChannel.get(srcCell); + ch.removeChannelMember(cellToResNode.get(dstCell).getInSideResource(ch)); + } + } else if (cell.isVertex()) { + if (cellToChannel.get(cell) != null) { + DataTransferChannel ch = cellToChannel.get(cell); + if (ch.getInputChannelMembers().size() == 0) { + model.removeInputChannel(cellToChannel.get(cell).getChannelName()); + } else { + model.removeChannel(cellToChannel.get(cell).getChannelName()); + } + } else if (cellToResNode.get(cell) != null) { + for (ResourcePath resPath: cellToResNode.get(cell).getInSideResources()) { + model.removeResourcePath(resPath); + } + for (ResourcePath resPath: cellToResNode.get(cell).getOutSideResources()) { + model.removeResourcePath(resPath); + } + } + } + } + graph.removeCells(graph.getSelectionCells()); + } + + public void setChannelCode(DataTransferChannel ch, String code) { + ch.setSourceText(code); + Parser.TokenStream stream = new Parser.TokenStream(); + Parser parser = new Parser(stream); + + for (String line : code.split("\n")) { + stream.addLine(line); + } + try { + DataTransferChannel ch2 = parser.parseChannel(getModel()); + for (ChannelMember chm2 : ch2.getInputChannelMembers()) { + for (ChannelMember chm : ch.getInputChannelMembers()) { + if (chm2.getResource().getResourceHierarchy() == chm.getResource().getResourceHierarchy()) { + chm.setStateTransition(chm2.getStateTransition()); + break; + } + } + } + for (ChannelMember chm2 : ch2.getOutputChannelMembers()) { + for (ChannelMember chm : ch.getOutputChannelMembers()) { + if (chm2.getResource().getResourceHierarchy() == chm.getResource().getResourceHierarchy()) { + chm.setStateTransition(chm2.getStateTransition()); + break; + } + } + } + for (ChannelMember chm2 : ch2.getReferenceChannelMembers()) { + for (ChannelMember chm : ch.getReferenceChannelMembers()) { + if (chm2.getResource().getResourceHierarchy() == chm.getResource().getResourceHierarchy()) { + chm.setStateTransition(chm2.getStateTransition()); + break; + } + } + } + } catch (ExpectedRightBracket | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | + ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | + WrongLHSExpression | WrongRHSExpression | ExpectedAssignment | ExpectedRightCurlyBracket | + WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionCellEditor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionCellEditor.java new file mode 100644 index 0000000..8ca07ef --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionCellEditor.java @@ -0,0 +1,132 @@ +package application.editor.stages; + +import application.editor.FlowCellEditor; +import com.mxgraph.model.mxIGraphModel; +import com.mxgraph.swing.mxGraphComponent; +import com.mxgraph.util.mxConstants; +import com.mxgraph.util.mxUtils; +import com.mxgraph.view.mxCellState; +import models.dataFlowModel.PushPullAttribute; +import models.dataFlowModel.PushPullValue; + +import javax.swing.*; +import java.awt.*; +import java.util.EventObject; +import java.util.List; + +public class PushPullSelectionCellEditor extends FlowCellEditor { + + public int DEFAULT_MIN_WIDTH = 70; + public int DEFAULT_MIN_HEIGHT = 30; + public double DEFAULT_MINIMUM_EDITOR_SCALE = 1; + + protected double minimumEditorScale = DEFAULT_MINIMUM_EDITOR_SCALE; + protected int minimumWidth = DEFAULT_MIN_WIDTH; + protected int minimumHeight = DEFAULT_MIN_HEIGHT; + + private EventObject trigger; + private JComboBox comboBox; + + public PushPullSelectionCellEditor(PushPullSelectionStage stage, mxGraphComponent graphComponent) { + super(stage, graphComponent); + } + + @Override + public void startEditing(Object cellObj, EventObject eventObj) { + if (editingCell != null) { + stopEditing(true); + } + if (!graphComponent.getGraph().getModel().isEdge(cellObj)) { + return; + } + mxCellState state = graphComponent.getGraph().getView().getState(cellObj); + if (state != null && state.getLabel() != null && !state.getLabel().isEmpty()) { + editingCell = cellObj; + trigger = eventObj; + + double scale = Math.max(minimumEditorScale, graphComponent.getGraph().getView().getScale()); + Object value = graphComponent.getGraph().getModel().getValue(cellObj); + if (value instanceof PushPullAttribute) { + PushPullAttribute attr = (PushPullAttribute) value; + comboBox = new JComboBox<>(attr.getOptionStrings()); + comboBox.setBorder(BorderFactory.createEmptyBorder()); + comboBox.setOpaque(false); + comboBox.setBounds(getEditorBounds(state, scale)); + comboBox.setVisible(true); + graphComponent.getGraphControl().add(comboBox, 0); + comboBox.updateUI(); + } + } + } + + @Override + public void stopEditing(boolean cancel) { + if (editingCell == null) { + return; + } + comboBox.transferFocusUpCycle(); + Object cell = editingCell; + editingCell = null; + if (!cancel) { + EventObject trig = trigger; + trigger = null; + Object value = graphComponent.getGraph().getModel().getValue(cell); + if (value instanceof PushPullAttribute) { + PushPullAttribute attr = (PushPullAttribute) value; + List options = attr.getOptions(); + PushPullValue selected = null; + for (PushPullValue option : options) { + if (option.toString().equals(getCurrentValue())) { + selected = option; + break; + } + } + if (selected != null) { + attr.selectOption(selected); + } + graphComponent.labelChanged(cell, attr, trig); + } + } else { + mxCellState state = graphComponent.getGraph().getView().getState(cell); + graphComponent.redraw(state); + } + + if (comboBox.getParent() != null) { + comboBox.setVisible(false); + comboBox.getParent().remove(comboBox); + } + + graphComponent.requestFocusInWindow(); + } + + public String getCurrentValue() { + return (String) comboBox.getSelectedItem(); + } + + /** + * Returns the bounds to be used for the editor. + */ + public Rectangle getEditorBounds(mxCellState state, double scale) { + mxIGraphModel model = state.getView().getGraph().getModel(); + Rectangle bounds = state.getLabelBounds().getRectangle(); + bounds.height += 10; + + // Applies the horizontal and vertical label positions + if (model.isVertex(state.getCell())) { + String horizontal = mxUtils.getString(state.getStyle(), mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER); + if (horizontal.equals(mxConstants.ALIGN_LEFT)) { + bounds.x -= (int) state.getWidth(); + } else if (horizontal.equals(mxConstants.ALIGN_RIGHT)) { + bounds.x += (int) state.getWidth(); + } + String vertical = mxUtils.getString(state.getStyle(), mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE); + if (vertical.equals(mxConstants.ALIGN_TOP)) { + bounds.y -= (int) state.getHeight(); + } else if (vertical.equals(mxConstants.ALIGN_BOTTOM)) { + bounds.y += (int) state.getHeight(); + } + } + bounds.setSize((int) Math.max(bounds.getWidth(), Math.round(minimumWidth * scale)), (int) Math.max(bounds.getHeight(), Math.round(minimumHeight * scale))); + return bounds; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java new file mode 100644 index 0000000..632e16a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java @@ -0,0 +1,371 @@ +package application.editor.stages; + +import algorithms.DataTransferModelAnalyzer; +import application.editor.Editor; +import application.editor.FlowCellEditor; +import application.editor.Stage; +import com.mxgraph.model.mxCell; +import com.mxgraph.model.mxGeometry; +import com.mxgraph.model.mxGraphModel; +import com.mxgraph.swing.mxGraphComponent; +import com.mxgraph.util.mxEventSource.mxIEventListener; +import com.mxgraph.util.mxPoint; + +import generators.CodeGenerator; +import generators.CodeGeneratorFromDataFlowGraph; +import generators.JavaSpecific; +import generators.StandaloneSpecific; +import models.Edge; +import models.algebra.*; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; +import models.dataFlowModel.*; + +import java.awt.event.MouseListener; +import java.util.*; + +public class PushPullSelectionStage extends Stage { + + private DataFlowGraph dataFlowGraph = null; + private HashMap resNodeToCell; + private HashMap channelToCell; + + public PushPullSelectionStage(mxGraphComponent graphComponent) { + super(graphComponent); + } + + @Override + public void init(Stage prevStage) { + if (prevStage instanceof DataFlowModelingStage) { + model = prevStage.getModel(); + dataFlowGraph = analyzeDataTransferModel(model); + } + } + + @Override + public FlowCellEditor createCellEditor(mxGraphComponent graphComponent) { + return new PushPullSelectionCellEditor(this, graphComponent); + } + + @Override + public mxIEventListener createChangeEventListener(Editor editor) { + return (sender, eventObject) -> { + List terminals = new ArrayList<>(); + mxCell cell = null; + for (Object change : ((List) eventObject.getProperties().get("changes"))) { + if (change instanceof mxGraphModel.mxTerminalChange) { + mxGraphModel.mxTerminalChange terminalChange = (mxGraphModel.mxTerminalChange) change; + cell = (mxCell) terminalChange.getCell(); + mxCell terminal = (mxCell) terminalChange.getTerminal(); + terminals.add(terminal); + } + } + if (terminals.size() == 2) { + // cancel connect + graph.removeCells(new mxCell[]{cell}); + graph.clearSelection(); + } + }; + } + + @Override + public MouseListener createMouseEventListener(Editor editor) { + return null; + } + + @Override + public boolean canChangeFrom(Stage prevStage) { + if (prevStage instanceof DataFlowModelingStage) { + return ((DataFlowModelingStage) prevStage).isValid(); + } + return false; + } + + private DataFlowGraph analyzeDataTransferModel(DataTransferModel model) { + DataFlowGraph flowGraph = DataTransferModelAnalyzer.createDataFlowGraphWithStateStoringAttribute(model); + dataFlowGraph = DataTransferModelAnalyzer.annotateWithSelectableDataTransferAttiribute(flowGraph); + mxCell parent = (mxCell) graph.getDefaultParent(); + if (parent.getChildCount() == 0) { + constructGraph(); // Construct data-flow graph (on file open action) + } + updateEdgeAttributes(dataFlowGraph); // Update push/pull selection pull-downs + return dataFlowGraph; + } + + private void updateEdgeAttributes(DataFlowGraph dataFlowGraph) { + mxCell root = (mxCell) graph.getDefaultParent(); + + graph.getModel().beginUpdate(); + try { + // add input, output and reference edges + for (Edge e : dataFlowGraph.getEdges()) { + if (e instanceof DataFlowEdge) { + DataFlowEdge dataFlow = (DataFlowEdge) e; + if (!dataFlow.isChannelToResource()) { + ResourceNode srcRes = (ResourceNode) dataFlow.getSource(); + DataTransferChannel channel = ((ChannelNode) dataFlow.getDestination()).getChannel(); + // input edge + for (Object edge : graph.getChildEdges(root)) { + mxCell edgeCell = (mxCell) edge; + if (edgeCell.getValue() instanceof Editor.SrcDstAttribute) { + Editor.SrcDstAttribute edgeAttr = (Editor.SrcDstAttribute) edgeCell.getValue(); + if (srcRes.getPrimaryResourcePath().equals(edgeAttr.getSource()) && channel.equals(edgeAttr.getDestination())) { + edgeCell.setValue(dataFlow.getAttribute()); + break; + } + } + } + } + } + } + } finally { + graph.getModel().endUpdate(); + } + graph.refresh(); + } + + /** + * Construct a mxGraph from DataFlowGraph + */ + public void constructGraph() { + ((mxGraphModel) graph.getModel()).clear(); + mxCell parent = (mxCell) graph.getDefaultParent(); + + graph.getModel().beginUpdate(); + try { + Map channelInToCell = new HashMap<>(); + Map channelOutToCell = new HashMap<>(); + channelToCell = new HashMap<>(); + resNodeToCell = new HashMap<>(); + + mxGeometry geoPortIn = new mxGeometry(0, 0.5, PORT_DIAMETER, PORT_DIAMETER); + geoPortIn.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); + geoPortIn.setRelative(true); + + mxGeometry geoPortOut = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); + geoPortOut.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); + geoPortOut.setRelative(true); + + // create resource vertices + for (ResourceNode resourceNode : dataFlowGraph.getRootResourceNodes()) { + int w = 80; + int h = 30; + ResourcePath resourcePath = resourceNode.getPrimaryResourcePath(); + mxCell resourceCell = (mxCell) graph.insertVertex(parent, null, resourcePath.getLeafResourceName(), 20, 20, w, h, "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top"); // insert a resource as a vertex + resNodeToCell.put(resourceNode, resourceCell); + createChildResourceVertices(resourceCell, resourceNode, w, h); + } + + // create channel vertices + for (ChannelNode channelNode : dataFlowGraph.getRootChannelNodes()) { + DataTransferChannel channel = channelNode.getChannel(); + if (!channel.getInputResources().isEmpty()) { + // Normal channel + if (channelInToCell.get(channel) == null || channelOutToCell.get(channel) == null) { + String channelName = channel.getChannelName(); + if (channel.getSelectors().size() > 0) { + channelName += "("; + String delimiter = ""; + for (Selector s: channel.getSelectors()) { + Expression exp = s.getExpression(); + String selectorName = exp.toString(); + channelName += delimiter + selectorName; + delimiter = ", "; + } + channelName += ")"; + } + int w = 60; + int h = 30; + if (channelNode.getChildren().size() > 0) { + w *= 2; + h *= 2; + } + mxCell channelCell = (mxCell) graph.insertVertex(parent, null, channelName, 150, 20, w, h, "verticalAlign=top"); // insert a channel as a vertex + channelToCell.put(channel, channelCell); + + mxCell portIn = new mxCell(null, geoPortIn, "shape=ellipse;perimter=ellipsePerimeter"); + portIn.setVertex(true); + graph.addCell(portIn, channelCell); // insert the input port of a channel + channelInToCell.put(channel, portIn); + + mxCell portOut = new mxCell(null, geoPortOut, "shape=ellipse;perimter=ellipsePerimeter"); + portOut.setVertex(true); + graph.addCell(portOut, channelCell); // insert the output port of a channel + channelOutToCell.put(channel, portOut); + createChildChannelVertices(channelCell, channelNode, channelInToCell, channelOutToCell, geoPortIn, geoPortOut, w, h); + } + } else { + // Event channel + if (channelOutToCell.get(channel) == null) { + String channelName = channel.getChannelName(); + if (channel.getSelectors().size() > 0) { + channelName += "("; + String delimiter = ""; + for (Selector s: channel.getSelectors()) { + Expression exp = s.getExpression(); + String selectorName = exp.toString(); + channelName += delimiter + selectorName; + delimiter = ", "; + } + channelName += ")"; + } + int w = 40; + int h = 30; + if (channelNode.getChildren().size() > 0) { + w *= 2; + h *= 2; + } + mxCell channelCell = (mxCell) graph.insertVertex(parent, null, channelName, 150, 20, w, h, "verticalAlign=top"); // insert a channel as a vertex + channelToCell.put(channel, channelCell); + + mxCell portOut = new mxCell(null, geoPortOut, "shape=ellipse;perimter=ellipsePerimeter"); + portOut.setVertex(true); + graph.addCell(portOut, channelCell); // insert the output port of a channel + channelOutToCell.put(channel, portOut); + createChildChannelVertices(channelCell, channelNode, channelInToCell, channelOutToCell, geoPortIn, geoPortOut, w, h); + } + } + } + + // add input, output and reference edges + for (Edge edge : dataFlowGraph.getEdges()) { + DataFlowEdge dataFlowEdge = (DataFlowEdge) edge; + if (dataFlowEdge.isChannelToResource()) { + // output edge + DataTransferChannel channel = ((ChannelNode) dataFlowEdge.getSource()).getChannel(); + ResourcePath dstRes = ((ResourceNode) dataFlowEdge.getDestination()).getInSideResource(channel); + graph.insertEdge(parent, null, new Editor.SrcDstAttribute(channel, dstRes), channelOutToCell.get(channel), resNodeToCell.get((ResourceNode) dataFlowEdge.getDestination()), "movable=false"); + } else { + // input edge + DataTransferChannel channel = ((ChannelNode) dataFlowEdge.getDestination()).getChannel(); + ResourcePath srcRes = ((ResourceNode) dataFlowEdge.getSource()).getOutSideResource(channel); + Set> toRes = getResourceDependencyForChannel(channel, dataFlowGraph); + for (Map.Entry RtoR : toRes) { + graph.insertEdge(parent, null, null, resNodeToCell.get(RtoR.getValue()), resNodeToCell.get(RtoR.getKey()), "dashed=true;movable=false"); + } + + graph.insertEdge(parent, null, new Editor.SrcDstAttribute(srcRes, channel), resNodeToCell.get((ResourceNode) dataFlowEdge.getSource()), channelInToCell.get(channel), "movable=false"); + } + } + + for (Channel ch : model.getChannels()) { + // reference edges + DataTransferChannel channel = (DataTransferChannel) ch; + for (ResourcePath refRes : channel.getReferenceResources()) { + graph.insertEdge(parent, null, null, resNodeToCell.get(dataFlowGraph.getResourceNode(refRes)), channelInToCell.get(channel), "dashed=true;movable=false"); + } + } + } finally { + graph.getModel().endUpdate(); + } + } + + private void createChildResourceVertices(mxCell parentCell, ResourceNode parentResNode, int w, int h) { + for (ResourceNode resNode: parentResNode.getChildren()) { + ResourcePath resPath = resNode.getPrimaryResourcePath(); + mxCell resourceCell = (mxCell) graph.insertVertex(parentCell, null, resPath.getName(), 0, 0, w, h, "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top"); // insert a resource as a vertex + resNodeToCell.put(resNode, resourceCell); + createChildResourceVertices(resourceCell, resNode, w, h); + } + } + + private void createChildChannelVertices(mxCell parentCell, ChannelNode parentChannelNode, + Map channelInToCell, Map channelOutToCell, mxGeometry geoPortIn, mxGeometry geoPortOut, int w, int h) { + for (ChannelNode channelNode: parentChannelNode.getChildren()) { + DataTransferChannel channel = channelNode.getChannel(); + if (!channel.getInputResources().isEmpty()) { + // Normal channel + if (channelInToCell.get(channel) == null || channelOutToCell.get(channel) == null) { + String channelName = channel.getChannelName(); + if (channel.getSelectors().size() > 0) { + channelName += "("; + String delimiter = ""; + for (Selector s: channel.getSelectors()) { + Expression exp = s.getExpression(); + String selectorName = exp.toString(); + channelName += delimiter + selectorName; + delimiter = ", "; + } + channelName += ")"; + } + mxCell channelCell = (mxCell) graph.insertVertex(parentCell, null, channelName, w / 4, h / 4, w / 2, h / 2, "verticalAlign=top"); // insert a channel as a vertex + channelToCell.put(channel, channelCell); + + mxCell portIn = new mxCell(null, geoPortIn, "shape=ellipse;perimter=ellipsePerimeter"); + portIn.setVertex(true); + graph.addCell(portIn, channelCell); // insert the input port of a channel + channelInToCell.put(channel, portIn); + + mxCell portOut = new mxCell(null, geoPortOut, "shape=ellipse;perimter=ellipsePerimeter"); + portOut.setVertex(true); + graph.addCell(portOut, channelCell); // insert the output port of a channel + channelOutToCell.put(channel, portOut); + createChildChannelVertices(channelCell, channelNode, channelInToCell, channelOutToCell, geoPortIn, geoPortOut, w / 2, h / 2); + } + } else { + // Event channel + if (channelOutToCell.get(channel) == null) { + String channelName = channel.getChannelName(); + if (channel.getSelectors().size() > 0) { + channelName += "("; + String delimiter = ""; + for (Selector s: channel.getSelectors()) { + Expression exp = s.getExpression(); + String selectorName = exp.toString(); + channelName += delimiter + selectorName; + delimiter = ", "; + } + channelName += ")"; + } + mxCell channelCell = (mxCell) graph.insertVertex(parentCell, null, channelName, w / 4, h / 4, w / 2, h / 2, "verticalAlign=top"); // insert a channel as a vertex + channelToCell.put(channel, channelCell); + + mxCell portOut = new mxCell(null, geoPortOut, "shape=ellipse;perimter=ellipsePerimeter"); + portOut.setVertex(true); + graph.addCell(portOut, channelCell); // insert the output port of a channel + channelOutToCell.put(channel, portOut); + createChildChannelVertices(channelCell, channelNode, channelInToCell, channelOutToCell, geoPortIn, geoPortOut, w / 2, h / 2); + } + } + } + } + + private Set> getResourceDependencyForChannel(DataTransferChannel ch, DataFlowGraph dataFlowGraph) { + Set> resourceDependency = new HashSet<>(); + if (!ch.getOutputChannelMembers().isEmpty()) { + try { + Map>> dependency = ch.fillOutsideResourcePaths(ch.getOutputChannelMembers().iterator().next(), new CodeGeneratorFromDataFlowGraph(new StandaloneSpecific(), new JavaSpecific()).getPullAccessor(new StandaloneSpecific())); + for (ChannelMember srcMem : dependency.keySet()) { + ResourceNode srcNode = dataFlowGraph.getResourceNode(srcMem.getResource()); + if (srcNode != null) { + for (ChannelMember dstMem : dependency.get(srcMem).getValue()) { + ResourceNode dstNode = dataFlowGraph.getResourceNode(dstMem.getResource()); + while (srcNode.getResourceHierarchy().getNumParameters() == 0 && srcNode.getParent() != null) { + srcNode = srcNode.getParent(); + } + resourceDependency.add(new AbstractMap.SimpleEntry<>(srcNode, dstNode)); + } + } + } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | + UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + } + return resourceDependency; + } + + public DataFlowGraph getDataFlowGraph() { + return dataFlowGraph; + } + + public HashMap getResNodeToCell() { + return resNodeToCell; + } + + public HashMap getChannelToCell() { + return channelToCell; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/layouts/DAGLayout.java b/AlgebraicDataflowArchitectureModel/src/application/layouts/DAGLayout.java index d493d10..9200de6 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/layouts/DAGLayout.java +++ b/AlgebraicDataflowArchitectureModel/src/application/layouts/DAGLayout.java @@ -1,8 +1,13 @@ package application.layouts; import java.util.ArrayList; -import java.util.Collections; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; import com.mxgraph.layout.mxGraphLayout; import com.mxgraph.model.mxCell; @@ -13,131 +18,823 @@ import com.mxgraph.view.mxGraphView; public class DAGLayout extends mxGraphLayout { + private mxIGraphModel graphModel; + private mxGraphView view; + private Map> dotEdges; + private List> paths; + private List order; + private Map> orderInResourceHierarchy; + private Set usedPathIndex; + private List cells; + private Set roots; + private Map resourceToRoot; + private Set resources; + private Set channels; + private Set eventChannels; + private Map> vertexToDepths; + private Map> cellToPathIndex; + private Map> cellGeo; + final double MOVE_X = 100; + final double MOVE_Y = 50; + final double WIDTH = 80; + final double HEIGHT = 30; + final double SHIFT = WIDTH / 4; + final double SPACE = 10; + final double MARGIN_WIDTH = 30; + final double MARGIN_HEIGHT = 30; + final double delta = Math.pow(10, -3); public DAGLayout(mxGraph graph) { super(graph); - } - - public void execute(Object parent) { - mxIGraphModel model = graph.getModel(); - model.beginUpdate(); + graphModel = graph.getModel(); + view = graph.getView(); + dotEdges = new HashMap<>(); + paths = new ArrayList<>(); + order = new ArrayList<>(); + orderInResourceHierarchy = new HashMap<>(); + usedPathIndex = new HashSet<>(); + cells = new ArrayList<>(); + roots = new HashSet<>(); + resourceToRoot = new HashMap<>(); + resources = new HashSet<>(); + channels = new HashSet<>(); + eventChannels = new HashSet<>(); + vertexToDepths = new HashMap<>(); + cellToPathIndex = new HashMap<>(); + cellGeo = new HashMap<>(); + } + + public void execute(Object rootCell) { + graphModel.beginUpdate(); try { - List> map = new ArrayList>(); - List moved = new ArrayList<>(); - - for (int i = 0; i < model.getChildCount(parent); i++) { + // Initialize cells, roots, channels and eventChannels fields. + for (int i = 0; i < graphModel.getChildCount(rootCell); i++) { + mxCell cell = (mxCell) graphModel.getChildAt(rootCell, i); - mxCell cell = (mxCell) model.getChildAt(parent, i); - - if (model.isVertex(cell)) { - mxGraphView view = graph.getView(); + if (graphModel.isVertex(cell)) { mxCellState state = view.getState(cell); + cells.add(cell); - if (!"ellipse".equals(state.getStyle().get("shape")) && (cell.getEdgeCount() == 1) && !"true".equals(state.getStyle().get("dashed"))) { - List newline = new ArrayList(); - map.add(newline); - lines(map, cell); + if ("ellipse".equals(state.getStyle().get("shape"))) { + // If the cell represents a root resource. + roots.add(cell); + orderInResourceHierarchy.put(cell, new ArrayList<>()); + traverseResourceHierarchy(cell, cell, 0); + } + + if ("rectangle".equals(state.getStyle().get("shape"))) { + // If the cell represents a root channel. + if ("true".equals(state.getStyle().get("dashed"))) { + continue; + } + + boolean bEventChannel = true; + for (int j = 0; j < cell.getEdgeCount(); j++) { + mxCell edge = (mxCell) cell.getEdgeAt(j); + if (edge.getTarget() == cell) { + bEventChannel = false; + } + } + + if (bEventChannel) { + // If the cell represents a root event channel. + eventChannels.add(cell); + } else { + channels.add(cell); + } + orderInResourceHierarchy.put(cell, new ArrayList<>()); } } } - sort(map, 0, false); - - // layout - int count; - int skip = 0; - mxGraphView view = graph.getView(); - for (int i = 0; i < map.size(); i++) { - count = 0; - for (int j = 0; j < map.get(i).size(); j++) { - mxGeometry geom = (mxGeometry) map.get(i).get(j).getGeometry().clone(); - mxCellState state = view.getState(map.get(i).get(j)); - if (checkmoved(moved, map.get(i).get(j))) { - if ("ellipse".equals(state.getStyle().get("shape"))){ - geom.setX(50 + j*200); - } else { - geom.setX(100 + j*200); - } - geom.setY(100 + (i-skip)*100); - model.setGeometry(map.get(i).get(j), geom); - moved.add(map.get(i).get(j).getId()); - } else if (geom.getX() < 100 + j*150) { - if ("ellipse".equals(state.getStyle().get("shape"))){ - geom.setX(50 + j*200); - } else { - geom.setX(100 + j*200); - } - geom.setY(100 + (i-skip)*100); - model.setGeometry(map.get(i).get(j), geom); - } else { - count++; - } + // For all cells + for (mxCell c : cells) { + c.getGeometry().setX(0); + c.getGeometry().setY(0); + + if (resources.contains(c)) { + // For a resource cell. + view.getState(c).getStyle().put("verticalAlign", "top"); + c.getGeometry().setWidth(WIDTH); + c.getGeometry().setHeight(HEIGHT); } - if (count >= map.get(i).size())skip++; } + // Initialize dotEdges. + for (mxCell c : cells) { + dotEdges.put(c, new HashSet<>()); + } + + for (mxCell eventCh : eventChannels) { + List newPath = new ArrayList(); + paths.add(newPath); + constructPaths(eventCh, 0); + } + + recalcDepths(); + + for (int i = 0; i < paths.size(); i++) { + for (mxCell cell : paths.get(i)) { + if (cellToPathIndex.get(cell) == null) { + cellToPathIndex.put(cell, new ArrayList<>()); + } + cellToPathIndex.get(cell).add(i); + } + } + + sortPaths(); + + boolean isVersion1 = true; + + System.out.println(vertexToDepths); + if (isVersion1) { + layout1((mxCell) rootCell); + } else { + layout2((mxCell) rootCell); + } } finally { - model.endUpdate(); + graphModel.endUpdate(); } } + public void traverseResourceHierarchy(mxCell rootResourceCell, mxCell curResourceCell, int layer) { + resourceToRoot.put(curResourceCell, rootResourceCell); + resources.add(curResourceCell); + if (rootResourceCell != curResourceCell) { + orderInResourceHierarchy.get(rootResourceCell).add(curResourceCell); + } + + int childNum = graphModel.getChildCount(curResourceCell); + for (int i = 0; i < childNum; i++) { + mxCell childCell = (mxCell) graphModel.getChildAt(curResourceCell, i); + cells.add(childCell); + resources.add(childCell); + traverseResourceHierarchy(rootResourceCell, childCell, layer + 1); + } + } - public void lines(List> mapping, mxCell next) { - mapping.get(mapping.size()-1).add(next); - int tagcount = 0; - mxCell edge; - mxGraphView view = graph.getView(); - for (int i = 0; i < next.getEdgeCount(); i++) { - edge = (mxCell) next.getEdgeAt(i); + public void constructPaths(mxCell curCell, int depth) { + if (vertexToDepths.get(curCell) == null) { + vertexToDepths.put(curCell, Arrays.asList(depth, depth)); + } else { + List depths = vertexToDepths.get(curCell); + depths.set(0, Math.max(depths.get(0), depth)); + depths.set(1, depths.get(0)); + } + + paths.get(paths.size() - 1).add(curCell); + + int branchCount = 0; + for (int i = 0; i < curCell.getEdgeCount(); i++) { + mxCell edge = (mxCell) curCell.getEdgeAt(i); mxCellState state = view.getState(edge); - if (next != (mxCell) edge.getTarget() && ((mxCell) edge.getTarget() != null) && !"true".equals(state.getStyle().get("dashed"))) { - tagcount++; - if (tagcount > 1) { - List newline = new ArrayList(mapping.get(mapping.size()-1)); - while (newline.get(newline.size()-1).getId() != next.getId()) { - newline.remove(newline.size()-1); - } - mapping.add(newline); - lines(mapping, (mxCell) edge.getTarget()); - + mxCell dstCell = (mxCell) edge.getTarget(); + + if ((curCell != dstCell) && (dstCell != null)) { + if ("true".equals(state.getStyle().get("dashed"))) { + state.getStyle().put("strokeColor", "#800080"); + dotEdges.get(curCell).add(dstCell); } else { - lines(mapping, (mxCell) edge.getTarget()); + branchCount++; + if (branchCount > 1) { + // If a branch is found. + List newPath = new ArrayList(paths.get(paths.size() - 1)); + while (newPath.get(newPath.size() - 1).getId() != curCell.getId()) { + newPath.remove(newPath.size() - 1); + } + paths.add(newPath); + constructPaths(dstCell, depth + 1); + } else { + constructPaths(dstCell, depth + 1); + } } } } } - public boolean checkmoved(List list, mxCell cell) { - for (int i = 0; i < list.size(); i++) { - if (list.get(i).equals(cell.getId()))return false; + public void recalcDepths() { + while (true) { + boolean isUpdated = false; + + for (List path : paths) { + for (int i = 1; i < path.size(); i++) { + mxCell curCell = path.get(i); + mxCell prevCell = path.get(i - 1); + if (!(resources.contains(curCell) && resources.contains(prevCell))) { + // An edge from a resource to a channel + if (vertexToDepths.get(curCell).get(0) < vertexToDepths.get(prevCell).get(1) + 1) { + List dists = vertexToDepths.get(curCell); + dists.set(1, Math.max(dists.get(0), dists.get(1))); + dists.set(0, vertexToDepths.get(prevCell).get(1) + 1); + isUpdated = true; + } + } + } + } + + for (mxCell rootCell : roots) { + + // For all resource cells included in (under) the root resource cell. + for (mxCell cell : orderInResourceHierarchy.get(rootCell)) { + mxCell parentCell = (mxCell) graphModel.getParent(cell); + if (!vertexToDepths.containsKey(cell)) { + if (vertexToDepths.get(parentCell) != null) vertexToDepths.put(cell, Arrays.asList(vertexToDepths.get(parentCell).get(0), vertexToDepths.get(parentCell).get(0))); + } else { + if (vertexToDepths.get(parentCell) != null && vertexToDepths.get(parentCell).get(0) > vertexToDepths.get(cell).get(0)) { + List dists = vertexToDepths.get(cell); + dists.set(1, Math.max(dists.get(0), dists.get(1))); + dists.set(0, vertexToDepths.get(parentCell).get(0)); + isUpdated = true; + } + + if (vertexToDepths.get(parentCell) != null && vertexToDepths.get(parentCell).get(1) < vertexToDepths.get(cell).get(1)) { + List dists = vertexToDepths.get(parentCell); + dists.set(1, vertexToDepths.get(cell).get(1)); + isUpdated = true; + } + } + } + } + + if (!isUpdated) { + break; + } } - return true; } - public void sort(List> map, int n, boolean check) { - int msize = -1; - int mnum = -1; - if (check) { - for (int i = n; i < map.size(); i++) { - if (map.get(i).size() > msize && (map.get(n-1).get(0).getId().equals(map.get(i).get(0).getId()))) { - mnum = i; + public void sortPaths() { + for (int i = 0; i < paths.size(); i++) { + List path = paths.get(i); + + if (path.size() > 1 && roots.contains(path.get(1))) { + for (mxCell c : path) { + addPath(c); } } + } + } + + public void addPath(mxCell c) { + if (cellToPathIndex.get(c) != null) { + for (int i : cellToPathIndex.get(c)) { + if (!usedPathIndex.contains(i)) { + order.add(i); + } + usedPathIndex.add(i); + } + } + + for (int i = 0; i < graphModel.getChildCount(c); i++) { + mxCell child = (mxCell) graphModel.getChildAt(c, i); + addPath(child); + } + } + + public void layout1(mxCell s) { + Set movedSet = new HashSet<>(); + Map> movedMap = new TreeMap<>(); + Map distToMaxX = new HashMap<>(); + double maxY = 0; + int maxD = 0; + + putCellGeo(s, 0, 0); + + for (mxCell c : cells) { + if (vertexToDepths.get(c) != null) maxD = Math.max(maxD, vertexToDepths.get(c).get(1)); + } + + distToMaxX.put(-1, 0.0); + for (int d = 0; d <= maxD; d++) { + movedMap.put(d, new ArrayList<>()); + distToMaxX.put(d, -1.0); + } + + for (int i : order) { + double centerY = -1; + for (mxCell cur : paths.get(i)) { + if (movedSet.contains(cur)) { + continue; + } + + int d = vertexToDepths.get(cur).get(0); + double x = distToMaxX.get(d - 1) + MOVE_X; + double endX = 0; + double endY = 0; + + if (roots.contains(cur) || channels.contains(cur) || eventChannels.contains(cur)) { + if (centerY == -1) { + centerY = maxY + MOVE_Y + cur.getGeometry().getHeight() / 2; + } + double y = centerY - cur.getGeometry().getHeight() / 2; + double ny = y; + double nx = x; + + for (mxCell m : movedSet) { + if (roots.contains(m) || channels.contains(m)) { + if (cellOverlap(m.getGeometry().getX(), m.getGeometry().getY(), m.getGeometry().getWidth(), m.getGeometry().getHeight(), x, y, cur.getGeometry().getWidth(), cur.getGeometry().getHeight())) { + ny = m.getGeometry().getY() + m.getGeometry().getHeight() + MOVE_Y; + } + } + } + + cur.getGeometry().setX(nx); + cur.getGeometry().setY(ny); + endX = nx + cur.getGeometry().getWidth(); + endY = ny + cur.getGeometry().getHeight(); + putCellGeo(cur, nx, ny); + addMoved(movedSet, movedMap, cur, d); + graphModel.setGeometry(cur, (mxGeometry) cur.getGeometry().clone()); + + if (distToMaxX.get(d) < endX) { + updateDistToMaxX(distToMaxX, movedSet, movedMap, d, maxD, endX); + } + maxY = Math.max(maxY, endY); + + // For all resource cells included in (under) the root resource cell. + for (mxCell c : orderInResourceHierarchy.get(cur)) { + d = vertexToDepths.get(c).get(0); + nx = x; + mxCell parent = (mxCell) graphModel.getParent(c); + + if (d == vertexToDepths.get(parent).get(0)) { + nx = cellGeo.get(parent).get("x") + MARGIN_WIDTH; + } else { + nx = distToMaxX.get(d - 1) + MOVE_X; + } + + double brotherMaxY = MOVE_Y; + for (int k = 0; k < graphModel.getChildCount(parent); k++) { + mxCell child = (mxCell) graphModel.getChildAt(parent, k); + if (child == c) { + continue; + } + + if (movedSet.contains(child) && (vertexToDepths.get(child).get(0) <= d && d <= vertexToDepths.get(child).get(1))) { + brotherMaxY = Math.max(brotherMaxY, child.getGeometry().getY() + child.getGeometry().getHeight() + SPACE); + } + } + + c.getGeometry().setX(nx - cellGeo.get(parent).get("x")); + c.getGeometry().setY(brotherMaxY); + graphModel.setGeometry(c, (mxGeometry) c.getGeometry().clone()); + addMoved(movedSet, movedMap, c, d); + putCellGeo(c, nx, cellGeo.get(parent).get("y") + brotherMaxY); + + endX = cellGeo.get(c).get("x") + c.getGeometry().getWidth(); + endY = cellGeo.get(c).get("y") + c.getGeometry().getHeight(); + endY = resize(parent, endX, endY); + + if (distToMaxX.get(d) < endX) { + updateDistToMaxX(distToMaxX, movedSet, movedMap, d, maxD, endX); + } + maxY = Math.max(maxY, endY); + } + } + } + } + + for (mxCell c : resources) { + for (mxCell cc : dotEdges.get(c)) { + for (Map.Entry> entry : dotEdges.entrySet()) { + mxCell u = entry.getKey(); + for (mxCell v : entry.getValue()) { + if ((c == u && cc == v) || (c == v && cc == u)) { + continue; + } + + double []posC = {cellGeo.get(c).get("x") + c.getGeometry().getWidth() / 2, cellGeo.get(c).get("y") + c.getGeometry().getHeight() / 2}; + double []posCC = {cellGeo.get(cc).get("x") + cc.getGeometry().getWidth() / 2, cellGeo.get(cc).get("y") + cc.getGeometry().getHeight() / 2}; + double []posU = {cellGeo.get(u).get("x") + u.getGeometry().getWidth() / 2, cellGeo.get(u).get("y") + u.getGeometry().getHeight() / 2}; + double []posV = {cellGeo.get(v).get("x") + v.getGeometry().getWidth() / 2, cellGeo.get(v).get("y") + v.getGeometry().getHeight() / 2}; + + if (isStraightLine(posC, posCC, posU, posV)) { + c.getGeometry().setX(c.getGeometry().getX() + SHIFT); + cellGeo.get(c).replace("x", cellGeo.get(c).get("x")); + cc.getGeometry().setX(cc.getGeometry().getX() + SHIFT); + cellGeo.get(cc).replace("x", cellGeo.get(cc).get("x") + SHIFT); + graphModel.setGeometry(c, c.getGeometry()); + graphModel.setGeometry(cc, cc.getGeometry()); + } + } + } + } + } + + for (int i : order) { + mxCell cur = paths.get(i).get(1); + List ecs = new ArrayList<>(); + for (int j : cellToPathIndex.get(cur)) { + if (!ecs.contains(paths.get(j).get(0)) && cur == paths.get(j).get(1)) { + ecs.add(paths.get(j).get(0)); + } + } + + double centerY = cellGeo.get(cur).get("y") + cur.getGeometry().getHeight() / 2; + double y = 0; + if (ecs.size() % 2 != 0) { + y = centerY - ecs.size()*HEIGHT / 2 - ((ecs.size() - 1) / 2)*SPACE; + } else { + y = centerY - ecs.size()*HEIGHT / 2 - (ecs.size() - 1)*SPACE / 2; + } + + for (int j : order) { + mxCell other = paths.get(j).get(0); + if (ecs.contains(other)) { + continue; + } + } + + for (mxCell ec : ecs) { + ec.getGeometry().setY(y); + graphModel.setGeometry(ec, ec.getGeometry()); + cellGeo.get(ec).replace("y", y); + y += HEIGHT + SPACE; + } + } + + List sortedEcs = new ArrayList<>(); + Set usedEcs = new HashSet<>(); + for (int i = 0; i < eventChannels.size(); i++) { + mxCell minEc = movedMap.get(0).get(0); + double ecMinY = Double.MAX_VALUE; + for (mxCell ec : movedMap.get(0)) { + if (usedEcs.contains(ec)) { + continue; + } + if (cellGeo.get(ec).get("y") < ecMinY) { + minEc = ec; + ecMinY = cellGeo.get(ec).get("y"); + } + } + sortedEcs.add(minEc); + usedEcs.add(minEc); + } + + for (int i = 1; i < sortedEcs.size(); i++) { + mxCell cur = sortedEcs.get(i); + mxCell pre = sortedEcs.get(i - 1); + + if (cellGeo.get(cur).get("y") < cellGeo.get(pre).get("y") + pre.getGeometry().getHeight() + SPACE) { + double dy = cellGeo.get(pre).get("y") + pre.getGeometry().getHeight() + SPACE - cellGeo.get(cur).get("y"); + cur.getGeometry().setY(cur.getGeometry().getY() + dy); + cellGeo.get(cur).replace("y", cellGeo.get(cur).get("y") + dy); + graphModel.setGeometry(cur, cur.getGeometry()); + } + } + } + + public void layout2(mxCell s) { + Set movedSet = new HashSet<>(); + Map> movedMap = new TreeMap<>(); + Map distToMaxX = new HashMap<>(); + double maxY = 0; + int maxD = 0; + + putCellGeo(s, 0, 0); + + for (mxCell c : cells) { + maxD = Math.max(maxD, vertexToDepths.get(c).get(1)); + } + + distToMaxX.put(-1, 0.0); + for (int d = 0; d <= maxD; d++) { + movedMap.put(d, new ArrayList<>()); + distToMaxX.put(d, -1.0); + } + + for (int i : order) { + double centerY = -1; + for (int j = 0; j < paths.get(i).size(); j++) { + mxCell cur = paths.get(i).get(j); + + if (movedSet.contains(cur)) { + continue; + } + + int d = vertexToDepths.get(cur).get(0); + double x = distToMaxX.get(d - 1) + MOVE_X; + double endX = 0; + double endY = 0; + + if (roots.contains(cur) || eventChannels.contains(cur)) { + if (centerY == -1) { + centerY = maxY + MOVE_Y + cur.getGeometry().getHeight() / 2; + } + double y = centerY - cur.getGeometry().getHeight() / 2; + double ny = y; + double nx = x; + + cur.getGeometry().setX(nx); + cur.getGeometry().setY(ny); + endX = nx + cur.getGeometry().getWidth(); + endY = ny + cur.getGeometry().getHeight(); + putCellGeo(cur, nx, ny); + addMoved(movedSet, movedMap, cur, d); + graphModel.setGeometry(cur, (mxGeometry) cur.getGeometry().clone()); + + if (distToMaxX.get(d) < endX) { + updateDistToMaxX(distToMaxX, movedSet, movedMap, d, maxD, endX); + } + maxY = Math.max(maxY, endY); + + for (mxCell c : orderInResourceHierarchy.get(cur)) { + d = vertexToDepths.get(c).get(0); + nx = x; + mxCell parent = (mxCell) graphModel.getParent(c); + + if (d == vertexToDepths.get(parent).get(0)) { + nx = cellGeo.get(parent).get("x") + MARGIN_WIDTH; + } else { + nx = distToMaxX.get(d - 1) + MOVE_X; + } + + double brotherMaxY = MOVE_Y; + for (int k = 0; k < graphModel.getChildCount(parent); k++) { + mxCell child = (mxCell) graphModel.getChildAt(parent, k); + if (child == c) { + continue; + } + + if (movedSet.contains(child) && (vertexToDepths.get(child).get(0) <= d && d <= vertexToDepths.get(child).get(1))) { + brotherMaxY = Math.max(brotherMaxY, child.getGeometry().getY() + child.getGeometry().getHeight() + SPACE); + } + } + + c.getGeometry().setX(nx - cellGeo.get(parent).get("x")); + c.getGeometry().setY(brotherMaxY); + graphModel.setGeometry(c, (mxGeometry) c.getGeometry().clone()); + addMoved(movedSet, movedMap, c, d); + putCellGeo(c, nx, cellGeo.get(parent).get("y") + brotherMaxY); + + endX = cellGeo.get(c).get("x") + c.getGeometry().getWidth(); + endY = cellGeo.get(c).get("y") + c.getGeometry().getHeight(); + endY = resize(parent, endX, endY); + + if (distToMaxX.get(d) < endX) { + updateDistToMaxX(distToMaxX, movedSet, movedMap, d, maxD, endX); + } + maxY = Math.max(maxY, endY); + } + } + + if (channels.contains(cur)) { + mxCell pre = paths.get(i).get(j - 1); + centerY = cellGeo.get(pre).get("y") + pre.getGeometry().getHeight() / 2; + double y = centerY - cur.getGeometry().getHeight() / 2; + + cur.getGeometry().setX(x); + cur.getGeometry().setY(y); + endX = x + cur.getGeometry().getWidth(); + endY = y + cur.getGeometry().getHeight(); + putCellGeo(cur, x, y); + addMoved(movedSet, movedMap, cur, d); + graphModel.setGeometry(cur, (mxGeometry) cur.getGeometry().clone()); + + if (distToMaxX.get(d) < endX) { + updateDistToMaxX(distToMaxX, movedSet, movedMap, d, maxD, endX); + } + maxY = Math.max(maxY, endY); + } + } + } + + for (mxCell c : resources) { + for (mxCell cc : dotEdges.get(c)) { + for (Map.Entry> entry : dotEdges.entrySet()) { + mxCell u = entry.getKey(); + for (mxCell v : entry.getValue()) { + if ((c == u && cc == v) || (c == v && cc == u)) { + continue; + } + + double []posC = {cellGeo.get(c).get("x") + c.getGeometry().getWidth() / 2, cellGeo.get(c).get("y") + c.getGeometry().getHeight() / 2}; + double []posCC = {cellGeo.get(cc).get("x") + cc.getGeometry().getWidth() / 2, cellGeo.get(cc).get("y") + cc.getGeometry().getHeight() / 2}; + double []posU = {cellGeo.get(u).get("x") + u.getGeometry().getWidth() / 2, cellGeo.get(u).get("y") + u.getGeometry().getHeight() / 2}; + double []posV = {cellGeo.get(v).get("x") + v.getGeometry().getWidth() / 2, cellGeo.get(v).get("y") + v.getGeometry().getHeight() / 2}; + + if (isStraightLine(posC, posCC, posU, posV)) { + c.getGeometry().setX(c.getGeometry().getX() + SHIFT); + cellGeo.get(c).replace("x", cellGeo.get(c).get("x")); + cc.getGeometry().setX(cc.getGeometry().getX() + SHIFT); + cellGeo.get(cc).replace("x", cellGeo.get(cc).get("x") + SHIFT); + graphModel.setGeometry(c, c.getGeometry()); + graphModel.setGeometry(cc, cc.getGeometry()); + } + } + } + } + } + + for (int i : order) { + mxCell cur = paths.get(i).get(1); + List ecs = new ArrayList<>(); + for (int j : cellToPathIndex.get(cur)) { + if (!ecs.contains(paths.get(j).get(0)) && cur == paths.get(j).get(1)) { + ecs.add(paths.get(j).get(0)); + } + } + + double centerY = cellGeo.get(cur).get("y") + cur.getGeometry().getHeight() / 2; + double y = 0; + if (ecs.size() % 2 != 0) { + y = centerY - ecs.size()*HEIGHT / 2 - ((ecs.size() - 1) / 2)*SPACE; + } else { + y = centerY - ecs.size()*HEIGHT / 2 - (ecs.size() - 1)*SPACE / 2; + } + + for (int j : order) { + mxCell other = paths.get(j).get(0); + if (ecs.contains(other)) { + continue; + } + } + + for (mxCell ec : ecs) { + ec.getGeometry().setY(y); + graphModel.setGeometry(ec, ec.getGeometry()); + cellGeo.get(ec).replace("y", y); + y += HEIGHT + SPACE; + } + } + + List sortedEcs = new ArrayList<>(); + Set usedEcs = new HashSet<>(); + for (int i = 0; i < eventChannels.size(); i++) { + mxCell minEc = movedMap.get(0).get(0); + double ecMinY = Double.MAX_VALUE; + for (mxCell ec : movedMap.get(0)) { + if (usedEcs.contains(ec)) { + continue; + } + if (cellGeo.get(ec).get("y") < ecMinY) { + minEc = ec; + ecMinY = cellGeo.get(ec).get("y"); + } + } + sortedEcs.add(minEc); + usedEcs.add(minEc); + } + + for (int i = 1; i < sortedEcs.size(); i++) { + mxCell cur = sortedEcs.get(i); + mxCell pre = sortedEcs.get(i - 1); + + if (cellGeo.get(cur).get("y") < cellGeo.get(pre).get("y") + pre.getGeometry().getHeight() + SPACE) { + double dy = cellGeo.get(pre).get("y") + pre.getGeometry().getHeight() + SPACE - cellGeo.get(cur).get("y"); + cur.getGeometry().setY(cur.getGeometry().getY() + dy); + cellGeo.get(cur).replace("y", cellGeo.get(cur).get("y") + dy); + graphModel.setGeometry(cur, cur.getGeometry()); + } + } + } + + public void putCellGeo(mxCell c, double x, double y) { + cellGeo.put(c, new HashMap<>()); + cellGeo.get(c).put("x", x); + cellGeo.get(c).put("y", y); + } + + public void addMoved(Set ms, Map> mm, mxCell c, int d) { + ms.add(c); + mm.get(d).add(c); + } + + public boolean isStraightLine(double []u1, double []v1, double []u2, double []v2) { + double gradient1 = 0; + double length1 = Math.pow(u1[0] - v1[0], 2) + Math.pow(u1[1] - v1[1], 2); + double gradient2 = 0; + double length2 = Math.pow(u2[0] - v2[0], 2) + Math.pow(u2[1] - v2[1], 2); + boolean isVertical = false; + + if (u1[0] == v1[0]) { + isVertical = true; + } else { + gradient1 = (u1[1] - v1[1]) / (u1[0] - v1[0]); + } + + if (isVertical) { + if (u2[0] != v2[0]) { + return false; + } else { + gradient2 = (u2[1] - v2[1]) / (u2[0] - v2[0]); + } } else { - for (int i = n; i < map.size(); i++) { - if (map.get(i).size() > msize) { - mnum = i; + if (gradient1 - gradient2 > delta) { + return false; + } + } + + double [][]a = {u1, v1}; + double [][]b = {u2, v2}; + double maxLength = 0; + for (double []c1 : a) { + for (double []c2 : b) { + double gradient3 = 0; + double length3 = Math.pow(c1[0] - c2[0], 2) + Math.pow(c1[1] - c2[1], 2); + + if(isVertical) { + if (c1[0] == c2[0]) { + maxLength = Math.max(maxLength, length3); + } else { + return false; + } + } else { + if (c1[0] == c2[0]) { + return false; + } else { + gradient3 = (c2[1] - c1[1]) / (c2[0] - c1[0]); + if (gradient1 - gradient3 > delta) { + return false; + } + maxLength = Math.max(maxLength, length3); + } } } } - if (mnum >= 0) { - Collections.swap(map, n, mnum); - sort(map, n+1, true); - } else if(n < map.size()) { - sort(map, n+1, false); + + if (length1 + length2 < maxLength) { + return false; + } else { + return true; } } + public boolean cellOverlap(double ax, double ay, double aw, double ah, double bx, double by, double bw, double bh) { + if (((ax <= bx) && (bx <= ax + aw)) || ((bx <= ax) && (ax <= bx + bw))) { + if (((ay <= by) && (by <= ay + ah)) || ((by <= ay) && (ay <= by + bh))) { + return true; + } + } + return false; + } + public void updateDistToMaxX(Map distToMaxX, Set movedSet, Map> movedMap, int d, int md, double endX) { + double preEndX = distToMaxX.get(d); + distToMaxX.replace(d, endX); + for (int i = d + 1; i <= md; i++) { + if (distToMaxX.get(i) == -1) { + distToMaxX.replace(i, endX); + } + } + + for (Map.Entry> entry : movedMap.entrySet()) { + if (entry.getKey() <= d) { + continue; + } + + for (mxCell cell : entry.getValue()) { + double newX = cellGeo.get(cell).get("x") + endX - preEndX; + mxCell cp = (mxCell) cell.getParent(); + relocateX(cell, newX, cellGeo.get(cp).get("x")); + + if (!(roots.contains(cell) || channels.contains(cell))) { + mxCell ancestor = (mxCell) graphModel.getParent(cell); + resize(ancestor, cellGeo.get(cell).get("x") + cell.getGeometry().getWidth(), cellGeo.get(cell).get("y") + cell.getGeometry().getHeight()); + } + if (distToMaxX.get(entry.getKey()) < cellGeo.get(cell).get("x") + cell.getGeometry().getWidth()) { + distToMaxX.replace(entry.getKey(), cellGeo.get(cell).get("x") + cell.getGeometry().getWidth()); + for (int i = entry.getKey() + 1; i <= md; i++) { + if (distToMaxX.get(i) == -1) { + distToMaxX.replace(i, cellGeo.get(cell).get("x") + cell.getGeometry().getWidth()); + } + } + } + } + } + } + + public double resize(mxCell ancestor, double endX, double endY) { + while (true) { + boolean isChanging = false; + + if (ancestor.getGeometry().getWidth() < endX - cellGeo.get(ancestor).get("x") + MARGIN_WIDTH) { + ancestor.getGeometry().setWidth(endX - cellGeo.get(ancestor).get("x") + MARGIN_WIDTH); + isChanging = true; + } + if (ancestor.getGeometry().getHeight() < endY - cellGeo.get(ancestor).get("y") + MARGIN_HEIGHT) { + ancestor.getGeometry().setHeight(endY - cellGeo.get(ancestor).get("y") + MARGIN_HEIGHT); + isChanging = true; + } + if (isChanging) { + graphModel.setGeometry(ancestor, ancestor.getGeometry()); + } + + endX = cellGeo.get(ancestor).get("x") + ancestor.getGeometry().getWidth(); + endY = cellGeo.get(ancestor).get("y") + ancestor.getGeometry().getHeight(); + + if (roots.contains(ancestor)) { + break; + } + ancestor = (mxCell) ancestor.getParent(); + } + + return endY; + } + + public void relocateX(mxCell c, double nx, double dx) { + c.getGeometry().setX(nx - dx); + graphModel.setGeometry(c, (mxGeometry) c.getGeometry().clone()); + cellGeo.get(c).replace("x", nx); + } } \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/application/simulator/InputEventCellEditor.java b/AlgebraicDataflowArchitectureModel/src/application/simulator/InputEventCellEditor.java new file mode 100644 index 0000000..fb04068 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/simulator/InputEventCellEditor.java @@ -0,0 +1,339 @@ +package application.simulator; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Rectangle; +import java.util.EventObject; +import java.util.HashMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import javax.swing.BorderFactory; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.JTextField; + +import com.mxgraph.model.mxCell; +import com.mxgraph.model.mxGraphModel; +import com.mxgraph.model.mxIGraphModel; +import com.mxgraph.swing.mxGraphComponent; +import com.mxgraph.swing.view.mxICellEditor; +import com.mxgraph.util.mxConstants; +import com.mxgraph.util.mxUtils; +import com.mxgraph.view.mxCellState; +import com.mxgraph.view.mxGraph; +import com.mxgraph.view.mxGraphView; + +import application.editor.Editor; +import application.layouts.DAGLayout; +import models.algebra.Expression; +import models.algebra.InvalidMessage; +import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.Position; +import models.algebra.Term; +import models.algebra.Type; +import models.algebra.UnificationFailed; +import models.algebra.ValueUndefined; +import models.algebra.Variable; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ResourceHierarchy; +import models.dataConstraintModel.ResourcePath; +import models.dataFlowModel.DataTransferModel; +import models.dataFlowModel.DataFlowGraph; +import models.dataFlowModel.DataTransferChannel; +import models.dataFlowModel.PushPullAttribute; +import models.dataFlowModel.PushPullValue; +import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; +import models.visualModel.FormulaChannel; +import parser.Parser; +import parser.Parser.TokenStream; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; +import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.WrongJsonExpression; +import simulator.ChannelState; +import simulator.Resource; +import simulator.ResourceIdentifier; +import simulator.Simulator; +import simulator.Event; +import simulator.SystemState; + +public class InputEventCellEditor implements mxICellEditor { + public int DEFAULT_MIN_WIDTH = 70; + public int DEFAULT_MIN_HEIGHT = 30; + public double DEFAULT_MINIMUM_EDITOR_SCALE = 1; + private double x = 20; + private double y = 20; + + protected double minimumEditorScale = DEFAULT_MINIMUM_EDITOR_SCALE; + protected int minimumWidth = DEFAULT_MIN_WIDTH; + protected int minimumHeight = DEFAULT_MIN_HEIGHT; + + private SimulatorWindow window; + private Object editingCell; + private EventObject trigger; + private JComboBox comboBox; + private mxGraphComponent graphComponent; + private Simulator simulator; + private JComboBox pulldownMenu; + private Editor editor; + private boolean bReflectingArchitectureModel = false; + + public InputEventCellEditor(SimulatorWindow window, mxGraphComponent graphComponent, Simulator simulator, Editor editor) { + this.window = window; + this.graphComponent = graphComponent; + this.simulator = simulator; + this.editor = editor; + } + + @Override + public Object getEditingCell() { + return editingCell; + } + + @Override + public void startEditing(Object cell, EventObject evt) { + if (editingCell != null) { + stopEditing(true); + } + if (!graphComponent.getGraph().getModel().isEdge(cell)) { + Resource res = simulator.getCurState().getResource((String) ((mxCell) cell).getValue()); + ResourceIdentifier resId = res.getResourceIdentifier(); // clicked resource + ArrayList eventChs = new ArrayList<>(); // event channel list + ArrayList messageTexts = new ArrayList<>(); // message text list + ArrayList messageExps = new ArrayList<>(); // message expression list + ArrayList> refParams = new ArrayList<>(); // message parameters for ref ports + ResourcePath eventResPath = null; + + for (Channel ch: simulator.getModel().getInputChannels()) { // all channels + eventResPath = getSelectableMessages(ch, resId, eventChs, messageTexts, messageExps, refParams, eventResPath); + } + if (messageTexts.isEmpty()) { + return; + } + String[] messageList = messageTexts.toArray(new String[messageTexts.size()]); + JComboBox messageMenu = new JComboBox(messageList); + + JPanel eventSelectPanel = new JPanel(); + eventSelectPanel.add(messageMenu); + + int ret = JOptionPane.showConfirmDialog(window, eventSelectPanel, "Event Choice", JOptionPane.OK_CANCEL_OPTION); // Select an event. + if (ret == JOptionPane.OK_OPTION) { + int i, messageIdx; + i = messageIdx = 0; + for (String messageText : messageList) { + if(messageText.equals(messageMenu.getSelectedItem().toString())) { + messageIdx = i; + } + i++; + } + JPanel inputEventPanel = new JPanel(); + JTextArea textArea = new JTextArea(messageExps.get(messageIdx).toString(), 10, 30); + inputEventPanel.add(textArea); + + int approve = JOptionPane.showConfirmDialog(window, inputEventPanel, "Event Code", JOptionPane.OK_CANCEL_OPTION); // Input an message text for the event. + if (approve == JOptionPane.OK_OPTION) { + try { + + TokenStream stream = new Parser.TokenStream(); + Parser parser = new Parser(stream); + stream.addLine(textArea.getText()); + Expression eventMessage = parser.parseTerm(stream, simulator.getModel()); + if (eventMessage instanceof Term) { + TreeMap refMap = refParams.get(messageIdx); + for (Integer paramIdx: refMap.keySet()) { + ((Term) eventMessage).getSymbol().setArity(-1); + ((Term) eventMessage).addChild(paramIdx, refMap.get(paramIdx), true); + } + } + + Event newEvent = new Event(eventChs.get(messageIdx), eventMessage, eventResPath, simulator.getCurState().getResource(resId)); + simulator.transition(newEvent); + + graphComponent.setCellEditor(new InputEventCellEditor(window, graphComponent, simulator, this.editor)); + + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined | ExpectedRightBracket | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + } + // resource + return; + } + + mxCellState state = graphComponent.getGraph().getView().getState(cell); + if (state != null && state.getLabel() != null && !state.getLabel().equals("")) { + editingCell = cell; + trigger = evt; + + double scale = Math.max(minimumEditorScale, graphComponent.getGraph().getView().getScale()); + Object value = graphComponent.getGraph().getModel().getValue(cell); + if (value != null && value instanceof PushPullAttribute) { + PushPullAttribute attr = (PushPullAttribute) value; + comboBox = new JComboBox<>(attr.getOptionStrings()); + comboBox.setBorder(BorderFactory.createEmptyBorder()); + comboBox.setOpaque(false); + comboBox.setBounds(getEditorBounds(state, scale)); + comboBox.setVisible(true); + graphComponent.getGraphControl().add(comboBox, 0); + comboBox.updateUI(); + } + } + } + + private ResourcePath getSelectableMessages(Channel ch, ResourceIdentifier resId, + ArrayList eventChs, ArrayList messageTexts, ArrayList messageExps, ArrayList> refParams, + ResourcePath eventResPath) { + if (((DataTransferChannel) ch).getInputResources().size() == 0) { // event ch. or normal ch. + for (ChannelMember out: ((DataTransferChannel) ch).getOutputChannelMembers()) { + ResourcePath resPath = out.getResource(); + if (!out.isOutside() && resId.isInstanceOf(resPath)) { + eventResPath = resPath; + eventChs.add(((DataTransferChannel) ch)); + String messageText = null; + Expression mesExp = out.getStateTransition().getMessageExpression(); + TreeMap refMap = new TreeMap<>(); + if (mesExp instanceof Term) { + // Reconstruct an input message template + List pathParams = resPath.getPathParams(); + List children = ((Term) mesExp).getChildren(); + mesExp = new Term(((Term) mesExp).getSymbol()); + for (int i = 0; i < children.size(); i++) { + Expression child = children.get(i); + boolean isRefVar = false; + for (ChannelMember refCm: ((DataTransferChannel) ch).getReferenceChannelMembers()) { + if (refCm.getStateTransition().getMessageExpression() instanceof Term) { + Expression varExp = ((Term) refCm.getStateTransition().getMessageExpression()).getChild(i); + if (varExp != null && varExp instanceof Variable) { + if (refCm.getStateTransition().getCurStateExpression().contains(varExp)) { + // child has come from a reference resource. + isRefVar = true; + break; + } + } + } + } + if (!isRefVar) { + // child has not come from a reference resource. + if (!pathParams.contains(child)) { + ((Term) mesExp).addChild(child); + } else { + int idx = pathParams.indexOf(child); + ((Term) mesExp).addChild(resId.getPathParams().get(idx)); + } + } else { + // child has come from a reference resource. + refMap.put(i, child); + } + } + messageText = ((Term) mesExp).getSymbol().toString(); + } else if(mesExp instanceof Variable) { + messageText = ((Variable) mesExp).getName(); + } + messageExps.add(mesExp); + messageTexts.add(messageText); // for the pull-down menu + refParams.add(refMap); + } + } + for (Channel childCh: ch.getChildren()) { + eventResPath = getSelectableMessages(childCh, resId, eventChs, messageTexts, messageExps, refParams, eventResPath); + } + } + return eventResPath; + } + + @Override + public void stopEditing(boolean cancel) { + if (editingCell != null) { + comboBox.transferFocusUpCycle(); + Object cell = editingCell; + editingCell = null; + if (!cancel) { + EventObject trig = trigger; + trigger = null; + Object value = graphComponent.getGraph().getModel().getValue(cell); + if (value != null && value instanceof PushPullAttribute) { + PushPullAttribute attr = (PushPullAttribute) value; + List options = attr.getOptions(); + PushPullValue selected = null; + for (PushPullValue option: options) { + if (option.toString().equals(getCurrentValue())) { + selected = option; + break; + } + } + if (selected != null) { + attr.selectOption(selected); + } + graphComponent.labelChanged(cell, attr, trig); + } + } else { + mxCellState state = graphComponent.getGraph().getView().getState(cell); + graphComponent.redraw(state); + } + + if (comboBox.getParent() != null) { + comboBox.setVisible(false); + comboBox.getParent().remove(comboBox); + } + + graphComponent.requestFocusInWindow(); + } + } + + public String getCurrentValue() { + return (String) comboBox.getSelectedItem(); + } + + /** + * Returns the bounds to be used for the editor. + */ + public Rectangle getEditorBounds(mxCellState state, double scale) { + mxIGraphModel model = state.getView().getGraph().getModel(); + Rectangle bounds = null; + + bounds = state.getLabelBounds().getRectangle(); + bounds.height += 10; + + // Applies the horizontal and vertical label positions + if (model.isVertex(state.getCell())) { + String horizontal = mxUtils.getString(state.getStyle(), mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER); + + if (horizontal.equals(mxConstants.ALIGN_LEFT)) { + bounds.x -= state.getWidth(); + } else if (horizontal.equals(mxConstants.ALIGN_RIGHT)) { + bounds.x += state.getWidth(); + } + + String vertical = mxUtils.getString(state.getStyle(), + mxConstants.STYLE_VERTICAL_LABEL_POSITION, + mxConstants.ALIGN_MIDDLE); + + if (vertical.equals(mxConstants.ALIGN_TOP)) { + bounds.y -= state.getHeight(); + } else if (vertical.equals(mxConstants.ALIGN_BOTTOM)) { + bounds.y += state.getHeight(); + } + } + + bounds.setSize( + (int) Math.max(bounds.getWidth(), + Math.round(minimumWidth * scale)), + (int) Math.max(bounds.getHeight(), + Math.round(minimumHeight * scale))); + + return bounds; + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulationLayout.java b/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulationLayout.java new file mode 100644 index 0000000..eced48d --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulationLayout.java @@ -0,0 +1,157 @@ +package application.simulator; + +import com.mxgraph.model.mxGraphModel; +import com.mxgraph.view.mxGraph; +import models.dataConstraintModel.ResourcePath; +import simulator.Resource; +import simulator.ResourceIdentifier; +import simulator.Simulator; +import simulator.SystemState; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class SimulationLayout { + // Hold the division level for each resource + HashMap divisionLevelMap = new HashMap<>(); + // Hold the scaling factor for each resource + HashMap resourceScaleMap = new HashMap<>(); + int maxDivisionLevel = 1; + public final double BASE_WIDTH = 720; + public final double BASE_HEIGHT = BASE_WIDTH/2; + public final double MARGIN_SCALE = 0.92; + SystemState systemState; + public SimulationLayout(SystemState systemState){ + this.systemState = systemState; + // Calculate the division level for each resource + for (Resource res:systemState.getRootResources()) { + setDivisionLevel(divisionLevelMap, res.getResourceIdentifier(), 1); + } + // Calculate the scaling factor for each resource + for (ResourceIdentifier res:divisionLevelMap.keySet()) { + double scale = (double) maxDivisionLevel / divisionLevelMap.get(res); + resourceScaleMap.put(res, scale); + } + } + public double getScale(ResourceIdentifier resource){ + return resourceScaleMap.get(resource); + } + public double getDivision(ResourceIdentifier resource){ + return divisionLevelMap.get(resource); + } + + public int getMaxDivisionLevel() { + return maxDivisionLevel; + } + + public boolean isExistResource(ResourceIdentifier resourceIdentifier){ + return divisionLevelMap.containsKey(resourceIdentifier); + } + private void setDivisionLevel(HashMap resourceSet, ResourceIdentifier resource, int childCount){ + int divisionLevel; + if(resourceSet.get(resource.getParent()) == null){ + divisionLevel = 1; + }else{ + divisionLevel = resourceSet.get(resource.getParent()) * childCount; + } + if (divisionLevel > maxDivisionLevel)maxDivisionLevel = divisionLevel; + resourceSet.put(resource,divisionLevel); + + Collection identifiers = systemState.getResource(resource).getChildren(); + if (identifiers != null) { + for (Resource child:identifiers) { + setDivisionLevel(resourceSet, child.getResourceIdentifier(), identifiers.size()); + } + } + } + /** + * + * Draw an object corresponding to the target resource on the mxGraph. + * @param graph The mxGraph for drawing. + * @param parent The parent object of the target resource. + * @param resourceIdentifier The ID of the target resource. + * @param index The index. + * @param length The number of sibling resources of the target resource. + * @return The drawing object of the target resource. + */ + + private Object setLayout(mxGraph graph,Object parent, ResourceIdentifier resourceIdentifier,double index, double length){ + double width, height, x, y; + double parentWidth = graph.getCellGeometry(parent).getWidth(); + double parentHeight = graph.getCellGeometry(parent).getHeight(); + + width = parentWidth / length * MARGIN_SCALE; + height = width/2; + x = parentWidth * (index - 1)/length + (parentWidth/length)*(1-MARGIN_SCALE)/2; + + // Process to avoid hiding the parent's resource name + if ((int)length == 1) { + y = 20; + height -=20; + } else { + y = parentHeight/2 - height/2; + } + + Object result = graph.insertVertex(parent, null, + resourceIdentifier.toString(), x, y, width, height, + "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); + System.out.println(result); + return result; + } + + public mxGraph constructSimulateGraph(mxGraph graph, Simulator simulator){ + ((mxGraphModel) graph.getModel()).clear(); + Object parent = graph.getDefaultParent(); + graph.getModel().beginUpdate(); + + try { + Map resources = new HashMap<>(); + int i = 0; + int childCount = simulator.getCurState().getRootResources().size(); + // create resource vertices + for (Resource resNode: simulator.getCurState().getRootResources()) { + double scale = this.getScale(resNode.getResourceIdentifier()); + double maxDiv = this.getMaxDivisionLevel(); + double w = this.BASE_WIDTH * scale / maxDiv / childCount; + double h = this.BASE_HEIGHT * scale / maxDiv / childCount; + double x = w * i + 50; + double y = 20 ; + ResourcePath res = resNode.getResourceIdentifier(); + Object resource = graph.insertVertex(parent, null, + res.toString(), x, y, w, h, + "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); // insert a resource as a vertex + resources.put(resNode, resource); + i++; + createNextChildSimulateResourceVerticies(graph, resource, resNode, resources); + + } + + } finally { + graph.getModel().endUpdate(); + } + + return graph; + } + private void createNextChildSimulateResourceVerticies(mxGraph graph, Object parent, Resource resNode, Map resources) { //sample + Collection children = resNode.getChildren(); + if (children != null) { + //List children = resNode.getChildren(); + double i = 1; + double childCount = children.size(); + for (Resource childNode: children) { + Object childResource = setLayout(graph, parent, childNode.getResourceIdentifier(), i, childCount); + resources.put(childNode, childResource); + i++; + createNextChildSimulateResourceVerticies(graph, childResource, childNode, resources); + + } + } + if (children == null || children.size() == 0) { + Object state = graph.insertVertex(parent, null, + resNode.getState().getValue().toString(), 0.5, 0.5, 0.25, 0.25, "opacity=0;verticalAlign=down;", true); // insert a state label as a vertex + } + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorMenuBar.java b/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorMenuBar.java new file mode 100644 index 0000000..29463f4 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorMenuBar.java @@ -0,0 +1,27 @@ +package application.simulator; + +import javax.swing.JMenu; +import javax.swing.JMenuBar; + +import application.actions.ZoomInAction; +import application.actions.ZoomOutAction; +import application.simulator.actions.ShowUISimulatorAction; + +public class SimulatorMenuBar extends JMenuBar { + private static final long serialVersionUID = 7769410930379012970L; + + private SimulatorWindow simulatorWindow = null; + + public SimulatorMenuBar(SimulatorWindow simulatorWindow) { + this.simulatorWindow = simulatorWindow; + + JMenu menu = null; + menu = add(new JMenu("View")); + menu.add(new ZoomInAction(simulatorWindow.getGraphComponent())); + menu.add(new ZoomOutAction(simulatorWindow.getGraphComponent())); + + menu = add(new JMenu("Show")); + menu.add(new ShowUISimulatorAction(simulatorWindow.getSimulator())); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java b/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java new file mode 100644 index 0000000..3ba4fe5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java @@ -0,0 +1,178 @@ +package application.simulator; + +import application.editor.Editor; +import generators.JavaSpecific; +import generators.TypeInference; + +import com.mxgraph.model.mxCell; +import com.mxgraph.model.mxGeometry; +import com.mxgraph.model.mxGraphModel; +import com.mxgraph.swing.handler.mxRubberband; +import com.mxgraph.swing.mxGraphComponent; +import com.mxgraph.util.mxEvent; +import com.mxgraph.util.mxEventObject; +import com.mxgraph.util.mxEventSource.mxIEventListener; +import com.mxgraph.view.mxGraph; +import models.dataFlowModel.DataTransferModel; +import simulator.Event; +import simulator.Simulator; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +public class SimulatorWindow extends JFrame implements INativeReceiver { + + private static final long serialVersionUID = -2425820512017088254L; + public static final String title = "Simulation Tool"; + + final int PORT_DIAMETER = 8; + final int PORT_RADIUS = PORT_DIAMETER / 2; + + private Editor editor = null; + private mxGraph graph = null; + private mxGraphComponent graphComponent = null; + + private Simulator simulator = null; + + private boolean bReflectingArchitectureModel = false; + private double x = 20; + private double y = 20; + private SimulatorMenuBar menuBar; + + public SimulatorWindow(Editor editor) { + setTitle(title); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + this.graph = new mxGraph() { + public boolean isPort(Object cell) { + mxGeometry geo = getCellGeometry(cell); + + return (geo != null) ? geo.isRelative() : false; + } + + public boolean isCellFoldable(Object cell, boolean collapse) { + return false; + } + }; + + this.graphComponent = new mxGraphComponent(graph); + this.editor = editor; + + graph.getModel().addListener(mxEvent.CHANGE, new mxIEventListener() { + public void invoke(Object sender, mxEventObject evt) { + List terminals = new ArrayList<>(); + mxCell cell = null; + for (Object change : ((List) evt.getProperties().get("changes"))) { + if (change instanceof mxGraphModel.mxTerminalChange) { + mxGraphModel.mxTerminalChange terminalChange = (mxGraphModel.mxTerminalChange) change; + cell = (mxCell) terminalChange.getCell(); + mxCell terminal = (mxCell) terminalChange.getTerminal(); + terminals.add(terminal); + } + } + if (terminals.size() == 2) { + if (!editor.connectEdge(cell, terminals.get(0), terminals.get(1))) { + graph.removeCells(new mxCell[]{cell}); + } + } + } + }); + getContentPane().add(graphComponent); + new mxRubberband(graphComponent); + graph.setAllowDanglingEdges(false); + graph.setCellsDisconnectable(true); + + setTitle(title); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + setSize(870, 640); + setVisible(true); + + DataTransferModel model = this.editor.getModel(); + TypeInference typeInference = new TypeInference(new JavaSpecific()); + typeInference.infer(model); + simulator = new Simulator(model); + SimulationLayout layout = new SimulationLayout(simulator.getCurState()); + layout.constructSimulateGraph(graph, simulator); + graphComponent.setCellEditor(new InputEventCellEditor(this, graphComponent, simulator, this.editor)); + simulator.addSystemReceiver(this); + + menuBar = new SimulatorMenuBar(this); + setJMenuBar(menuBar); + } + + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + SimulationLayout layout = new SimulationLayout(nextSystemState); + layout.constructSimulateGraph(graph, simulator); + } + +// public mxGraph constructSimulateGraph(Set simulateRes, DataTransferModel model, DataFlowGraph dataFlowGraph) { +// bReflectingArchitectureModel = true; +// ((mxGraphModel) graph.getModel()).clear(); +// Object parent = graph.getDefaultParent(); +// graph.getModel().beginUpdate(); +// +// try { +// Map resources = new HashMap<>(); +// +// // create resource vertices +// for (Resource resNode: simulateRes) { +// int w = 80; +// int h = 30; +// ResourcePath res = resNode.getResourceIdentifier(); +// Object resource = graph.insertVertex(parent, null, +// res.toString(), x, y, w, h, +// "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); // insert a resource as a vertex +// resources.put(resNode, resource); +// createChildSimulateResourceVerticies(resource, resNode, resources, w, h); +// x+=80; +// } +// +// } finally { +// graph.getModel().endUpdate(); +// } +// +// bReflectingArchitectureModel = false; +// return graph; +// } +// +// +// public void createChildSimulateResourceVerticies(Object resource, Resource resNode, Map resources, int w, int h) { //sample +// +// if(resNode.getChildren() != null) { +// for (Resource childNode: resNode.getChildren()) { +// ResourcePath childRes = childNode.getResourceIdentifier(); +// Object childResource = graph.insertVertex(resource, null, +// childRes.toString(), 0, 0, w/2, h/2, +// "shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top;"); // insert a resource as a vertex +// resources.put(childNode, childResource); +// createChildSimulateResourceVerticies(childResource, childNode, resources, w, h); +// } +// } +// if (resNode.getChildren() == null || resNode.getChildren().size() == 0) { +// Object state = graph.insertVertex(resource, null, +// resNode.getState().getValue().toString(), 0.5, 0.5, 0.25, 0.25, "opacity=0;verticalAlign=down;", true); // insert a state label as a vertex +// } +// } + + public mxGraphComponent getGraphComponent() { + return graphComponent; + } + + public Editor getEditor() { + return editor; + } + + public void setEditor(Editor editor) { + this.editor = editor; + } + + public Simulator getSimulator() { + return simulator; + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/simulator/UISimulatorWindow.java b/AlgebraicDataflowArchitectureModel/src/application/simulator/UISimulatorWindow.java new file mode 100644 index 0000000..1c246b9 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/simulator/UISimulatorWindow.java @@ -0,0 +1,29 @@ +package application.simulator; + +import javax.swing.JFrame; +import javax.swing.JPanel; + +import simulator.Simulator; +import simulator.interfaces.swing.SwingPresenter; +import simulator.interfaces.timers.TimerService; + +public class UISimulatorWindow extends JFrame { + + private static final long serialVersionUID = 1770206525826167136L; + private SwingPresenter presenter; + private Simulator simulator; + private JPanel mainPanel; + private TimerService timerService; + + public UISimulatorWindow(Simulator simulator) { + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + this.simulator = simulator; + mainPanel = new JPanel(); + presenter = new SwingPresenter(mainPanel, simulator); + this.add(mainPanel); + timerService = new TimerService(simulator); + + setSize(870,640); + setVisible(true); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/simulator/actions/ShowUISimulatorAction.java b/AlgebraicDataflowArchitectureModel/src/application/simulator/actions/ShowUISimulatorAction.java new file mode 100644 index 0000000..758d2d9 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/simulator/actions/ShowUISimulatorAction.java @@ -0,0 +1,23 @@ +package application.simulator.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; + +import application.simulator.UISimulatorWindow; +import simulator.Simulator; + +public class ShowUISimulatorAction extends AbstractAction { + private Simulator simulator; + + public ShowUISimulatorAction(Simulator simulator) { + super("Show UI Simulator"); + this.simulator = simulator; + } + + @Override + public void actionPerformed(ActionEvent e) { + new UISimulatorWindow(simulator); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/application/views/NavigationWindow.java b/AlgebraicDataflowArchitectureModel/src/application/views/NavigationWindow.java new file mode 100644 index 0000000..cddad6c --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/application/views/NavigationWindow.java @@ -0,0 +1,87 @@ +package application.views; + +import application.ApplicationWindow; +import application.editor.Editor; +import application.editor.IStageChangeListener; +import application.editor.Stage; +import application.editor.stages.DataFlowModelingStage; +import application.editor.stages.PushPullSelectionStage; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class NavigationWindow extends JDialog implements IStageChangeListener { + + private static final String TITLE = "Navigation"; + private final Editor editor; + + private final JToggleButton dataFlowModelingButton; + private final JToggleButton pushPullSelectionButton; + + private boolean forbidReentry = false; + + public NavigationWindow(ApplicationWindow owner, Editor editor) { + super(owner); + this.editor = editor; + dataFlowModelingButton = new JToggleButton("Data Flow Modeling"); + pushPullSelectionButton = new JToggleButton("Push Pull Selection"); + dataFlowModelingButton.addActionListener(new DataFlowModelingButtonListener()); + pushPullSelectionButton.addActionListener(new PushPullSelectionButtonListener()); + pushPullSelectionButton.setEnabled(false); + dataFlowModelingButton.setSelected(true); + + setTitle(TITLE); + setDefaultCloseOperation(HIDE_ON_CLOSE); + Container panel = getContentPane(); + panel.setLayout(new GridLayout(2, 1)); + + ButtonGroup group = new ButtonGroup(); + group.add(dataFlowModelingButton); + group.add(pushPullSelectionButton); + panel.add(dataFlowModelingButton); + panel.add(pushPullSelectionButton); + + pack(); + + Point location = new Point(owner.getX() + (owner.getWidth() / 2) - (this.getWidth() / 2), owner.getY() + (owner.getHeight() / 2) - (this.getHeight() / 2)); + setLocation(location); + + setResizable(false); + } + + @Override + public void stageChanged(Stage newStage) { + if (forbidReentry) { + return; + } + if (newStage instanceof DataFlowModelingStage) { + dataFlowModelingButton.setSelected(true); + pushPullSelectionButton.setEnabled(editor.canChange(Editor.STAGE_PUSH_PULL_SELECTION)); + } else if (newStage instanceof PushPullSelectionStage) { + pushPullSelectionButton.setSelected(true); + dataFlowModelingButton.setEnabled(editor.canChange(Editor.STAGE_DATA_FLOW_MODELING)); + } + } + + private class DataFlowModelingButtonListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + forbidReentry = true; + editor.changeStage(Editor.STAGE_DATA_FLOW_MODELING); + forbidReentry = false; + pushPullSelectionButton.setEnabled(editor.canChange(Editor.STAGE_PUSH_PULL_SELECTION)); + } + } + + private class PushPullSelectionButtonListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + forbidReentry = true; + editor.changeStage(Editor.STAGE_PUSH_PULL_SELECTION); + forbidReentry = false; + dataFlowModelingButton.setEnabled(editor.canChange(Editor.STAGE_DATA_FLOW_MODELING)); + } + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/AnnotatableType.java b/AlgebraicDataflowArchitectureModel/src/code/ast/AnnotatableType.java new file mode 100644 index 0000000..6e87c83 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/AnnotatableType.java @@ -0,0 +1,26 @@ +package code.ast; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents an abstract base class for AST types that can have annotations. + * This class extends the functionality of {@link Type} by introducing support + * for attaching annotations to the type. + *

+ * Subclasses of this class represent specific kinds of types in the AST that + * allow annotations, such as primitive types or other specialized types. + * + * @author s-yamagiwa + */ +public abstract class AnnotatableType extends Type { + private final List annotations = new ArrayList<>(); + + public void addAnnotation(Annotation annotation) { + annotations.add(annotation); + } + + public List getAnnotations() { + return annotations; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Assignment.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Assignment.java new file mode 100644 index 0000000..a7a2fc9 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Assignment.java @@ -0,0 +1,37 @@ +package code.ast; + +/** + * Represents an assignment expression node in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class Assignment extends Expression { + private Expression left; + private Expression right; + + public Assignment(Expression left, Expression right) { + this.left = left; + this.right = right; + } + + public Expression getLeft() { + return left; + } + + public void setLeft(Expression left) { + this.left = left; + } + + public Expression getRight() { + return right; + } + + public void setRight(Expression right) { + this.right = right; + } + + @Override + public String toString() { + return left.toString() + " " + "+" + " " + right.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java index 2b4f654..a7a07d9 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java @@ -2,31 +2,88 @@ import java.util.List; import java.util.ArrayList; +import java.util.stream.Collectors; -public class Block extends ASTNode { - private List statements = new ArrayList(); +public class Block extends Statement { + private List statements = new ArrayList(); - public List getStatements() { + public List getStatements2() { return statements; } - public void setStatements(List statements) { + public void setStatements(List statements) { this.statements = statements; } - public void addFirstStatement(String statement) { + public void addFirstStatement(Statement statement) { statements.add(0, statement); } - - public void addStatement(String statement) { + + public void addStatement(Statement statement) { statements.add(statement); } - - public String toString() { - String code = ""; - for (String statement: statements) { - code += (statement + "\n"); + + public void addFirstStatements(List statements) { + this.statements.addAll(0, statements); + } + + public void addStatements(List statements) { + this.statements.addAll(statements); + } + + //==================================================== + //TODO: CodeGenerator修正後削除 + + public List getStatements() { + List strings = new ArrayList<>(); + for (Statement stmt : statements) { + if (stmt != null) { + strings.add(stmt.toString()); + } } - return code; + return strings; + } + + public void addFirstStatement(String statement) { + if (statement != null) { + this.addFirstStatement(new Statement() { + @Override + public String toString() { + return statement; + } + }); + } + } + + public void addStatement(String statement) { + if (statement != null) { + this.addStatement(new PlainStatement(statement)); + } + } + + //==================================================== + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{\n"); + + for (Statement statement : statements) { + if (statement != null) { + String content = statement.toString(); + + // split statement + String[] lines = content.split("\n"); + + // Tab + for (String line : lines) { + sb.append("\t").append(line).append("\n"); + } + } + } + + sb.append("}"); + return sb.toString(); } } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ClassInstanceCreation.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ClassInstanceCreation.java new file mode 100644 index 0000000..fe20607 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ClassInstanceCreation.java @@ -0,0 +1,59 @@ +package code.ast; + +import java.util.List; + +public class ClassInstanceCreation extends Expression { + private Type type; + + private List arguments; + + public ClassInstanceCreation(Type type) { + this(type, List.of()); + } + + public ClassInstanceCreation(Type type, List arguments) { + this.type = type; + this.arguments = arguments; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public List getArguments() { + return arguments; + } + + public void setArguments(List arguments) { + this.arguments = arguments; + } + + public void addArgument(Expression expression) { + arguments.add(expression); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + + builder.append("new "); + builder.append(type.toString()); + builder.append("("); + for (int i = 0; i < arguments.size(); i++) { + Expression argument = arguments.get(i); + + builder.append(argument.toString()); + + if (i < arguments.size() - 1) { + builder.append(", "); + } + } + builder.append(")"); + + return builder.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/CodeUtil.java b/AlgebraicDataflowArchitectureModel/src/code/ast/CodeUtil.java index 99f1561..fd57c66 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/CodeUtil.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/CodeUtil.java @@ -10,34 +10,4 @@ } return newString; } - - public static String getToStringExp(String typeName, String rawExp) { - if (typeName.equals("int")) { - return "Integer.toString(" + rawExp + ")"; - } else if (typeName.equals("float")) { - return "Float.toString(" + rawExp + ")"; - } else if (typeName.equals("double")) { - return "Double.toString(" + rawExp + ")"; - } else if (typeName.equals("boolean")) { - return "Boolean.toString(" + rawExp + ")"; - } else { - return rawExp + ".toString()"; - } - } - - public static String getToValueExp(String typeName, String strExp) { - if (typeName.equals("int")) { - return "Integer.parseInt(" + strExp + ")"; - } else if (typeName.equals("float")) { - return "Float.parseFloat(" + strExp + ")"; - } else if (typeName.equals("double")) { - return "Double.parseDouble(" + strExp + ")"; - } else if (typeName.equals("boolean")) { - return "Boolean.parseBoolean(" + strExp + ")"; - } else if (typeName.startsWith("ArrayList") || typeName.startsWith("List")) { - return "Arrays.asList(" + strExp + ".replace(\"[\",\"\").replace(\"]\",\"\").split(\",\",0))"; - } else { - return strExp; - } - } } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Constant.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Constant.java new file mode 100644 index 0000000..f15c136 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Constant.java @@ -0,0 +1,27 @@ +package code.ast; + +/** + * Represents a constant in the AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class Constant extends Expression { + private String value; + + public Constant(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/EnhancedForStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/EnhancedForStatement.java new file mode 100644 index 0000000..a447d10 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/EnhancedForStatement.java @@ -0,0 +1,22 @@ +package code.ast; + +public class EnhancedForStatement extends Statement { + + private VariableDeclaration singleVariableDeclaration; + private Expression expression; + private Statement body; + + public VariableDeclaration getParameter() { return singleVariableDeclaration; } + public void setParameter(VariableDeclaration parameter) { this.singleVariableDeclaration = parameter; } + + public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { this.expression = expression; } + + public Statement getBody() { return body; } + public void setBody(Statement body) { this.body = body; } + + @Override + public String toString() { + return "for (" + singleVariableDeclaration + " : " + expression + ") " + body; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Expression.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Expression.java new file mode 100644 index 0000000..d492947 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Expression.java @@ -0,0 +1,9 @@ +package code.ast; + +/** + * Abstract base class for all expression nodes in the abstract syntax tree (AST). + * + * @author s-yamagiwa + */ +public abstract class Expression extends ASTNode { +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ExpressionStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ExpressionStatement.java new file mode 100644 index 0000000..f8fdf96 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ExpressionStatement.java @@ -0,0 +1,17 @@ +package code.ast; + +public class ExpressionStatement extends Statement{ + private Expression expression; + + public ExpressionStatement(Expression expression) { + this.expression = expression; + } + + public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { this.expression = expression; } + + @Override + public String toString() { + return expression + ";"; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/FieldAccess.java b/AlgebraicDataflowArchitectureModel/src/code/ast/FieldAccess.java new file mode 100644 index 0000000..bfae25d --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/FieldAccess.java @@ -0,0 +1,45 @@ +package code.ast; + +/** + * Represents field accesses in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class FieldAccess extends Expression { + private Expression expression; + + private String fieldName; + + public FieldAccess(String fieldName) { + this(null, fieldName); + } + + public FieldAccess(Expression expression, String fieldName) { + this.expression = expression; + this.fieldName = fieldName; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public String getFieldName() { + return fieldName; + } + + public void setFieldName(String fieldName) { + this.fieldName = fieldName; + } + + @Override + public String toString() { + if (expression == null) { + return fieldName; + } + return expression + "." + fieldName; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/FieldDeclaration.java b/AlgebraicDataflowArchitectureModel/src/code/ast/FieldDeclaration.java index 0993b92..cedf1a4 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/FieldDeclaration.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/FieldDeclaration.java @@ -9,7 +9,8 @@ public class FieldDeclaration extends BodyDeclaration implements IAnnotatable { private Type type; private String fieldName; - private String initializer; + private String initializer = null; + private String initializationBlock = null; private Map annotations = new HashMap<>(); public FieldDeclaration(Type type, String fieldName) { @@ -47,6 +48,14 @@ this.initializer = initializer; } + public String getInitializationBlock() { + return initializationBlock; + } + + public void setInitializationBlock(String initializationBlock) { + this.initializationBlock = initializationBlock; + } + @Override public Annotation getAnnotation(String name) { return annotations.get(name); @@ -67,10 +76,14 @@ for (Annotation annotation: getAnnotations()) { code += annotation.toString() + "\n"; } - if (initializer == null) { - code += "private " + type.getInterfaceTypeName() + " " + fieldName + ";\n"; + if (initializationBlock != null) { + code += "private " + type.getInterfaceTypeName() + " " + fieldName + ";\n" + initializationBlock + "\n"; } else { - code += "private " + type.getInterfaceTypeName() + " " + fieldName + " = " + initializer + ";\n"; + if (initializer == null) { + code += "private " + type.getInterfaceTypeName() + " " + fieldName + ";\n"; + } else { + code += "private " + type.getInterfaceTypeName() + " " + fieldName + " = " + initializer + ";\n"; + } } return code; } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ForStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ForStatement.java new file mode 100644 index 0000000..479d6b5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ForStatement.java @@ -0,0 +1,69 @@ +package code.ast; + +import java.util.ArrayList; +import java.util.List; + +public class ForStatement extends Statement { + + private List initializers = new ArrayList<>(); + private Expression optionalConditionExpression; + private List updaters = new ArrayList<>(); + private Statement body; + + public List getInitializers() { + return initializers; + } + + public void setInitializers(List initializers) { + this.initializers = initializers; + } + + public Expression getExpression() { + return optionalConditionExpression; + } + + public void setExpression(Expression expression) { + this.optionalConditionExpression = expression; + } + + public List getUpdaters() { + return updaters; + } + + public void setUpdaters(List updaters) { + this.updaters = updaters; + } + + public Statement getBody() { + return body; + } + + public void setBody(Statement body) { + this.body = body; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("for ("); + + for (int i = 0; i < initializers.size(); i++) { + sb.append(initializers.get(i)); + if (i < initializers.size() - 1) sb.append(", "); + } + sb.append("; "); + + if (optionalConditionExpression != null) sb.append(optionalConditionExpression); + sb.append("; "); + + for (int i = 0; i < updaters.size(); i++) { + sb.append(updaters.get(i)); + if (i < updaters.size() - 1) sb.append(", "); + } + sb.append(") "); + + if (body != null) sb.append(body); + + return sb.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/IfStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/IfStatement.java new file mode 100644 index 0000000..d688700 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/IfStatement.java @@ -0,0 +1,43 @@ +package code.ast; + +public class IfStatement extends Statement { + + private Expression expression; + private Statement thenStatement; + private Statement elseStatement; + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public Statement getThenStatement() { + return thenStatement; + } + + public void setThenStatement(Statement thenStatement) { + this.thenStatement = thenStatement; + } + + public Statement getElseStatement() { + return elseStatement; + } + + public void setElseStatement(Statement elseStatement) { + this.elseStatement = elseStatement; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("if (").append(expression).append(") "); + sb.append(thenStatement); + if (elseStatement != null) { + sb.append(" else ").append(elseStatement); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/InfixExpression.java b/AlgebraicDataflowArchitectureModel/src/code/ast/InfixExpression.java new file mode 100644 index 0000000..8aa90be --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/InfixExpression.java @@ -0,0 +1,50 @@ +package code.ast; + +import models.algebra.Symbol; + +/** + * Represents an infix expression in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class InfixExpression extends Expression { + private Symbol operator; + + private Expression leftOperand; + private Expression rightOperand; + + public InfixExpression(Symbol operator, Expression leftOperand, Expression rightOperand) { + this.operator = operator; + this.leftOperand = leftOperand; + this.rightOperand = rightOperand; + } + + public Symbol getOperator() { + return this.operator; + } + + public void setOperator(Symbol operator) { + this.operator = operator; + } + + public Expression getLeftOperand() { + return leftOperand; + } + + public void setLeftOperand(Expression expression) { + this.leftOperand = expression; + } + + public Expression getRightOperand() { + return rightOperand; + } + + public void setRightOperand(Expression expression) { + this.rightOperand = expression; + } + + @Override + public String toString() { + return leftOperand.toString() + " " + operator.toString() + " " + rightOperand.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Lexer.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Lexer.java new file mode 100644 index 0000000..cd2974c --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Lexer.java @@ -0,0 +1,55 @@ +package code.ast; + +/** + * The Lexer class provides functionalities for parsing and iterating through + * a source string of text character by character. + * + * @author s-yamagiwa; + */ +public class Lexer { + private final String source; + private int position; + + public Lexer(String source) { + this.source = source; + this.position = 0; + } + + /** + * Retrieves the next character without advancing the position. + * + * @return The next character. + */ + public char peek() { + if (position >= source.length()) { + return '\0'; // End of line + } + + return source.charAt(position); + } + + /** + * Retrieves the next character after advancing the position. + * + * @return The next character. + */ + public char peekNext() { + if (position + 1 >= source.length()) { + return '\0'; // End of line + } + + return source.charAt(position + 1); + } + + /** + * Advances the position by one character. + * + * @return The character that was previously at the current position. + */ + public char advance() { + char current = peek(); + position++; + + return current; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java b/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java index fad7629..333388e 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java @@ -82,6 +82,9 @@ } public Block getBody() { + if (body == null) { + body = new Block(); + } return body; } @@ -89,6 +92,13 @@ this.body = body; } + public void addStatement(Statement statement) { + if (body == null) { + body = new Block(); + } + body.addStatement(statement); + } + public void addStatement(String statement) { if (body == null) { body = new Block(); @@ -96,6 +106,13 @@ body.addStatement(statement); } + public void addFirstStatement(Statement statement) { + if (body == null) { + body = new Block(); + } + body.addFirstStatement(statement); + } + public void addFirstStatement(String statement) { if (body == null) { body = new Block(); @@ -109,6 +126,10 @@ } thrws.addException(exception); } + + public Throws getThrows() { + return thrws; + } @Override public Annotation getAnnotation(String name) { @@ -138,21 +159,18 @@ } code += (name + "("); if (parameters != null) { - String delimitar = ""; - for (VariableDeclaration parameter: parameters) { - code = code + delimitar + parameter.toString(); - delimitar = ", "; + for (int i = 0; i < parameters.size(); i++) { + code += parameters.get(i).toString(); + if (i < parameters.size() - 1) code += ", "; } } code += ") "; - if (thrws != null) { - code += thrws.toString() + " "; - } - code += "{\n"; + if (body != null) { - code += CodeUtil.insertTab(body.toString()); + code += body.toString(); + } else { + code += ";"; } - code += "}"; return code; } } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/MethodInvocation.java b/AlgebraicDataflowArchitectureModel/src/code/ast/MethodInvocation.java new file mode 100644 index 0000000..94c90e1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/MethodInvocation.java @@ -0,0 +1,91 @@ +package code.ast; + +import java.util.List; + +/** + * Represents a method invocation in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + * @apiNote Type arguments aren't supported because it isn't necessary in DTRAM code generator. + */ +public class MethodInvocation extends Expression { + /** + * The receiver expression of the invocation + * defaults to {@code null} + */ + private Expression receiver; + + /** + * The method name to be called by this invocation + */ + private String methodName; + + /** + * All arguments used in the called method + */ + private List arguments; + + public MethodInvocation(String methodName) { + this(null, methodName); + } + + public MethodInvocation(Expression receiver, String methodName) { + this(receiver, methodName, List.of()); + } + + public MethodInvocation(Expression receiver, String methodName, List arguments) { + this.receiver = receiver; + this.methodName = methodName; + this.arguments = arguments; + } + + public Expression getReceiver() { + return receiver; + } + + public void setReceiver(Expression receiver) { + this.receiver = receiver; + } + + public String getMethodName() { + return methodName; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + public List getArguments() { + return arguments; + } + + public void setArguments(List arguments) { + this.arguments = arguments; + } + + @Override + public String toString() { + if (receiver == null) { + StringBuilder builder = new StringBuilder(); + + builder.append(methodName).append("("); + + if (!arguments.isEmpty()) { + for (int i = 0; i < arguments.size(); i++) { + Expression argument = arguments.get(i); + + builder.append(argument.toString()); + + if (i < arguments.size() - 1) { + builder.append(", "); + } + } + } + + builder.append(");"); + + return builder.toString(); + } + return super.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ParameterizedType.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ParameterizedType.java new file mode 100644 index 0000000..ca7d269 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ParameterizedType.java @@ -0,0 +1,109 @@ +package code.ast; + +import java.util.List; + +/** + * Represents a parameterized type in an abstract syntax tree (AST). + * A parameterized type consists of a base type and a set of type arguments. + *

+ * For example, List<String> is a parameterized type where + * List is the base type and String is the type argument. + * + * @author s-yamagiwa + */ +public class ParameterizedType extends Type { + /** + * The base type of the parameterized type. + *

+ * For example, List in List<String> is a base type. + */ + private Type type; + + /** + * The type arguments of the parameterized type. + * Defaults to an empty list. + *

+ * For example, String in List<String> is a type argument. + */ + private List typeArguments; + + public ParameterizedType(Type type, List typeArguments) { + this.type = type; + this.typeArguments = typeArguments; + } + + public ParameterizedType(Type type) { + this(type, List.of()); + } + + /** + * Adds a type argument to the parameterized type. + * + * @param type The type argument to add. Only {@link SimpleType}s are allowed for now. + */ + public void addTypeArgument(Type type) { + typeArguments.add(type); + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + /** + * Returns the type arguments of the parameterized type. + * Only {@link SimpleType}s are allowed for now. + *

+ * It can be empty if it is the type of created instances like in the following example. + * new List<>() or new HashMap<>() + * + * @return The type arguments of the parameterized type. + */ + public List getTypeArguments() { + return typeArguments; + } + + public void setTypeArguments(List typeArguments) { + this.typeArguments = typeArguments; + } + + + /** + * Replace all type arguments and their descendant types that match the replacedType with the replacingType. + * @param replacedType the type to be replaced + * @param replacingType the type to replace with + */ + public void replaceSubTypes(Type replacedType, Type replacingType) { + for (int i = 0; i < typeArguments.size(); i++) { + Type typeArgment = typeArguments.get(i); + if (typeArgment.equals(replacedType)) { + typeArguments.set(i, replacingType); + } else if (typeArgment instanceof ParameterizedType) { + ((ParameterizedType) typeArgment).replaceSubTypes(replacedType, replacingType); + } + } + } + + @Override + public String toString() { + if (typeArguments.isEmpty()) { + return type.toString(); + } + + StringBuilder builder = new StringBuilder(); + builder.append(type.toString()); + builder.append("<"); + for (int i = 0; i < typeArguments.size(); i++) { + builder.append(typeArguments.get(i).toString()); + if (i < typeArguments.size() - 1) { + builder.append(", "); + } + } + builder.append(">"); + + return builder.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ParenthesizedExpression.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ParenthesizedExpression.java new file mode 100644 index 0000000..a7b50cb --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ParenthesizedExpression.java @@ -0,0 +1,28 @@ +package code.ast; + +/** + * Represents a parenthesized expression in AST (Abstract Syntax Tree) + * This class is used to save the priority of each expression + * + * @author s-yamagiwa + */ +public class ParenthesizedExpression extends Expression { + private Expression expression; + + public ParenthesizedExpression(Expression expression) { + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public String toString() { + return "(" + expression.toString() + ")"; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/PlainStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/PlainStatement.java new file mode 100644 index 0000000..edc9ff5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/PlainStatement.java @@ -0,0 +1,18 @@ +package code.ast; + +//==================================================== +//TODO: CodeGenerator修正後削除 +//==================================================== + +public class PlainStatement extends Statement { + private String code; + + public PlainStatement(String code) { + this.code = code; + } + + @Override + public String toString() { + return code; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/PostfixExpression.java b/AlgebraicDataflowArchitectureModel/src/code/ast/PostfixExpression.java new file mode 100644 index 0000000..bc520ac --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/PostfixExpression.java @@ -0,0 +1,53 @@ +package code.ast; + +/** + * Represents a postfix expression in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class PostfixExpression extends Expression { + public enum Operator { + INCREMENT("++"), DECREMENT("--"); + + Operator(String symbol) { + this.symbol = symbol; + } + + private final String symbol; + + @Override + public String toString() { + return symbol; + } + } + + private Expression operand; + + private Operator operator; + + public PostfixExpression(Expression operand, Operator operator) { + this.operand = operand; + this.operator = operator; + } + + public Expression getOperand() { + return operand; + } + + public void setOperand(Expression operand) { + this.operand = operand; + } + + public Operator getOperator() { + return operator; + } + + public void setOperator(Operator operator) { + this.operator = operator; + } + + @Override + public String toString() { + return operand.toString() + operator.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/PrefixExpression.java b/AlgebraicDataflowArchitectureModel/src/code/ast/PrefixExpression.java new file mode 100644 index 0000000..2e854b7 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/PrefixExpression.java @@ -0,0 +1,53 @@ +package code.ast; + +/** + * Represents a prefix expression in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class PrefixExpression extends Expression { + public enum Operator { + INCREMENT("++"), DECREMENT("--"), PLUS("+"), MINUS("-"), NOT("!"); + + Operator(String symbol) { + this.symbol = symbol; + } + + private final String symbol; + + @Override + public String toString() { + return symbol; + } + } + + private Expression operand; + + private Operator operator; + + public PrefixExpression(Expression operand, Operator operator) { + this.operand = operand; + this.operator = operator; + } + + public Expression getOperand() { + return operand; + } + + public void setOperand(Expression operand) { + this.operand = operand; + } + + public Operator getOperator() { + return operator; + } + + public void setOperator(Operator operator) { + this.operator = operator; + } + + @Override + public String toString() { + return operator.toString() + operand.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java b/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java new file mode 100644 index 0000000..3381022 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java @@ -0,0 +1,34 @@ +package code.ast; + +/** + * Represents a primitive type in the abstract syntax tree (AST). + * This class extends the {@code AnnotatableType}, allowing annotations + * to be attached to primitive types. + *

+ * Primitive types are: {@code boolean}, {@code byte}, {@code char}, {@code short}, {@code int}, {@code long}, {@code float}, {@code double} and {@code void} + * + * @author s-yamagiwa + */ +public class PrimitiveType extends AnnotatableType { + private String typeName; + + public PrimitiveType(String typeName) { + this.typeName = typeName; + } + + @Override + public String toString() { + if (getAnnotations().isEmpty()) { + return typeName; + } + + StringBuilder builder = new StringBuilder(); + for (Annotation annotation : getAnnotations()) { + builder.append(annotation.toString()); + builder.append(" "); + } + builder.append(typeName); + + return builder.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ReturnStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ReturnStatement.java new file mode 100644 index 0000000..400de02 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ReturnStatement.java @@ -0,0 +1,21 @@ +package code.ast; + +public class ReturnStatement extends Statement{ + private Expression expression; + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public String toString() { + if (expression != null) { + return "return " + expression + ";"; + } + return "return;"; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/SimpleType.java b/AlgebraicDataflowArchitectureModel/src/code/ast/SimpleType.java new file mode 100644 index 0000000..3451ee3 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/SimpleType.java @@ -0,0 +1,39 @@ +package code.ast; + +/** + * Represents a simple type in the AST, which is a type with a single identifier. + * For example, String, List, Map or MyClass. + * + * @author s-yamagiwa + */ +public class SimpleType extends AnnotatableType { + private String name; + + public SimpleType(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + if (getAnnotations().isEmpty()) { + return name; + } + + StringBuilder builder = new StringBuilder(); + for (Annotation annotation : getAnnotations()) { + builder.append(annotation.toString()); + builder.append(" "); + } + builder.append(name); + + return builder.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Statement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Statement.java new file mode 100644 index 0000000..96d1af1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Statement.java @@ -0,0 +1,7 @@ +package code.ast; + +public abstract class Statement extends ASTNode { + + @Override + public abstract String toString(); +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/SuperMethodInvocation.java b/AlgebraicDataflowArchitectureModel/src/code/ast/SuperMethodInvocation.java new file mode 100644 index 0000000..e7e3573 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/SuperMethodInvocation.java @@ -0,0 +1,62 @@ +package code.ast; + +import java.util.List; + +/** + * Represents a super method invocation in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + * @apiNote Type arguments aren't supported because it isn't necessary in DTRAM code generator. + */ +public class SuperMethodInvocation extends Expression { + private String methodName; + private List arguments; + + public SuperMethodInvocation(String methodName) { + this(methodName, List.of()); + } + + public SuperMethodInvocation(String methodName, List arguments) { + this.methodName = methodName; + this.arguments = arguments; + } + + public String getMethodName() { + return methodName; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + public List getArguments() { + return arguments; + } + + public void setArguments(List arguments) { + this.arguments = arguments; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + + builder.append("super.").append(methodName).append("("); + + if (!arguments.isEmpty()) { + for (int i = 0; i < arguments.size(); i++) { + Expression argument = arguments.get(i); + + builder.append(argument.toString()); + + if (i < arguments.size() - 1) { + builder.append(", "); + } + } + } + + builder.append(");"); + + return builder.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ThisExpression.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ThisExpression.java new file mode 100644 index 0000000..aad8ee8 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ThisExpression.java @@ -0,0 +1,4 @@ +package code.ast; + +public class ThisExpression extends Expression { +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java new file mode 100644 index 0000000..d5291e9 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java @@ -0,0 +1,37 @@ +package code.ast; + +/** + * Represents an abstract base class for all types in an abstract syntax tree (AST). + * A type can represent various forms such as primitive types, simple types, + * parameterized types, or others as defined by subclasses. + * + * @author s-yamagiwa + */ +public abstract class Type extends ASTNode implements models.algebra.Type.ITypeImpl { + /** + * Returns whether this type is a primitive type or not. + * + * @return true if this type is a primitive type, false otherwise. + */ + public final boolean isPrimitiveType() { + return (this instanceof PrimitiveType); + } + + /** + * Returns whether this type is a simple type or not. + * + * @return true if this type is a simple type, false otherwise. + */ + public final boolean isSimpleType() { + return (this instanceof SimpleType); + } + + /** + * Returns whether this type is a parameterized type or not. + * + * @return true if this type is a parameterized type, false otherwise. + */ + public final boolean isParameterizedType() { + return (this instanceof ParameterizedType); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/TypeLiteral.java b/AlgebraicDataflowArchitectureModel/src/code/ast/TypeLiteral.java new file mode 100644 index 0000000..4163b7d --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/TypeLiteral.java @@ -0,0 +1,27 @@ +package code.ast; + +/** + * Represents a type literal expression in the AST. + * + * @author s-yamagiwa + */ +public class TypeLiteral extends Expression { + private Type type; + + public TypeLiteral(Type type) { + this.type = type; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + @Override + public String toString() { + return type.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Variable.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Variable.java new file mode 100644 index 0000000..6d3dc00 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Variable.java @@ -0,0 +1,27 @@ +package code.ast; + +/** + * Represents a variable in the AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class Variable extends Expression { + private String name; + + public Variable(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclaration.java b/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclaration.java index 6a7b25b..5d86c98 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclaration.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclaration.java @@ -9,6 +9,7 @@ public class VariableDeclaration extends ASTNode implements IAnnotatable { private Type type; private String variableName; + private Expression optionalInitializer; private Map annotations = new HashMap<>(); public VariableDeclaration(Type type, String variableName) { @@ -16,6 +17,11 @@ this.variableName = variableName; } + public VariableDeclaration(Type type, String variableName, Expression initializer) { + this(type, variableName); + this.optionalInitializer = initializer; + } + public Type getType() { return type; } @@ -32,6 +38,10 @@ this.variableName = variableName; } + public Expression getInitializer() { return optionalInitializer; } + + public void setInitializer(Expression initializer) { this.optionalInitializer = initializer; } + @Override public Annotation getAnnotation(String name) { return annotations.get(name); diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclarationStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclarationStatement.java new file mode 100644 index 0000000..bdc0ad4 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclarationStatement.java @@ -0,0 +1,60 @@ +package code.ast; + +import java.util.ArrayList; +import java.util.List; + +public class VariableDeclarationStatement extends Statement { + + private List modifiers = new ArrayList<>(); + private Type type; + private List fragments = new ArrayList<>(); + + public List getModifiers() { + return modifiers; + } + + public void setModifiers(List modifiers) { + this.modifiers = modifiers; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public List getFragments() { + return fragments; + } + + public void addFragment(VariableDeclaration fragment) { + this.fragments.add(fragment); + } + + public void setFragments(List fragments) { + this.fragments = fragments; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + for (Integer mod : modifiers) { + sb.append(mod.toString()).append(" "); + } + + if (type != null) { + sb.append(type.toString()).append(" "); + } + + for (int i = 0; i < fragments.size(); i++) { + sb.append(fragments.get(i).getName()); + if (i < fragments.size() - 1) sb.append(", "); + } + + sb.append(";"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/WhileStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/WhileStatement.java new file mode 100644 index 0000000..6d22d84 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/WhileStatement.java @@ -0,0 +1,33 @@ +package code.ast; + +public class WhileStatement extends Statement { + + private Expression expression; + private Statement body; + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public Statement getBody() { + return body; + } + + public void setBody(Statement body) { + this.body = body; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("while (").append(expression).append(") "); + if (body != null) { + sb.append(body); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerationContext.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerationContext.java new file mode 100644 index 0000000..157806d --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerationContext.java @@ -0,0 +1,144 @@ +package generators; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import code.ast.TypeDeclaration; +import models.algebra.Type; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ListType; +import models.dataConstraintModel.MapType; +import models.dataConstraintModel.ResourceHierarchy; +import models.dataFlowModel.DataTransferChannel; + +public class CodeGenerationContext { + protected HashMap> componentNames = new HashMap<>(); + protected Map resourceHierarchyToComponent; + protected Map componentNameToType; + protected Map>> updateMethods; + protected ILanguageSpecific langSpec = null; + protected IPlatformSpecific platformSpec = null; + + public CodeGenerationContext(ILanguageSpecific langSpec, IPlatformSpecific platformSpec) { + this.resourceHierarchyToComponent = new HashMap<>(); + this.componentNameToType = new HashMap<>(); + this.updateMethods = new HashMap<>(); + this.langSpec = langSpec; + this.platformSpec = platformSpec; + } + + public String getComponentName(ResourceHierarchy res, ILanguageSpecific langSpec) { + String name = res.getResourceName(); + if (res.getNumParameters() > 0) { + if (name.length() > 3 && name.endsWith("ies")) { + name = name.substring(0, name.length() - 3) + "y"; + } else if (name.length() > 1 && name.endsWith("s")) { + name = name.substring(0, name.length() - 1); + } else { + name += "Element"; + } + } + String componentName = langSpec.toComponentName(name); + if (!generatesComponent(res)) return componentName; + // To avoid generating multiple components with the same name. + HashMap resToName = componentNames.get(componentName); + if (resToName == null) { + resToName = new HashMap<>(); + resToName.put(res, componentName); + componentNames.put(componentName, resToName); + return componentName; + } + if (resToName.get(res) == null) { + componentName += resToName.size(); + resToName.put(res, componentName); + return componentName; + } + return resToName.get(res); + } + + public Type getOrCreateComponentType(ResourceHierarchy res) { + return getOrCreateComponentType(getComponentName(res, langSpec)); + } + + public Type getOrCreateComponentType(String componentName) { + Type componentType = componentNameToType.get(componentName); + if (componentType != null) return componentType; + componentType = new Type(componentName, new code.ast.SimpleType(componentName)); + componentNameToType.put(componentName, componentType); + return componentType; + } + + public Type getImplStateType(ResourceHierarchy res, ILanguageSpecific langSpec) { + Set children = res.getChildren(); + if (children == null || children.size() == 0) { + // leaf resource. + return res.getResourceStateType(); + } else { + ResourceHierarchy child = children.iterator().next(); + if (children.size() == 1 && child.getNumParameters() > 0) { + // map or list. + if (DataConstraintModel.typeList.isAncestorOf(res.getResourceStateType()) || res.getResourceStateType() instanceof ListType) { + // list. + if (generatesComponent(child)) { + return langSpec.newListType(getOrCreateComponentType(child)); + } else { + return langSpec.newListType(getImplStateType(child, langSpec)); + } + } else if (DataConstraintModel.typeMap.isAncestorOf(res.getResourceStateType()) || res.getResourceStateType() instanceof MapType) { + // map. + if (generatesComponent(child)) { + return langSpec.newMapType(DataConstraintModel.typeString, getOrCreateComponentType(child).getInterfaceTypeName()); + } else { + return langSpec.newMapType(DataConstraintModel.typeString, getImplStateType(child, langSpec).getInterfaceTypeName()); + } + } + return null; + } else { + // class + return res.getResourceStateType(); + } + } + } + + public boolean generatesComponent(ResourceHierarchy res) { + if (res.getParent() == null) return true; + if (res.getChildren() == null || res.getChildren().size() == 0) return false; + if (res.getNumParameters() > 0 && res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0) return false; + if (res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0 + && (res.getChildren().iterator().next().getChildren() == null || res.getChildren().iterator().next().getChildren().size() == 0)) return false; + return true; +// return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); + } + + public void putComponent(ResourceHierarchy res, TypeDeclaration component) { + resourceHierarchyToComponent.put(res, component); + } + + public TypeDeclaration getComponent(ResourceHierarchy res) { + return resourceHierarchyToComponent.get(res); + } + + + public String getOrPutUpdateMethodName(ResourceHierarchy srcRes, DataTransferChannel ch, ResourceHierarchy dstRes) { + Map> dstResUpdatesMethods = updateMethods.getOrDefault(dstRes, new HashMap<>()); + updateMethods.put(dstRes, dstResUpdatesMethods); + Map dstResFromSrcResUpdatesMethods = dstResUpdatesMethods.getOrDefault(srcRes, new HashMap<>()); + dstResUpdatesMethods.put(srcRes, dstResFromSrcResUpdatesMethods); + String updateMethodName = dstResFromSrcResUpdatesMethods.get(ch); + if (updateMethodName == null) { + String srcResComponentName = getComponentName(srcRes, langSpec); + String dstResComponentName = getComponentName(dstRes, langSpec); + if (generatesComponent(dstRes)) { + updateMethodName = CodeGenerator.updateMethodPrefix + CodeGenerator.from + srcResComponentName; + } else if (dstRes.getParent() != null) { + updateMethodName = CodeGenerator.updateMethodPrefix + dstResComponentName + CodeGenerator.from + srcResComponentName; + } + if (dstResFromSrcResUpdatesMethods.size() > 0) { + updateMethodName += dstResFromSrcResUpdatesMethods.size() + 1; // To avoid declaring the method multiply. + } + dstResFromSrcResUpdatesMethods.put(ch, updateMethodName); + } + return updateMethodName; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java new file mode 100644 index 0000000..e38225a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -0,0 +1,1272 @@ +package generators; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +import code.ast.*; +import models.Edge; +import models.Node; +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Field; +import models.algebra.Parameter; +import models.algebra.Symbol; +import models.algebra.Term; +import models.algebra.Type; +import models.algebra.Variable; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ListType; +import models.dataConstraintModel.MapType; +import models.dataConstraintModel.PairType; +import models.dataConstraintModel.ResourceHierarchy; +import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; +import models.dataConstraintModel.TupleType; +import models.dataFlowModel.ChannelNode; +import models.dataFlowModel.DataFlowEdge; +import models.dataFlowModel.DataFlowGraph; +import models.dataFlowModel.DataTransferChannel; +import models.dataFlowModel.DataTransferModel; +import models.dataFlowModel.PushPullAttribute; +import models.dataFlowModel.PushPullValue; +import models.dataFlowModel.ResourceNode; +import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; + +/** + * Common generator for prototypes + * + * @author Nitta + * + */ +public abstract class CodeGenerator { + public static final String fieldOfResourceState = "value"; + public static final String methoNameOfResourceState = "Value"; + public static final String getterPrefix = "get"; + public static final String getterOfResourceState = getterPrefix + methoNameOfResourceState; // "getValue" + public static final String updateMethodPrefix = "update"; + public static final String from = "From"; + public static final String _for = "For"; + public static final String presenter = "presenter"; + public static final Type presenterType = new Type("SwingPresenter", new code.ast.SimpleType("SwingPresenter")); + private static String mainTypeName = null; + protected CodeGenerationContext generationContext = null; + protected ILanguageSpecific langSpec = null; + protected IPlatformSpecific platformSpec = null; + + public CodeGenerator(IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + this.langSpec = langSpec; + this.platformSpec = platformSpec; + this.generationContext = new CodeGenerationContext(langSpec, platformSpec); + } + + public String getMainTypeName() { + return mainTypeName; + } + + public void setMainTypeName(String mainTypeName) { + CodeGenerator.mainTypeName = mainTypeName; + } + + public void resetMainTypeName() { + CodeGenerator.mainTypeName = null; + } + + public String getComponentName(ResourceHierarchy res, ILanguageSpecific langSpec) { + return generationContext.getComponentName(res, langSpec); + } + + public Type getImplStateType(ResourceHierarchy res, ILanguageSpecific langSpec) { + return generationContext.getImplStateType(res, langSpec); + } + + public boolean generatesComponent(ResourceHierarchy res) { + return generationContext.generatesComponent(res); + } + + /** + * Generate source codes in specified language from data-flow/control-flow graph. + * + * @param model architecture model + * @param flowGraph data-flow or control-flow graph + * @param langSpec specified language + * @return source codes + */ + public ArrayList generateCode(DataTransferModel model, DataFlowGraph flowGraph) { + ArrayList codes = new ArrayList<>(); + + Map> dependedRootComponentGraph = null; + Collection components = null; + if (platformSpec.isMonolithic()) { + // To build monolithic application, the dependency of the components should be resolved in advance. + + // Get the dependency among root nodes. + dependedRootComponentGraph = getDependedRootComponentGraph(model); + + // Sort the all components. + components = determineComponentOrder(flowGraph, dependedRootComponentGraph); + } else { + // Get the all components. + components = flowGraph.getResourceNodes(); + } + + // Generate the other components. + generateCodeFromFlowGraph(model, flowGraph, components, codes, dependedRootComponentGraph); + + return codes; + } + + public abstract void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, Collection components, ArrayList codes, Map> dependedRootComponentGraph); + + private static Map> getDependedRootComponentGraph(DataTransferModel model) { + Map> dependedComponentGraph = new HashMap<>(); + for (Channel ch: model.getChannels()) { + Set inRes = new HashSet<>(); + Set outRes = new HashSet<>(); + getDependedRootComponentGraphSub(ch, inRes, outRes, true); + if (outRes.size() > 0 && inRes.size() > 0) { + for (ResourceHierarchy out: outRes) { + for (ResourceHierarchy in: inRes) { + Set dependings = dependedComponentGraph.get(out.getRoot()); + if (dependings == null) { + dependings = new HashSet<>(); + dependedComponentGraph.put(out.getRoot(), dependings); + } + if (!out.getRoot().equals(in.getRoot())) { + dependings.add(in.getRoot()); + } + } + } + } + } + return dependedComponentGraph; + } + + private static void getDependedRootComponentGraphSub(Channel ch, Set inRes, Set outRes, boolean isRoot) { + DataTransferChannel dtCh = (DataTransferChannel) ch; + for (ChannelMember cm: dtCh.getChannelMembers()) { + if (!isRoot && !cm.isOutside()) { + outRes.add(cm.getResource().getResourceHierarchy()); // dependency to a descendant channel resource. + } + if (cm.isOutside()) { + outRes.add(cm.getResource().getResourceHierarchy()); // dependency to an outside resource. + } else { + inRes.add(cm.getResource().getResourceHierarchy()); // dependency from an inside resource. + } + } + for (Channel childCh: ch.getChildren()) { + getDependedRootComponentGraphSub(childCh, inRes, outRes, false); + } + } + + private static ArrayList determineComponentOrder(DataFlowGraph graph, Map> dependedRootComponentGraph) { + ArrayList objects = new ArrayList<>(); + Set visited = new HashSet<>(); + Collection allNodes = graph.getResourceNodes(); + for (ResourceNode resNode: allNodes) { + topologicalSort(resNode, allNodes, dependedRootComponentGraph, visited, objects); + } + return objects; + } + + private static void topologicalSort(ResourceNode curResNode, Collection allNodes, Map> dependedRootComponentGraph, Set visited, List orderedList) { + if (visited.contains(curResNode)) return; + visited.add(curResNode); + // A caller is before the callee + + // For each incoming PUSH transfer. + for (Edge chToRes: curResNode.getInEdges()) { + for (Edge resToCh: chToRes.getSource().getInEdges()) { + if (!(resToCh instanceof DataFlowEdge) || ((PushPullAttribute)((DataFlowEdge) resToCh).getAttribute()).getSelectedOption() == PushPullValue.PUSH) { + topologicalSort((ResourceNode) resToCh.getSource(), allNodes, dependedRootComponentGraph, visited, orderedList); + } + } + } + // For each outgoing PULL transfer. + if (curResNode instanceof ResourceNode) { + for (Edge resToCh: curResNode.getOutEdges()) { + DataFlowEdge de = (DataFlowEdge) resToCh; + if (((PushPullAttribute) de.getAttribute()).getSelectedOption() != PushPullValue.PUSH) { + for (Edge chToRes : resToCh.getDestination().getOutEdges()) { + topologicalSort((ResourceNode) chToRes.getDestination(), allNodes, dependedRootComponentGraph, visited, orderedList); + } + } + } + } + // For each depending root node. + if (curResNode instanceof ResourceNode && dependedRootComponentGraph.get(curResNode.getResourceHierarchy()) != null) { + for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(curResNode.getResourceHierarchy())) { + for (ResourceNode rootNode: allNodes) { + ResourceHierarchy rootRes = rootNode.getResourceHierarchy(); + if (rootRes.getParent() == null && rootRes.equals(dependingRes)) { + topologicalSort(rootNode, allNodes, dependedRootComponentGraph, visited, orderedList); + } + } + } + } + // For each reference resource. + ResourceNode cn = null; + if (curResNode instanceof ResourceNode) { + cn = (ResourceNode) curResNode; + } + if (cn != null) { + for (Node n: allNodes) { + ResourceNode resNode = null; + if (n instanceof ResourceNode) { + resNode = (ResourceNode) n; + } + if (resNode != null) { + for (Edge resToCh: resNode.getOutEdges()) { + ChannelNode chNode = (ChannelNode) resToCh.getDestination(); + for (ChannelMember m: chNode.getChannel().getReferenceChannelMembers()) { + if (curResNode.getOutSideResources().contains(m.getResource())) { + topologicalSort(resNode, allNodes, dependedRootComponentGraph, visited, orderedList); + } + } + } + } + } + } + orderedList.add(0, curResNode); + } + + protected void updateMainComponent(TypeDeclaration mainType, MethodDeclaration mainConstructor, Node componentNode, MethodDeclaration constructor, final List depends) { + // Declare the field to refer to each object in the main type. + ResourceNode resNode = null; + String nodeName = null; + if (componentNode instanceof ResourceNode) { + resNode = (ResourceNode) componentNode; + nodeName = resNode.getResourceName(); + } + String componentName = langSpec.toComponentName(nodeName); + // Declare a field to refer each object. + if (langSpec.declareField()) { + FieldDeclaration refField = langSpec.newFieldDeclaration(generationContext.getOrCreateComponentType(componentName), nodeName); + mainType.addField(refField); + } + // Add a statement to instantiate each object to the main constructor. + List parameters = new ArrayList<>(); + for (ResourceHierarchy res: depends) { + parameters.add(res.getResourceName()); + } + if (constructor.getParameters() != null) { + for (VariableDeclaration var: constructor.getParameters()) { + if (!parameters.contains(var.getName())) { + parameters.add(var.getName()); + } + } + } + + Block mainConstructorBody = mainConstructor.getBody(); + if (mainConstructorBody == null) { + mainConstructorBody = new Block(); + mainConstructor.setBody(mainConstructorBody); + } + mainConstructorBody.addStatement(langSpec.getFieldAccessor(nodeName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(componentName, parameters) + langSpec.getStatementDelimiter()); + } + + protected ResourceHierarchy addReference(TypeDeclaration component, MethodDeclaration constructor, ResourceHierarchy dstRes, ILanguageSpecific langSpec) { + if (!generatesComponent(dstRes)) { + dstRes = dstRes.getParent(); + } + String dstComponentName = getComponentName(dstRes, langSpec); + if (dstComponentName != null) { + String dstNodeName = langSpec.toVariableName(dstComponentName); + if (langSpec.declareField()) { + // Declare a field to refer to another component. + component.addField(langSpec.newFieldDeclaration(generationContext.getOrCreateComponentType(dstComponentName), dstNodeName)); + } + // Initialize the field to refer to another component. + constructor.addParameter(langSpec.newVariableDeclaration(generationContext.getOrCreateComponentType(dstComponentName), dstNodeName)); + constructor.getBody().addStatement(langSpec.getFieldAccessor(dstNodeName) + langSpec.getAssignment() + dstNodeName + langSpec.getStatementDelimiter()); + } + return dstRes; + } + + protected void fillStateGetterMethod(MethodDeclaration stateGetter, ResourceHierarchy resourceHierarchy, Type resStateType) { + // returns the state field when all incoming data-flow edges are PUSH-style. + if (langSpec.isValueType(resStateType)) { + stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState))); // return value; + } else { + if (resourceHierarchy.getChildren() != null && resourceHierarchy.getChildren().size() == 1 && resourceHierarchy.getChildren().iterator().next().getNumParameters() > 0) { + // list or map +// if (!platformSpec.isMonolithic()) { +// // For REST API +// stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState))); // return value; +// } else { + String implTypeName = resStateType.getImplementationTypeName(); + // copy the current state to be returned as a 'value' + List parameters = new ArrayList<>(); + parameters.add(langSpec.getFieldAccessor(fieldOfResourceState)); + stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters))); // return new Resource(value); +// } + } else { + if (resourceHierarchy.getChildren() == null || resourceHierarchy.getChildren().size() == 0) { +// // a leaf resource +// if (!platformSpec.isMonolithic()) { +// // For REST API +// stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState)) + langSpec.getStatementDelimiter()); // return value; +// } else { + String implTypeName = resStateType.getImplementationTypeName(); + // copy the current state to be returned as a 'value' + List parameters = new ArrayList<>(); + parameters.add(langSpec.getFieldAccessor(fieldOfResourceState)); + stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters))); // return new Resource(value); +// } + } else { + Term composer = null; + Term composerSub = new Constant(DataConstraintModel.nil); + composerSub.setType(DataConstraintModel.typeMap); + for (ResourceHierarchy child: resourceHierarchy.getChildren()) { + String childTypeName = getComponentName(child, langSpec); + String fieldName = child.getResourceName(); + Term childGetter = null; + if (!generatesComponent(child)) { + // the child is not a class + childGetter = new Term(new Symbol(getterPrefix + childTypeName, 1, Symbol.Type.METHOD)); + childGetter.addChild(new Constant(langSpec.getSelfExp())); + } else { + // the child is a class + childGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); + childGetter.addChild(new Field(fieldName, getImplStateType(child, langSpec))); + } + composer = new Term(DataConstraintModel.insert); + composer.addChild(composerSub); + composer.addChild(new Constant(fieldName, DataConstraintModel.typeString)); // key + composer.addChild(childGetter); // value + composer.setType(DataConstraintModel.typeMap); + composerSub = composer; + } + composer.setType(stateGetter.getReturnType()); + String[] sideEffects = new String[] {null}; + String returnValue = composer.toImplementation(sideEffects); + if (sideEffects[0] != null) { + stateGetter.addStatement(sideEffects[0] + langSpec.getReturnStatement(returnValue)); + } else { + stateGetter.addStatement(langSpec.getReturnStatement(returnValue)); + } + } + } + } + } + + protected void fillDescendantGetterMethod(MethodDeclaration descendantGetter, ResourceHierarchy descendant, + ResourceHierarchy child, ResourceHierarchy ancestor, TypeDeclaration ancestorComponent) { + // (#4) descendant getter method (the implementation must be kept consistent with #3) + Expression selector; + if (DataConstraintModel.typeList.isAncestorOf(ancestor.getResourceStateType())) { + selector = new Variable(langSpec.getFieldAccessor(fieldOfResourceState)); + } else if (DataConstraintModel.typeMap.isAncestorOf(ancestor.getResourceStateType())) { + selector = new Variable(langSpec.getFieldAccessor(fieldOfResourceState)); + } else { + String fieldName = child.getResourceName(); + selector = new Variable(langSpec.getFieldAccessor(fieldName)); + } + if (descendantGetter.getParameters() != null) { + for (VariableDeclaration param: descendantGetter.getParameters()) { + if (DataConstraintModel.typeInt.isAncestorOf(param.getType())) { + Term newSelector = new Term(DataConstraintModel.get); + newSelector.addChild(selector); + newSelector.addChild(new Variable(param.getName())); + selector = newSelector; + } else if (DataConstraintModel.typeString.isAncestorOf(param.getType())) { + Term newSelector = new Term(DataConstraintModel.lookup); + newSelector.addChild(selector); + newSelector.addChild(new Variable(param.getName())); + selector = newSelector; + } + } + } + if (descendantGetter != null && (descendantGetter.getBody() == null || descendantGetter.getBody().getStatements().size() == 0)) { + String[] sideEffects = new String[] {null}; + String returnValue = selector.toImplementation(sideEffects); + if (sideEffects[0] != null) descendantGetter.addStatement(sideEffects[0]); + descendantGetter.addStatement(langSpec.getReturnStatement(returnValue)); + } + } + + protected void declareAccessorInMainComponent(TypeDeclaration mainComponent, ResourceNode accessRes, MethodDeclaration stateGetter) { + List mainGetterParams = new ArrayList<>(); + int v = 1; + for (Expression param: accessRes.getPrimaryResourcePath().getPathParams()) { + if (param instanceof Variable) { + Variable var = (Variable) param; + mainGetterParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + } else if (param instanceof Term) { + Term var = (Term) param; + mainGetterParams.add(new VariableDeclaration(var.getType(), "v" + v)); + } + v++; + } + ResourcePath accessResPath = new ResourcePath(accessRes.getPrimaryResourcePath()); + for (int i = 0; i < mainGetterParams.size(); i++) { + Parameter pathParam = new Parameter(mainGetterParams.get(i).getName()); + accessResPath.replacePathParam(i, pathParam, null); + } + MethodDeclaration accessor = null; + if (mainGetterParams.size() == 0) { + accessor = langSpec.newMethodDeclaration(getterPrefix + getComponentName(accessRes.getResourceHierarchy(), langSpec), getImplStateType(accessRes.getResourceHierarchy(), langSpec)); + } else { + accessor = langSpec.newMethodDeclaration(getterPrefix + getComponentName(accessRes.getResourceHierarchy(), langSpec), false, getImplStateType(accessRes.getResourceHierarchy(), langSpec), mainGetterParams); + } + Block block = new Block(); + Expression getState = getPullAccessor(platformSpec).getDirectStateAccessorFor(accessResPath, null); + block.addStatement(langSpec.getReturnStatement(getState.toImplementation(new String[] {null}))); +// if (stateGetter.getParameters() == null || stateGetter.getParameters().size() == 0) { +// block.addStatement(langSpec.getReturnStatement(langSpec.getMethodInvocation(accessRes.getResourceName(), stateGetter.getName()))); +// } else { +// List resParams = new ArrayList<>(); +// for (VariableDeclaration var: stateGetter.getParameters()) { +// resParams.add(var.getName()); +// } +// block.addStatement(langSpec.getReturnStatement(langSpec.getMethodInvocation(accessRes.getResourceName(), stateGetter.getName(), resParams))); +// } + accessor.setBody(block); + mainComponent.addMethod(accessor); + } + + protected void declareFieldsToReferenceResources(DataTransferModel model, ResourceNode resourceNode, TypeDeclaration component, MethodDeclaration constructor, final List depends) { + Set refs = new HashSet<>(); + for (Channel ch : model.getChannels()) { + DataTransferChannel c = (DataTransferChannel) ch; + if (resourceNode.getOutSideResource(c) != null) { + for (ResourcePath res: c.getReferenceResources()) { + if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) { + refs.add(res); + String refResName = langSpec.toComponentName(res.getLeafResourceName()); + component.addField(langSpec.newFieldDeclaration(generationContext.getOrCreateComponentType(refResName), res.getLeafResourceName())); + constructor.addParameter(langSpec.newVariableDeclaration(generationContext.getOrCreateComponentType(refResName), res.getLeafResourceName())); + constructor.getBody().addStatement(langSpec.getFieldAccessor(res.getLeafResourceName()) + langSpec.getAssignment() + res.getLeafResourceName() + langSpec.getStatementDelimiter()); + } + } + } + } + } + + protected String getUpdateMethodName(ResourceHierarchy srcRes, ResourceHierarchy dstRes, DataTransferChannel ch) { + return generationContext.getOrPutUpdateMethodName(srcRes, ch, dstRes); + } + + protected MethodDeclaration getConstructor(TypeDeclaration component) { + for (MethodDeclaration m: component.getMethods()) { + if (m.isConstructor()) return m; + } + return null; + } + + protected static List getGetterMethods(TypeDeclaration component, String resourceName) { + List getters = new ArrayList<>(); + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().equals(getterPrefix + resourceName)) { + getters.add(m); + } + } + return getters; + } + + protected MethodDeclaration getUpdateMethod(Edge inEdge, TypeDeclaration component, + Map>> dataFlowInform, ILanguageSpecific langSpec) { + List passedResoueces = dataFlowInform.get(inEdge).get(PushPullValue.PUSH); + String methodName = updateMethodPrefix; + for (ResourceNode rn: passedResoueces) { + methodName += langSpec.toComponentName(rn.getResourceName()); + } + return getMethod(component, methodName); + } + + protected MethodDeclaration getInputMethod(ResourceNode resourceNode, DataTransferChannel ch, TypeDeclaration component) { + MethodDeclaration input = null; + for (ChannelMember out : ch.getOutputChannelMembers()) { + if (resourceNode.getInSideResources().contains(out.getResource())) { + Expression message = out.getStateTransition().getMessageExpression(); + if (message instanceof Term) { + input = getMethod(component, ((Term) message).getSymbol().getImplName()); + } else if (message instanceof Variable) { + // Declare an input method in this component. + input = getMethod(component, ((Variable) message).getName()); + } + break; + } + } + return input; + } + + + protected MethodDeclaration getMethod(TypeDeclaration component, String methodName, List params) { + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().equals(methodName)) { + if (m.getParameters() == null && (params == null || params.size() == 0)) return m; + if (m.getParameters() != null && params != null && m.getParameters().size() == params.size()) { + boolean matchParams = true; + for (int i = 0; i < m.getParameters().size(); i++) { + if (!m.getParameters().get(i).getType().equals(params.get(i).getType())) { + matchParams = false; + break; + } + } + if (matchParams) return m; + } + } + } + return null; + } + + protected MethodDeclaration getMethod(TypeDeclaration component, String methodName) { + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().equals(methodName)) return m; + } + return null; + } + + protected boolean isPut(ChannelMember cm) { + return cm.getStateTransition().isRightUnary(); + } + + protected boolean isDelete(ChannelMember cm) { + boolean isDelete = false; + Expression nextExp = cm.getStateTransition().getNextStateExpression(); + if (nextExp instanceof Term) { + Symbol rootSymbol = ((Term) nextExp).getSymbol(); + if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { + isDelete = true; + } else if (rootSymbol.equals(DataConstraintModel.cond)) { + Expression childExp = ((Term) nextExp).getChild(1); + if (childExp instanceof Term) { + rootSymbol = ((Term) childExp).getSymbol(); + if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { + isDelete = true; + } + } + childExp = ((Term) nextExp).getChild(2); + if (childExp instanceof Term) { + rootSymbol = ((Term) childExp).getSymbol(); + if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { + isDelete = true; + } + } + } + } + return isDelete; + } + + protected String getGetterResourcePathAndPathParams(ResourcePath resPath, List pathParams, + IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + int v = 1; + List params = new ArrayList<>(); + for (Expression pathParam: resPath.getPathParams()) { + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; + String paramName = var.getName(); + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + pathParams.add(param); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; + String paramName = "v" + v; + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + pathParams.add(param); + } + } + return resPath.getResourceHierarchy().toResourcePath(params); + } + + protected String getUpdateResourcePathAndPathParams(ResourcePath resPath, ArrayList pathParams, boolean isRestAPI, + IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + int v = 1; + List params = new ArrayList<>(); + for (Expression pathParam: resPath.getPathParams()) { + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; + String paramName = null; + if (isRestAPI) { + paramName = var.getName(); + } else { + paramName = "self" + (v > 1 ? v : ""); + } + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (isRestAPI) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + pathParams.add(param); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; + String paramName = null; + if (isRestAPI) { + paramName = "v" + v; + } else { + paramName = "self" + (v > 1 ? v : ""); + } + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (isRestAPI) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + pathParams.add(param); + } + v++; + } + return resPath.getResourceHierarchy().toResourcePath(params); + } + + protected String getInputMethodResourcePathAndPathParams(ResourcePath resPath, ArrayList rootInputParams, + IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + int v = 1; + List params = new ArrayList<>(); + if (resPath.getLastParam() != null) { + Expression pathParam = resPath.getLastParam(); + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; + String paramName = var.getName(); + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + rootInputParams.add(param); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; + String paramName = "v" + v; + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + rootInputParams.add(param); + } + v++; + } + if (resPath.getParent() != null) { + for (Expression pathParam: resPath.getParent().getPathParams()) { + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; + String paramName = var.getName(); + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + rootInputParams.add(param); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; + String paramName = "v" + v; + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + rootInputParams.add(param); + } + v++; + } + } + return resPath.getResourceHierarchy().toResourcePath(params); + } + + protected void generatePullDataTransfer(MethodDeclaration method, Block block, String fromResourceName, String fromResourcePath, Type fromResourceType, + boolean doesAddFirst, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + if (block == null) { + block = method.getBody(); + } + RestApiSpecific restApiSpec = (RestApiSpecific) platformSpec; + String varName = new String(fromResourceName); + Type respType = fromResourceType; + String respImplTypeName = fromResourceType.getImplementationTypeName(); + String responseConverter = ""; + if (DataConstraintModel.typeList.isAncestorOf(fromResourceType) && fromResourceType != DataConstraintModel.typeList) { + if (fromResourceType instanceof ListType) { + Type compType = ((ListType) fromResourceType).getElementType(); + if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { + varName += "_list"; + Type mapType = convertFromEntryToMapType(compType, langSpec); + respType = langSpec.newListType(mapType); + responseConverter += langSpec.newVariableDeclaration(fromResourceType, fromResourceName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(fromResourceType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + EnhancedForStatement forStatement = langSpec.getForStatementForCollection(langSpec.newVariableDeclaration(mapType, "i"), varName); + Block forBlock = new Block(); + forBlock.addStatement(langSpec.getMethodInvocation(fromResourceName, DataConstraintModel.append.getImplName(), List.of(getCodeForConversionFromMapToTuple(compType, "i", langSpec))) + langSpec.getStatementDelimiter()); + forStatement.setBody(forBlock); + responseConverter += forStatement; + restApiSpec.addJsonException(method); + } else if (compType != null && DataConstraintModel.typeMap.isAncestorOf(compType)) { + // To do. + } + } + } else if (DataConstraintModel.typeTuple.isAncestorOf(fromResourceType)) { + varName += "_json"; + respType = convertFromEntryToMapType(fromResourceType, langSpec); + responseConverter += langSpec.newVariableDeclaration(fromResourceType, fromResourceName) + langSpec.getAssignment() + getCodeForConversionFromMapToTuple(fromResourceType, varName, langSpec) + langSpec.getStatementDelimiter(); + respImplTypeName = "HashMap"; + } else if (DataConstraintModel.typePair.isAncestorOf(fromResourceType)) { + varName += "_json"; + respType = convertFromEntryToMapType(fromResourceType, langSpec); + responseConverter += langSpec.newVariableDeclaration(fromResourceType, fromResourceName) + langSpec.getAssignment() + getCodeForConversionFromMapToPair(fromResourceType, varName, langSpec) + langSpec.getStatementDelimiter(); + respImplTypeName = "HashMap"; + } else if (DataConstraintModel.typeMap.isAncestorOf(fromResourceType)) { + varName += "_json"; + respType = convertFromEntryToMapType(fromResourceType, langSpec); + responseConverter += langSpec.newVariableDeclaration(fromResourceType, fromResourceName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(fromResourceType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + responseConverter += getCodeForConversionFromMapToMap(fromResourceType, varName, fromResourceName, langSpec); + respImplTypeName = "HashMap"; + } + if (doesAddFirst) { + if (responseConverter.length() > 0) { + block.addFirstStatement(responseConverter); + } + block.addFirstStatement(langSpec.newVariableDeclaration(respType, varName) + langSpec.getAssignment() + restApiSpec.getHttpMethodCallWithResponseStatement(restApiSpec.getBaseURL(), fromResourcePath, getterPrefix, respImplTypeName)); + } else { + block.addStatement(langSpec.newVariableDeclaration(respType, varName) + langSpec.getAssignment() + restApiSpec.getHttpMethodCallWithResponseStatement(restApiSpec.getBaseURL(), fromResourcePath, getterPrefix, respImplTypeName)); + if (responseConverter.length() > 0) { + block.addStatement(responseConverter); + } + } + } + + protected Type convertFromEntryToMapType(Type type, ILanguageSpecific langSpec) { + Type mapType = null; + if (DataConstraintModel.typePair.isAncestorOf(type)) { + if (type instanceof PairType) { + Type compType = ((PairType) type).getComponentType(); + String wrapperType = DataConstraintModel.getWrapperType(compType); + if (wrapperType != null) { + mapType = langSpec.newMapType(DataConstraintModel.typeString, wrapperType); + } else { + mapType = langSpec.newMapType(DataConstraintModel.typeString, compType); + } + } + } else if (DataConstraintModel.typeMap.isAncestorOf(type)) { + if (type instanceof MapType) { + Type keyType = ((MapType) type).getKeyType(); + Type valType = ((MapType) type).getValueType(); + String wrapperType = DataConstraintModel.getWrapperType(valType); + if (wrapperType != null) { + mapType = langSpec.newMapType(DataConstraintModel.typeString, wrapperType); + } else { + mapType = langSpec.newMapType(DataConstraintModel.typeString, valType.getInterfaceTypeName()); + } + } + } else { + if (type instanceof TupleType) { + // Tuple (Map.Entry>> ==> Map>>) + List compTypes = ((TupleType) type).getComponentTypes(); + mapType = compTypes.get(compTypes.size() - 1); + for (int i = compTypes.size() - 2; i >= 0; i--) { + Type compType = compTypes.get(i); + mapType = langSpec.newMapType(DataConstraintModel.typeString, mapType); + } + } + } + return mapType; + } + + protected String getCodeForConversionFromMapToTuple(Type tupleType, String mapVar, ILanguageSpecific langSpec) { + String decoded = "$x"; + String elementBase = mapVar; + if (tupleType instanceof TupleType) { + List componentsTypes = ((TupleType) tupleType).getComponentTypes(); + if (componentsTypes != null) { + for (Type elmType: componentsTypes.subList(0, componentsTypes.size() - 1)) { + elementBase = langSpec.getFirstEntryFromMapExp(elementBase); // elementBase.entrySet().iterator().next() + if (elmType == DataConstraintModel.typeBoolean + || elmType == DataConstraintModel.typeInt + || elmType == DataConstraintModel.typeLong + || elmType == DataConstraintModel.typeFloat + || elmType == DataConstraintModel.typeDouble) { + String getKey = langSpec.getMethodInvocation(elementBase, DataConstraintModel.fst.getImplName()); // elementBase.getKey() + String elmVal = langSpec.getStringToValueExp(elmType.getImplementationTypeName(), getKey); // Integer.parseInt(elementBase.getKey()) + decoded = decoded.replace("$x", langSpec.getPairExp(elmVal, "$x")); // new AbstractMap.SimpleEntry<>(Integer.parseInt(elementBase.getKey()), $x) + } else if (elmType == DataConstraintModel.typeString) { + String getKey = langSpec.getMethodInvocation(elementBase, DataConstraintModel.fst.getImplName()); // elementBase.getKey() + decoded = decoded.replace("$x", langSpec.getPairExp(getKey, "$x")); // new AbstractMap.SimpleEntry<>(elementBase.getKey(), $x) + } else { + // To do. + } + elementBase = langSpec.getMethodInvocation(elementBase, DataConstraintModel.snd.getImplName()); // elementBase.getValue() + } + } + } + decoded = decoded.replace("$x", elementBase); + return decoded; + } + + protected String getCodeForConversionFromMapToPair(Type pairType, String mapVar, ILanguageSpecific langSpec) { + String decoded = "$x"; + decoded = decoded.replace("$x", "new Pair<>(" + mapVar + ".get(\"left\"), $x)"); + decoded = decoded.replace("$x", mapVar + ".get(\"right\")"); + return decoded; + } + + protected String getCodeForConversionFromMapToMap(Type mapType, String mapVal, String mapVar, ILanguageSpecific langSpec) { + String decoded = ""; + if (mapType instanceof MapType) { + Type keyType = ((MapType) mapType).getKeyType(); + if (keyType == DataConstraintModel.typeBoolean + || keyType == DataConstraintModel.typeInt + || keyType == DataConstraintModel.typeLong + || keyType == DataConstraintModel.typeFloat + || keyType == DataConstraintModel.typeDouble) { + String keyVal = langSpec.getStringToValueExp(keyType.getImplementationTypeName(), "k"); + String getInvocation = langSpec.getMethodInvocation(mapVal, DataConstraintModel.lookup.getImplName(), List.of(keyVal)); + EnhancedForStatement forStatement = langSpec.getForStatementForMap("k", mapVal); + Block forBlock = new Block(); + forBlock.addStatement(langSpec.getMethodInvocation(mapVar, DataConstraintModel.insert.getImplName(), List.of(keyVal, getInvocation)) + langSpec.getStatementDelimiter()); + forStatement.setBody(forBlock); + decoded += forStatement; + } else if (keyType == DataConstraintModel.typeString) { + decoded += mapVar + langSpec.getAssignment() + mapVal + langSpec.getStatementDelimiter(); + } + } + return decoded; + } + + protected void setFieldInitializer(FieldDeclaration field, Type type, Expression initialValue) { + String initializer = null; + if (initialValue != null) { + String sideEffects[] = new String[]{""}; + initializer = initialValue.toImplementation(sideEffects); + if (sideEffects[0] == null || sideEffects[0].length() == 0) { + field.setInitializer(initializer); + } else { + field.setInitializationBlock("{\n" + sideEffects[0] + field.getName() + " = " + initializer + ";\n" + "}\n"); + } + } else if (type != null) { + initializer = DataConstraintModel.getDefaultValue(type); + field.setInitializer(initializer); + } + } + + public IResourceStateAccessor getPushAccessor(IPlatformSpecific platformSpec) { + if (platformSpec.isMonolithic()) { + return new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes= target.getResource(); + ResourcePath fromRes= from.getResource(); + if (targetRes.equals(fromRes)) { + return new Field(fieldOfResourceState, + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + // use the cached value as the current state + return new Field(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + + @Override + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes= target.getResource(); + return new Parameter(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + + @Override + public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { + if (fromRes != null && targetRes.equals(fromRes)) { + return new Field(fieldOfResourceState, + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + // for reference channel member + return new Parameter(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + }; + } else { + return new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes = target.getResource(); + ResourcePath fromRes = from.getResource(); + if (targetRes.equals(fromRes)) { + return new Field(fieldOfResourceState, + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + // use the cached value as the current state + return new Field(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + + @Override + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes = target.getResource(); + return new Parameter(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + + @Override + public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { + if (fromRes != null && targetRes.equals(fromRes)) { + return new Field(fieldOfResourceState, + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + return null; + } + }; + } + } + + public IResourceStateAccessor getPullAccessor(IPlatformSpecific platformSpec) { + if (platformSpec.isMonolithic()) { + return new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes= target.getResource(); + if (from != null) { + ResourcePath fromRes= from.getResource(); + if (!target.isOutside()) { + return getDirectStateAccessorFor(targetRes, fromRes); + } + Term getter = null; + String targetComponentName = getComponentName(targetRes.getResourceHierarchy(), langSpec); + if (generatesComponent(targetRes.getResourceHierarchy())) { + getter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); + getter.addChild(new Field(langSpec.toVariableName(targetComponentName), targetRes.getResourceStateType())); + } else { + String parentName = langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy().getParent(), langSpec)); + Type parentType = targetRes.getResourceHierarchy().getParent().getResourceStateType(); + getter = new Term(new Symbol(getterPrefix + targetComponentName, 1, Symbol.Type.METHOD)); + getter.addChild(new Field(parentName, parentType)); + } + return getter; + } else { + return getDirectStateAccessorFor(targetRes, null); + } + } + + @Override + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes= target.getResource(); + if (from != null) { + ResourcePath fromRes= from.getResource(); + if (!target.isOutside()) { + return getDirectStateAccessorFor(targetRes, fromRes); + } + Term getter = null; + String targetComponentName = getComponentName(targetRes.getResourceHierarchy(), langSpec); + if (generatesComponent(targetRes.getResourceHierarchy())) { + getter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); + getter.addChild(new Field(langSpec.toVariableName(targetComponentName), targetRes.getResourceStateType())); + } else { + String parentName = langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy().getParent(), langSpec)); + Type parentType = targetRes.getResourceHierarchy().getParent().getResourceStateType(); + getter = new Term(new Symbol(getterPrefix + targetComponentName, 1, Symbol.Type.METHOD)); + getter.addChild(new Field(parentName, parentType)); + } + return getter; + } else { + return getDirectStateAccessorFor(targetRes, null); + } + } + + @Override + public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { + if (fromRes != null) { + if (targetRes.equals(fromRes)) { + return new Field(fieldOfResourceState, + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + // for reference channel member + if (fromRes.isAncestorOf(targetRes)) { + Stack pathStack = new Stack<>(); + ResourcePath curPath = targetRes; + do { + pathStack.push(curPath); + curPath = curPath.getParent(); + } while (!curPath.equals(fromRes)); + // iterate from the fromRes resource + return getRelativePath(targetRes, pathStack); + } + if (generatesComponent(targetRes.getResourceHierarchy())) { + Term getter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); + getter.addChild(new Field(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), targetRes.getResourceStateType())); + return getter; + } else { + return new Field(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), targetRes.getResourceStateType()); + } + } else { + // (#3) access from the outside of the hierarchy (must be kept consistent with #4) + Stack pathStack = new Stack<>(); + ResourcePath curPath = targetRes; + do { + pathStack.push(curPath); + curPath = curPath.getParent(); + } while (curPath != null); + // iterate from the root resource + return getRelativePath(targetRes, pathStack); + } + } + + private Expression getRelativePath(ResourcePath targetRes, Stack pathStack) { + ResourcePath curPath; + Term getter = null; + int arity = 2; + boolean doesChainInvocations = true; + while (!pathStack.empty()) { + curPath = pathStack.pop(); + String typeName = getComponentName(curPath.getResourceHierarchy(), langSpec); + if (getter == null && generatesComponent(curPath.getResourceHierarchy())) { + // root resource + String fieldName = langSpec.toVariableName(typeName); + getter = new Field(fieldName, generationContext.getOrCreateComponentType(typeName)); + } else { + if (generatesComponent(curPath.getResourceHierarchy())) { + if (arity == 2) { + Term newGetter = new Term(new Symbol(getterPrefix + typeName, -1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + Expression param = curPath.getLastParam(); + if (param != null) { + newGetter.addChild(param); + newGetter.getSymbol().setArity(2); + } + } + getter = newGetter; + } else { + // add the last path parameter. + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + Expression param = curPath.getLastParam(); + if (param != null) { + getter.getSymbol().setArity(arity); + getter.addChild(param); + } + } + } + arity = 2; + doesChainInvocations = true; + } else { + // to get a descendant resource directly. (e.g, .todos.{year}.{month}.{day}.{id} ==> .getTodos().getTodo(year, month, day, id)) + if (doesChainInvocations) { + Term newGetter = new Term(new Symbol(getterPrefix + typeName, -1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + getter = newGetter; + doesChainInvocations = false; + } + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + // may change the symbol name + getter.getSymbol().changeName(getterPrefix + typeName); + // add a path parameter. + Expression param = curPath.getLastParam(); + if (param != null) { + getter.getSymbol().setArity(arity); + getter.addChild(param); + arity++; + } + } + } + } + } + + if (generatesComponent(targetRes.getResourceHierarchy())) { + Term newGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + getter = newGetter; + } + return getter; + } + }; + } else { + return new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes = target.getResource(); + if (from != null && !target.isOutside()) { + ResourcePath fromRes = from.getResource(); + if (targetRes.getCommonPrefix(fromRes) != null) { + return getDirectStateAccessorFor(targetRes, fromRes); + } + } + // for reference channel member + return new Parameter(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + + @Override + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes = target.getResource(); + if (from != null && !target.isOutside()) { + ResourcePath fromRes = from.getResource(); + if (targetRes.getCommonPrefix(fromRes) != null) { + return getDirectStateAccessorFor(targetRes, fromRes); + } + } + return new Parameter(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + + @Override + public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { + if (fromRes != null && !fromRes.getResourceHierarchy().isAncestorOf(targetRes.getResourceHierarchy())) { + if (targetRes.equals(fromRes)) { + return new Field(fieldOfResourceState, + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + // for reference channel member + return new Parameter(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } else { + // (#3) access from an ancestor or outside of the hierarchy (must be kept consistent with #4) + Stack pathStack = new Stack<>(); + ResourcePath curPath = targetRes; + do { + if (fromRes != null && curPath.equals(fromRes)) break; + pathStack.push(curPath); + curPath = curPath.getParent(); + } while (curPath != null); + // iterate from the `from' resource + Term getter = null; + int arity = 2; + boolean doesChainInvocations = true; + while (!pathStack.empty()) { + curPath = pathStack.pop(); + String typeName = getComponentName(curPath.getResourceHierarchy(), langSpec); + if (getter == null && fromRes == null) { + // root resource + String fieldName = langSpec.toVariableName(typeName); + getter = new Field(fieldName, generationContext.getOrCreateComponentType(typeName)); + } else { + if (generatesComponent(curPath.getResourceHierarchy())) { + if (arity == 2) { + Term newGetter = new Term(new Symbol(getterPrefix + typeName, -1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + Expression param = curPath.getLastParam(); + if (param != null) { + newGetter.addChild(param); + newGetter.getSymbol().setArity(2); + } + } + getter = newGetter; + } else { + // add the last path parameter. + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + Expression param = curPath.getLastParam(); + if (param != null) { + getter.getSymbol().setArity(arity); + getter.addChild(param); + } + } + } + arity = 2; + doesChainInvocations = true; + } else { + // to get a descendant resource directly. (e.g, .todos.{year}.{month}.{day}.{id} ==> .getTodos().getTodo(year, month, day, id)) + if (doesChainInvocations) { + Term newGetter = new Term(new Symbol(getterPrefix + typeName, -1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + getter = newGetter; + doesChainInvocations = false; + } + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + // may change the symbol name + getter.getSymbol().changeName(getterPrefix + typeName); + // add a path parameter. + Expression param = curPath.getLastParam(); + if (param != null) { + getter.getSymbol().setArity(arity); + getter.addChild(param); + arity++; + } + } + } + } + } + + if (generatesComponent(targetRes.getResourceHierarchy())) { + Term newGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + getter = newGetter; + } + return getter; + } + } + }; + } + } + + public IResourceStateAccessor getRefAccessor(IPlatformSpecific platformSpec) { + if (platformSpec.isMonolithic()) { + return new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes= target.getResource(); + ResourcePath fromRes= from.getResource(); + if (targetRes.equals(fromRes)) { + return new Field(fieldOfResourceState, + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + // use the cached value as the current state + return new Parameter(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + + @Override + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes= target.getResource(); + return new Parameter(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + + @Override + public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { + if (fromRes != null && targetRes.equals(fromRes)) { + return new Field(fieldOfResourceState, + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + // for reference channel member + return new Parameter(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + }; + } else { + return new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes = target.getResource(); + ResourcePath fromRes = from.getResource(); + if (targetRes.equals(fromRes)) { + return new Field(fieldOfResourceState, + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + // for reference channel member + return new Parameter(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + + @Override + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes = target.getResource(); + return new Parameter(langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy(), langSpec)), + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + + @Override + public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { + if (fromRes != null && targetRes.equals(fromRes)) { + return new Field(fieldOfResourceState, + targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() + : DataConstraintModel.typeInt); + } + return null; + } + }; + } + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java new file mode 100644 index 0000000..0224022 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -0,0 +1,3334 @@ +package generators; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.Stack; + +import code.ast.*; +import models.Edge; +import models.Node; +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Field; +import models.algebra.InvalidMessage; +import models.algebra.Parameter; +import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.Position; +import models.algebra.Symbol; +import models.algebra.Term; +import models.algebra.Type; +import models.algebra.UnificationFailed; +import models.algebra.ValueUndefined; +import models.algebra.Variable; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonAccessor; +import models.dataConstraintModel.JsonTerm; +import models.dataConstraintModel.ListType; +import models.dataConstraintModel.ResourceHierarchy; +import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; +import models.dataFlowModel.DataFlowEdge; +import models.dataFlowModel.DataFlowGraph; +import models.dataFlowModel.DataTransferChannel; +import models.dataFlowModel.DataTransferModel; +import models.dataFlowModel.PushPullAttribute; +import models.dataFlowModel.PushPullValue; +import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; +import models.dataFlowModel.ResourceNode; +import models.dataFlowModel.ChannelNode; +import models.dataFlowModel.StoreAttribute; +import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; +import simulator.ResourceIdentifier; + +public class CodeGeneratorFromDataFlowGraph extends CodeGenerator { + protected Map> constructorParams; + + public CodeGeneratorFromDataFlowGraph(IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + super(platformSpec, langSpec); + } + + public void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, Collection components, ArrayList codes, Map> dependedRootComponentGraph) { + constructorParams = new HashMap<>(); + Map resourceConstructors = new HashMap<>(); + List> constructorStatements = new ArrayList<>(); + Map>> updateStatements = new HashMap<>(); + Map> descendantGetters = new HashMap<>(); + + TypeDeclaration mainComponent = null; + MethodDeclaration mainConstructor = null; + if (platformSpec.hasMain()) { + // Add the main component. + if (getMainTypeName() == null) { + setMainTypeName(langSpec.getMainComponentName()); + } + mainComponent = langSpec.newTypeDeclaration(getMainTypeName()); + mainConstructor = mainComponent.createConstructor(); + CompilationUnit mainCU = langSpec.newCompilationUnit(mainComponent); + codes.add(mainCU); + } + + // For each components (1st pass). + for (Node componentNode: components) { + ResourceNode resourceNode = (ResourceNode) componentNode; + ResourceHierarchy resourceHierarchy = resourceNode.getResourceHierarchy(); + TypeDeclaration component = null; + if (generatesComponent(resourceHierarchy)) { + // A component will be generated for this resource. + String resourceName = getComponentName(resourceHierarchy, langSpec); + Type resStateType = getImplStateType(resourceHierarchy, langSpec); + component = generationContext.getComponent(resourceHierarchy); + List depends = new ArrayList<>(); + if (component == null) { + // Add compilation unit for this component. + component = langSpec.newTypeDeclaration(resourceName); + if (!platformSpec.isMonolithic() && resourceHierarchy.getParent() == null) { + // For each root node, add component annotations. + ((RestApiSpecific) platformSpec).addComponentAnnotations(component, resourceNode.getResourceName()); + } + generationContext.putComponent(resourceHierarchy, component); + CompilationUnit cu = langSpec.newCompilationUnit(component); + if (!platformSpec.isMonolithic() && resourceHierarchy.getParent() == null) { + // For each root node, add platform specific imports. + ((RestApiSpecific) platformSpec).addPlatformSpecificImports(cu); + } + codes.add(cu); + + if (platformSpec.isMonolithic()) { + // For monolithic applications (components are tightly coupled and must be built together). + + // Declare the constructor. + MethodDeclaration constructor = declareConstructor(resourceNode, component, dependedRootComponentGraph, depends); + + if (platformSpec.hasMain() && resourceHierarchy.getParent() == null) { + // For each root resource + // Update the main component for this component. + updateMainComponent(mainComponent, mainConstructor, componentNode, constructor, depends); + } + + // Declare the fields to refer to reference resources. + declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends); + + if (constructor.getParameters() == null || constructor.getParameters().size() == 0) { + component.removeMethod(constructor); + } else { + resourceConstructors.put(resourceHierarchy, constructor); + } + } + + // Declare the field to store the state in this resource. + if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { + declareStateField(resourceNode, resourceName, component, resStateType); + } + + // Declare the getter method in this resource to obtain the state. + MethodDeclaration stateGetter = declareStateGetterMethod(resourceNode, component, resStateType); + + // Declare the accessor method in the main component to call the getter method. + if (platformSpec.hasMain()) { + declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter); + } + } + if (component != null) { + if (generationContext.getComponent(resourceHierarchy) == null) { + generationContext.putComponent(resourceHierarchy, component); + } + // (#1) Declare the getter methods in this resource to obtain the descendant resources. (complementary to #2) + declareDescendantGetterMethods(resourceNode, component, descendantGetters); + } + } + } + + // For each components (2nd pass). + Map priorMemberForInputChannel = new HashMap<>(); + Set generatedResources = new HashSet<>(); + for (Node componentNode: components) { + // Declare this resource. + ResourceNode resourceNode = (ResourceNode) componentNode; + ResourceHierarchy resourceHierarchy = resourceNode.getResourceHierarchy(); + Type resStateType = getImplStateType(resourceHierarchy, langSpec); + String resourceName = getComponentName(resourceHierarchy, langSpec); + TypeDeclaration component = null; + TypeDeclaration parentComponent = null; + TypeDeclaration rootComponent = null; + if (generatesComponent(resourceHierarchy)) { + component = generationContext.getComponent(resourceHierarchy); + } + if (resourceHierarchy.getParent() != null) { + parentComponent = generationContext.getComponent(resourceHierarchy.getParent()); + } + rootComponent = generationContext.getComponent(resourceHierarchy.getRoot()); + + // Declare cache fields and update methods in this resource, and an update accessor method in the type of root resource. + Map.Entry, Map>>> initStatementsAndUpdateUpdates + = declareCacheFieldsAndUpdateMethods(resourceNode, component, parentComponent, rootComponent); + if (component == null) { + // Constructor statements were not added to any component because no component had been generated. + for (String statement: initStatementsAndUpdateUpdates.getKey()) { + constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceHierarchy.getParent(), statement)); + } + } + for (Map.Entry>> entry: initStatementsAndUpdateUpdates.getValue().entrySet()) { + Map.Entry> updateInfo = entry.getValue(); + updateStatements.put(entry.getKey(), updateInfo); +// extractConstructorParameterFromUpdateExpression(updateInfo, constructorParams, langSpec); + } + + // Declare the fields to refer to other resources for push/pull transfer in the parent/this component, and the state field in the parent component. + declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(resourceNode, component, parentComponent); + + // (#2) Declare the getter method to obtain the resource state in an ancestor resource. (complementary to #1) + if (component == null) { + MethodDeclaration stateGetter = declareStateGetterMethodInAncestor(resourceNode, resStateType); + + if (stateGetter != null && platformSpec.hasMain()) { + // Declare the accessor method in the main component to call the getter method. + declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter); + } + } + + if (!platformSpec.isMonolithic() && !generatedResources.contains(resourceHierarchy)) { + // Declare the getter accessor in the root resource. + declareGetterAccessorInTheRootResource(resourceNode, rootComponent); + } + + // Declare input methods in this component and the main component. + if (!generatedResources.contains(resourceHierarchy)) { + Map.Entry, Map>>> initStatementsAndInputUpdates + = declareInputMethodsInThisAndMainComponents(resourceNode, component, parentComponent, mainComponent, rootComponent, model, priorMemberForInputChannel); + if (component == null) { + // Constructor statements were not added to any component because no component had been generated. + for (String statement: initStatementsAndInputUpdates.getKey()) { + constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceHierarchy.getParent(), statement)); + } + } + for (Map.Entry>> entry: initStatementsAndInputUpdates.getValue().entrySet()) { + Map.Entry> updateInfo = entry.getValue(); + updateStatements.put(entry.getKey(), updateInfo); +// extractConstructorParameterFromUpdateExpression(updateInfo, constructorParams, langSpec); + } + } + + generatedResources.add(resourceHierarchy); + } + + // Add constructor parameters to the ancestor components. + for (ResourceNode root: flowGraph.getRootResourceNodes()) { + addConstructorParameters(root.getResourceHierarchy(), resourceConstructors); + } + + // Add constructor statements. + for (Map.Entry entry: constructorStatements) { + resourceConstructors.get(entry.getKey()).addStatement(entry.getValue()); + } + + // Add update statements. + for (MethodDeclaration method: updateStatements.keySet()) { + Expression updateExp = updateStatements.get(method).getKey(); + ResourceHierarchy resource = updateStatements.get(method).getValue().getKey(); + ResourceHierarchy descendantRes = updateStatements.get(method).getValue().getValue(); + TypeDeclaration descendantComponent = generationContext.getComponent(descendantRes); + addUpdateStatementWithConstructorInvocationToMethod(method, updateExp, resource, descendantRes, descendantComponent); + } + } + + private void extractConstructorParameterFromUpdateExpression( + Map.Entry> updateInfo, + Map> constructorParams, ILanguageSpecific langSpec) { + Expression updateExp = updateInfo.getKey(); + ResourceHierarchy newResource = updateInfo.getValue().getValue(); + if (updateExp instanceof Term) { + Map subTerms = ((Term) updateExp).getSubTerms(Term.class); + for (Term term: subTerms.values()) { + if (term.getType() != null) { + if (term.getType().equals(newResource.getResourceStateType())) { + if (term instanceof JsonTerm) { + JsonTerm jsonTerm = (JsonTerm) term; + for (String key: jsonTerm.keySet()) { + Map params = constructorParams.getOrDefault(newResource, new HashMap<>()); + Expression member = jsonTerm.get(key); + if (member != null && member instanceof Term) { + if (!params.containsKey(key) && ((Term) member).getType() != null) { + params.put(key, new VariableDeclaration(((Term) member).getType(), key)); + } + } else if (member != null && member instanceof Variable) { + if (!params.containsKey(key) && ((Variable) member).getType() != null) { + params.put(key, langSpec.newVariableDeclaration(((Variable) member).getType(), key)); + } + } + constructorParams.put(newResource, params); + } + } + } + } + } + } + } + + private List addConstructorParameters(ResourceHierarchy resource, Map resourceConstructors) { + List params = new ArrayList<>(); + for (ResourceHierarchy child: resource.getChildren()) { + params.addAll(addConstructorParameters(child, resourceConstructors)); + } + if (constructorParams.get(resource) != null) { + for (VariableDeclaration param: constructorParams.get(resource).values()) { + params.add(param); + } + } + if (params.size() > 0) { + MethodDeclaration constructor = resourceConstructors.get(resource); + if (constructor == null) { + if (generationContext.getComponent(resource) != null) { + String resourceName = getComponentName(resource, langSpec); + constructor = langSpec.newMethodDeclaration(resourceName, true, null, null); + Block body = new Block(); + constructor.setBody(body); + generationContext.getComponent(resource).addMethod(constructor); + resourceConstructors.put(resource, constructor); + } + } + if (constructor != null) { + for (VariableDeclaration param: params) { + boolean existsParam = false; + if (constructor.getParameters() != null) { + for (VariableDeclaration constParam: constructor.getParameters()) { + if (constParam.getName().equals(param.getName())) { + existsParam = true; + break; + } + } + } + if (!existsParam) { + constructor.addParameter(param); + constructor.getBody().addStatement(langSpec.getFieldAccessor(langSpec.toVariableName(param.getName())) + langSpec.getAssignment() + langSpec.toVariableName(param.getName()) + langSpec.getStatementDelimiter()); + boolean existsField = false; + for (FieldDeclaration field: generationContext.getComponent(resource).getFields()) { + if (field.getName().equals(param.getName())) { + existsField = true; + } + } + if (!existsField) { + generationContext.getComponent(resource).addField(langSpec.newFieldDeclaration(param.getType(), param.getName())); + } + } + } + } + } + if (resource.getNumParameters() > 0) params.clear(); + return params; + } + + private void addUpdateStatementWithConstructorInvocationToMethod(MethodDeclaration method, Expression exp, ResourceHierarchy resource, ResourceHierarchy descendantRes, TypeDeclaration descendantComponent) { + // Replace each json term in exp with the corresponding constructor invocation. + Type replacedJsonType = descendantRes.getResourceStateType(); + String replacingClassName = getComponentName(descendantRes, langSpec); + Type descendantType = generationContext.getOrCreateComponentType(replacingClassName); + Map subTerms = ((Term) exp).getSubTerms(Term.class); + Iterator> termEntItr = subTerms.entrySet().iterator(); + while (termEntItr.hasNext()) { + // For each sub-term of exp + Entry termEnt = termEntItr.next(); + Term jsonTerm = termEnt.getValue(); + if (jsonTerm.getType() != null) { + if (jsonTerm.getType().equals(replacedJsonType)) { + // a json sub-term to replace + if (jsonTerm instanceof JsonTerm || jsonTerm.getSymbol().equals(DataConstraintModel.addMember)) { + MethodDeclaration childConstructor = getConstructor(descendantComponent); + List params = new ArrayList<>(); + if (childConstructor != null) { + for (VariableDeclaration var: childConstructor.getParameters()) { + // Extract the argument of each constructor parameter from jsonTerm. + JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); + jsonMember.addChild(jsonTerm); + jsonMember.addChild(new Constant(var.getName(), DataConstraintModel.typeString)); + Expression param = jsonMember.reduce(); // Reduce {"name": "foo", age: 25}.name => "foo" + if (param != null) { + if (param instanceof Term) { + if (((Term) param).getType() == null) { + ((Term) param).setType(var.getType()); + } + } else if (param instanceof Variable) { + if (((Variable) param).getType() == null) { + ((Variable) param).setType(var.getType()); + } + } + params.add(param.toImplementation(null)); + } else { + params.add(var.getName()); + } + } + } + ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(langSpec.getConstructorInvocation(replacingClassName, params))); // dummy algebraic expression + subTerms = ((Term) exp).getSubTerms(Term.class); + termEntItr = subTerms.entrySet().iterator(); + } else { + jsonTerm.setType(descendantType); + } + } else { + // not any sub-term to replace, but its type should be rewritten + Type oldType = jsonTerm.getType(); + Type.ITypeImpl newImplementationType = oldType.getImplementationType(); + Type.ITypeImpl newInterfaceType = oldType.getInterfaceType(); + if (newImplementationType instanceof ParameterizedType) { + ((code.ast.ParameterizedType) newImplementationType).replaceSubTypes((code.ast.Type) replacedJsonType.getImplementationType(), (code.ast.Type) descendantType.getImplementationType()); + } + if (newInterfaceType instanceof ParameterizedType) { + ((code.ast.ParameterizedType) newInterfaceType).replaceSubTypes((code.ast.Type) replacedJsonType.getInterfaceType(), (code.ast.Type) descendantType.getInterfaceType()); + } + Type newType = new Type(oldType.getTypeName(), newImplementationType, newInterfaceType); + for (Type parent: oldType.getParentTypes()) { + newType.addParentType(parent); + } + jsonTerm.setType(newType); + } + } + } + // Replace the type of the state field. + Type fieldType = getImplStateType(resource, langSpec); + if (exp instanceof Term) { + ((Term) exp).setType(fieldType); + for (Map.Entry varEnt: ((Term) exp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals(fieldOfResourceState)) { + varEnt.getValue().setType(fieldType); + } + } + } else if (exp instanceof Variable) { + ((Variable) exp).setType(fieldType); + } + String[] sideEffects = new String[] {""}; + String newState = exp.toImplementation(sideEffects); + String updateStatement; + if (exp instanceof Term && ((Term) exp).getSymbol().isImplWithSideEffect()) { + updateStatement = sideEffects[0]; + if (updateStatement.endsWith("\n")) { + updateStatement = updateStatement.substring(0, updateStatement.length() - 1); + } + } else { + updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); + } + method.addStatement(updateStatement); + } + + private MethodDeclaration declareConstructor(ResourceNode resourceNode, TypeDeclaration component, Map> dependedRootComponentGraph, List depends) { + // Declare a constructor in each component. + String resourceName = getComponentName(resourceNode.getResourceHierarchy(), langSpec); + MethodDeclaration constructor = langSpec.newMethodDeclaration(resourceName, true, null, null); + Block block = new Block(); + constructor.setBody(block); + component.addMethod(constructor); + + for (Edge resToCh: resourceNode.getOutEdges()) { + DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); + // Check if the input resource is outside of the channel scope. + boolean outsideInputResource = false; + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (resourceNode.getOutSideResources().contains(cm.getResource()) && cm.isOutside()) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + for (Edge chToRes: resToCh.getDestination().getOutEdges()) { + if (chToRes.getDestination() instanceof ResourceNode) { + ResourceHierarchy dstRes = ((ResourceNode) chToRes.getDestination()).getResourceHierarchy(); + // Check if the output resource is outside of the channel scope. + boolean outsideOutputResource = false; + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (((ResourceNode) chToRes.getDestination()).getInSideResources().contains(cm.getResource()) && cm.isOutside()) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } + if ((((PushPullAttribute) ((DataFlowEdge) resToCh).getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { + // for PUSH transfer +// ResourceHierarchy dstRes = addReference(component, constructor, ((ResourceNode) chToRes.getDestination()).getOutSideResource().getResourceHierarchy(), langSpec); +// if (outsideOutputResource) { +// if (dstRes != null && dstRes.getParent() != null) { +// // Reference to root resource. +// addReference(component, constructor, dstRes.getRoot(), langSpec); +// } +// } + if (!generatesComponent(dstRes)) { + dstRes = dstRes.getParent(); + } + if (!depends.contains(dstRes)) depends.add(dstRes); + } + } + } + } + for (Edge chToRes: resourceNode.getInEdges()) { + for (Edge resToCh: chToRes.getSource().getInEdges()) { + ResourceHierarchy srcRes = ((ResourceNode) resToCh.getSource()).getResourceHierarchy(); + DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); + // Check if the input resource is outside of the channel scope. + boolean outsideInputResource = false; + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (((ResourceNode) resToCh.getSource()).getOutSideResources().contains(cm.getResource()) && cm.isOutside()) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + // Check if the output resource is outside of the channel scope. + boolean outsideOutputResource = false; + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (resourceNode.getInSideResources().contains(cm.getResource()) && cm.isOutside()) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } + if ((((PushPullAttribute) ((DataFlowEdge) resToCh).getAttribute()).getSelectedOption() != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { + // for PULL transfer +// srcRes = addReference(component, constructor, ((ResourceNode) resToCh.getSource()).getOutSideResource().getResourceHierarchy(), langSpec); +// if (outsideInputResource) { +// if (srcRes != null & srcRes.getParent() != null) { +// // Reference to root resource. +// addReference(component, constructor, srcRes.getRoot(), langSpec); +// } +// } + if (!generatesComponent(srcRes)) { + srcRes = srcRes.getParent(); + } + if (!depends.contains(srcRes)) depends.add(srcRes); + } + } + } + // Declare a field to refer to outside resources. + if (resourceNode.getParent() == null) { + for (ResourceHierarchy dependedRes: dependedRootComponentGraph.keySet()) { + for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(dependedRes)) { + if (resourceNode.getResourceHierarchy().equals(dependingRes)) { + // Declare a field to refer to outside resources. + depends.add(dependedRes); + addReference(component, constructor, dependedRes, langSpec); + } + } + } + } + return constructor; + } + + private void declareStateField(ResourceNode resourceNode, String resourceName, TypeDeclaration component, Type resStateType) { + Set children = resourceNode.getResourceHierarchy().getChildren(); + if (children == null || children.size() == 0) { + // leaf resource. + FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState); + setFieldInitializer(stateField, resStateType, resourceNode.getResourceHierarchy().getInitialValue()); + component.addField(stateField); + // Add a parameter to initialize the state field to the constructor. +// Map nameToParam = constructorParams.get(resourceNode.getResourceHierarchy()); +// if (nameToParam == null) { +// nameToParam = new HashMap<>(); +// constructorParams.put(resourceNode.getResourceHierarchy(), nameToParam); +// } +// String varName = fieldOfResourceState; +// if (nameToParam.get(varName) == null) { +// nameToParam.put(varName, langSpec.newVariableDeclaration(resStateType, varName)); +// } + } else { + ResourceHierarchy child = children.iterator().next(); + if (children.size() == 1 && child.getNumParameters() > 0) { + // map or list. + FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState); + setFieldInitializer(stateField, resStateType, resourceNode.getResourceHierarchy().getInitialValue()); + component.addField(stateField); + } else { + // class + for (ResourceHierarchy c: children) { + String childTypeName = getComponentName(c, langSpec); + Type childType = null; + if (generatesComponent(c)) { + // The child has a component. + childType = generationContext.getOrCreateComponentType(childTypeName); + String fieldName = c.getResourceName(); + FieldDeclaration stateField = langSpec.newFieldDeclaration(childType, fieldName, langSpec.getConstructorInvocation(childTypeName, new ArrayList<>())); + component.addField(stateField); + } + } + } + } + } + + private void declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent) { + // Declare reference fields for push data transfer. + boolean noPullTransfer = true; + for (Edge resToCh : resourceNode.getOutEdges()) { + DataFlowEdge re = (DataFlowEdge) resToCh; + ChannelNode directDstChNode = (ChannelNode) re.getDestination(); + DataTransferChannel directDstCh = directDstChNode.getChannel(); + // Check if the source resource is outside of the channel scope. + boolean outsideInputResource = false; + for (ChannelMember cm: directDstCh.getInputChannelMembers()) { + if (cm.getResource().equals(resourceNode.getOutSideResource(directDstCh)) && cm.isOutside()) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + // Should take into account the channel hierarchy. + Set ancestorDstChannels = directDstChNode.getAncestors(); + Set descendantDstChannels = directDstChNode.getDescendants(); + Set outEdges = new HashSet<>(); + outEdges.addAll(directDstChNode.getOutEdges()); + for (ChannelNode ancestorDst: ancestorDstChannels) { + outEdges.addAll(ancestorDst.getOutEdges()); + } + for (ChannelNode descendantDst: descendantDstChannels) { + outEdges.addAll(descendantDst.getOutEdges()); + } + for (Edge chToRes: outEdges) { + if (chToRes.getDestination() instanceof ResourceNode) { + ResourceHierarchy dstRes = ((ResourceNode) chToRes.getDestination()).getResourceHierarchy(); + ChannelNode chNode = (ChannelNode) chToRes.getSource(); + DataTransferChannel ch = chNode.getChannel(); + // Check if the destination resource is outside of the channel scope. + boolean outsideOutputResource = false; + ChannelMember out = null; + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (((ResourceNode) chToRes.getDestination()).getInSideResources().contains(cm.getResource())) { + out = cm; + if (cm.isOutside()) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } + } + ResourcePath dstResPath = out.getResource(); + // Also take into account the channel hierarchy to determine push/pull transfer. + if (descendantDstChannels.contains(chNode)) { + outsideOutputResource = true; // Regarded as (broadcasting) push transfer. + } + if (ancestorDstChannels.contains(chNode)) { + outsideInputResource = true; // Regarded as (collecting) pull transfer. + } + if ((((PushPullAttribute) re.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { + // Declare a field in the parent or this component to refer to the destination resource of push transfer. + if (!generatesComponent(dstRes)) { + dstRes = dstRes.getParent(); + } + String dstResName = getComponentName(dstRes, langSpec); + FieldDeclaration refFieldForPush = langSpec.newFieldDeclaration(generationContext.getOrCreateComponentType(dstResName), langSpec.toVariableName(dstResName)); + VariableDeclaration refVarForPush = langSpec.newVariableDeclaration(generationContext.getOrCreateComponentType(dstResName), langSpec.toVariableName(dstResName)); + if (!platformSpec.isMonolithic() + && (outsideOutputResource || (resourceNode.getOutSideResource(ch).getCommonPrefix(dstResPath) == null && platformSpec.isDifferentTreesAsDifferentServices()))) { + // Inter-service (for REST API) + if (parentComponent != null && + !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); + } + } else { + // Monolithic or Inner-service + if (component != null) { + // A component is created for this resource. + if (resourceNode.getResourceHierarchy() != dstRes) { + component.addField(refFieldForPush); + if (!outsideOutputResource) { + Map nameToParam = constructorParams.get(resourceNode.getResourceHierarchy()); + if (nameToParam == null) { + nameToParam = new HashMap<>(); + constructorParams.put(resourceNode.getResourceHierarchy(), nameToParam); + } + if (nameToParam.get(dstResName) == null) { + nameToParam.put(dstResName, refVarForPush); + } + } + } + } else { + // No component is created for this resource. + if (resourceNode.getParent().getResourceHierarchy() != dstRes && parentComponent != null) { + parentComponent.addField(refFieldForPush); + if (!outsideOutputResource) { + Map nameToParam = constructorParams.get(resourceNode.getParent().getResourceHierarchy()); + if (nameToParam == null) { + nameToParam = new HashMap<>(); + constructorParams.put(resourceNode.getParent().getResourceHierarchy(), nameToParam); + } + if (nameToParam.get(dstResName) == null) { + nameToParam.put(dstResName, refVarForPush); + } + } + } + } + if (outsideOutputResource) { + // When the reference to the destination resource can vary. + if (dstRes.getParent() != null) { + // Reference to its root resource. + String dstRootResName = getComponentName(dstRes.getRoot(), langSpec); + Type dstRootResType = generationContext.getOrCreateComponentType(dstRootResName); + dstRootResName = langSpec.toVariableName(dstRootResName); + FieldDeclaration refRootFieldForPush = langSpec.newFieldDeclaration(dstRootResType, dstRootResName); + VariableDeclaration refRootVarForPush = langSpec.newVariableDeclaration(dstRootResType, dstRootResName); + if (component != null) { + // A component is created for this resource. + boolean existsField = false; + for (FieldDeclaration field: component.getFields()) { + if (dstRootResName.equals(field.getName())) { + existsField = true; + break; + } + } + if (!existsField) { + component.addField(refRootFieldForPush); + Map nameToParam = constructorParams.get(resourceNode.getResourceHierarchy()); + if (nameToParam == null) { + nameToParam = new HashMap<>(); + constructorParams.put(resourceNode.getResourceHierarchy(), nameToParam); + } + if (nameToParam.get(dstRootResName) == null) { + nameToParam.put(dstRootResName, refRootVarForPush); + } + } + } else { + // No component is created for this resource. + boolean existsField = false; + for (FieldDeclaration field: parentComponent.getFields()) { + if (dstRootResName.equals(field.getName())) { + existsField = true; + break; + } + } + if (!existsField) { + parentComponent.addField(refRootFieldForPush); + Map nameToParam = constructorParams.get(resourceNode.getParent().getResourceHierarchy()); + if (nameToParam == null) { + nameToParam = new HashMap<>(); + constructorParams.put(resourceNode.getParent().getResourceHierarchy(), nameToParam); + } + if (nameToParam.get(dstRootResName) == null) { + nameToParam.put(dstRootResName, refRootVarForPush); + } + } + } + } + } + } + } + } + } + } + // Declare reference fields for pull data transfer. + for (Edge chToRes : resourceNode.getInEdges()) { + ChannelNode directSrcChNode = (ChannelNode) chToRes.getSource(); + DataTransferChannel directSrcCh = directSrcChNode.getChannel(); + // Should take into account the channel hierarchy. + Set ancestorSrcChannels = directSrcChNode.getAncestors(); + Set descendantSrcChannels = directSrcChNode.getDescendants(); + Set inEdges = new HashSet<>(); + inEdges.addAll(directSrcChNode.getInEdges()); + for (ChannelNode ancestorSrc: ancestorSrcChannels) { + inEdges.addAll(ancestorSrc.getInEdges()); + } + for (ChannelNode descendantSrc: descendantSrcChannels) { + inEdges.addAll(descendantSrc.getInEdges()); + } + for (Edge resToCh: inEdges) { + DataFlowEdge re = (DataFlowEdge) resToCh; + ChannelNode chNode = (ChannelNode) re.getDestination(); + DataTransferChannel ch = chNode.getChannel(); + ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(ch); + // Check if the source resource is outside of the channel scope. + boolean outsideInputResource = false; + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().equals(srcRes) && cm.isOutside()) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + // Check if the output resource is outside of the channel scope. + boolean outsideOutputResource = false; + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (resourceNode.getInSideResources().contains(cm.getResource()) && cm.isOutside()) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } + // Also take into account the channel hierarchy to determine push/pull transfer. + if (descendantSrcChannels.contains(chNode)) { + outsideInputResource = true; // Regarded as (collecting) pull transfer. + } + if (ancestorSrcChannels.contains(chNode)) { + outsideOutputResource = true; // Regarded as (broadcasting) push transfer. + } + if ((((PushPullAttribute) re.getAttribute()).getSelectedOption() != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { + noPullTransfer = false; + // Declare a field in the parent/this component to refer to the source resource of pull transfer. + if (!generatesComponent(srcRes.getResourceHierarchy())) { + srcRes = srcRes.getParent(); + } + String srcResName = getComponentName(srcRes.getResourceHierarchy(), langSpec); + FieldDeclaration refFieldForPull = langSpec.newFieldDeclaration(generationContext.getOrCreateComponentType(srcResName), langSpec.toVariableName(srcResName)); + VariableDeclaration refVarForPull = langSpec.newVariableDeclaration(generationContext.getOrCreateComponentType(srcResName), langSpec.toVariableName(srcResName)); + if (!platformSpec.isMonolithic() + && (outsideInputResource || (resourceNode.getInSideResource(ch).getCommonPrefix(srcRes) == null && platformSpec.isDifferentTreesAsDifferentServices()))) { + // Inter-service (for REST API) + if (parentComponent != null + && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); + } + } else { + // Monolithic or Inner-service (for REST API) + // Declare a field to directly refer to the source resource of pull transfer. + if (component != null) { + // A component is created for this resource. + if (resourceNode.getResourceHierarchy() != srcRes.getResourceHierarchy()) { + component.addField(refFieldForPull); + if (!outsideInputResource) { + Map nameToParam = constructorParams.get(resourceNode.getResourceHierarchy()); + if (nameToParam == null) { + nameToParam = new HashMap<>(); + constructorParams.put(resourceNode.getResourceHierarchy(), nameToParam); + } + if (nameToParam.get(srcResName) == null) { + nameToParam.put(srcResName, refVarForPull); + } + } + } + } else { + // No component is created for this resource. + if (resourceNode.getParent().getResourceHierarchy() != srcRes.getResourceHierarchy() && parentComponent != null) { + parentComponent.addField(refFieldForPull); + if (!outsideInputResource) { + Map nameToParam = constructorParams.get(resourceNode.getParent().getResourceHierarchy()); + if (nameToParam == null) { + nameToParam = new HashMap<>(); + constructorParams.put(resourceNode.getParent().getResourceHierarchy(), nameToParam); + } + if (nameToParam.get(srcResName) == null) { + nameToParam.put(srcResName, refVarForPull); + } + } + } + } + if (outsideInputResource) { + // When the reference to the source resource can vary. + if (srcRes.getParent() != null) { + // Reference to its root resource. + String srcRootResName = getComponentName(srcRes.getRoot().getResourceHierarchy(), langSpec); + Type srcRootResType = generationContext.getOrCreateComponentType(srcRootResName); + srcRootResName = langSpec.toVariableName(srcRootResName); + FieldDeclaration refRootFieldForPull = langSpec.newFieldDeclaration(srcRootResType, srcRootResName); + VariableDeclaration refRootVarForPull = langSpec.newVariableDeclaration(srcRootResType, srcRootResName); + if (component != null) { + // A component is created for this resource. + boolean existsField = false; + for (FieldDeclaration field: component.getFields()) { + if (srcRootResName.equals(field.getName())) { + existsField = true; + break; + } + } + if (!existsField) { + component.addField(refRootFieldForPull); + Map nameToParam = constructorParams.get(resourceNode.getResourceHierarchy()); + if (nameToParam == null) { + nameToParam = new HashMap<>(); + constructorParams.put(resourceNode.getResourceHierarchy(), nameToParam); + } + if (nameToParam.get(srcRootResName) == null) { + nameToParam.put(srcRootResName, refRootVarForPull); + } + } + } else { + // No component is created for this resource. + boolean existsField = false; + for (FieldDeclaration field: parentComponent.getFields()) { + if (srcRootResName.equals(field.getName())) { + existsField = true; + break; + } + } + if (!existsField) { + parentComponent.addField(refRootFieldForPull); + Map nameToParam = constructorParams.get(resourceNode.getParent().getResourceHierarchy()); + if (nameToParam == null) { + nameToParam = new HashMap<>(); + constructorParams.put(resourceNode.getParent().getResourceHierarchy(), nameToParam); + } + if (nameToParam.get(srcRootResName) == null) { + nameToParam.put(srcRootResName, refRootVarForPull); + } + } + } + } + } + } + } + } + } + // Declare the state field in the parent component. + if (component == null) { + ResourceHierarchy res = resourceNode.getResourceHierarchy(); + if (((StoreAttribute) resourceNode.getAttribute()).isStored() && noPullTransfer && res.getNumParameters() == 0) { + String resName = langSpec.toVariableName(getComponentName(res, langSpec)); + boolean existsField = false; + for (FieldDeclaration field: parentComponent.getFields()) { + if (resName.equals(field.getName())) { + existsField = true; + break; + } + } + if (!existsField) { + FieldDeclaration stateField = langSpec.newFieldDeclaration(res.getResourceStateType(), resName); + parentComponent.addField(stateField); + Map nameToParam = constructorParams.get(resourceNode.getParent().getResourceHierarchy()); + if (nameToParam == null) { + nameToParam = new HashMap<>(); + constructorParams.put(resourceNode.getParent().getResourceHierarchy(), nameToParam); + } + if (nameToParam.get(resName) == null) { + nameToParam.put(resName, langSpec.newVariableDeclaration(res.getResourceStateType(), resName)); + } + } + } + } + } + + + private MethodDeclaration declareStateGetterMethod(ResourceNode resourceNode, TypeDeclaration component, Type resStateType) { + // Declare the getter method of the resource state. + MethodDeclaration stateGetter = langSpec.newMethodDeclaration(getterOfResourceState, resStateType); + if (!platformSpec.isMonolithic() && resourceNode.getResourceHierarchy().getParent() == null) { + // Since this getter is also an accessor. + ((RestApiSpecific) platformSpec).addGetAnnotations(stateGetter); + } + component.addMethod(stateGetter); + + boolean hasDescendantIn = hasDescendantInput(resourceNode); + if (((StoreAttribute) resourceNode.getAttribute()).isStored() && !hasDescendantIn) { + fillStateGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resStateType); + } else { + // invocations to other getter methods when at least one incoming data-flow edges is PULL-style. + if (addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode)) { + // Declare a client field to connect to the destination resource of push transfer. + if (!((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); + } + } + } + + return stateGetter; + } + + private MethodDeclaration declareStateGetterMethodInAncestor(ResourceNode resourceNode, Type resStateType) { + // Search an ancestor in which the getter method is declared. + ResourceNode ancestorNode = resourceNode; + ResourceNode childNode = null; + Stack ancestors = new Stack<>(); + do { + ancestors.push(ancestorNode); + childNode = ancestorNode; + ancestorNode = ancestorNode.getParent(); + } while (!generatesComponent(ancestorNode.getResourceHierarchy())); + TypeDeclaration ancestorComponent = generationContext.getComponent(ancestorNode.getResourceHierarchy()); + List getterParams = new ArrayList<>(); + int v = 1; + while (ancestors.size() > 0) { + ResourceNode curAncestor = ancestors.pop(); + Expression param = curAncestor.getPrimaryResourcePath().getLastParam(); + if (param instanceof Variable) { + Variable var = (Variable) param; + getterParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + } else if (param instanceof Term) { + Term var = (Term) param; + getterParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); + } + v++; + } + // Check duplication. + String getterName = getterPrefix + getComponentName(resourceNode.getResourceHierarchy(), langSpec); + for (MethodDeclaration method: ancestorComponent.getMethods()) { + if (method.getName().equals(getterName) + && (method.getParameters() == null ? 0 : method.getParameters().size()) == getterParams.size()) return null; + } + + // Declare the getter method of the resource state. + MethodDeclaration stateGetter = null; + if (getterParams.size() == 0) { + stateGetter = langSpec.newMethodDeclaration(getterName, resStateType); + } else { + stateGetter = langSpec.newMethodDeclaration(getterName, false, resStateType, getterParams); + } + if (ancestorComponent != null) { + ancestorComponent.addMethod(stateGetter); + } + + boolean hasDescendantIn = hasDescendantInput(resourceNode); + if (((StoreAttribute) resourceNode.getAttribute()).isStored() && !hasDescendantIn) { + fillDescendantGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), childNode.getResourceHierarchy(), ancestorNode.getResourceHierarchy(), ancestorComponent); + } else { + if (addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode)) { + // Declare a client field to connect to the destination resource of push transfer. + if (ancestorComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(ancestorComponent)) { + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(ancestorComponent); + } + } + } + + return stateGetter; + } + + private boolean hasDescendantInput(ResourceNode resourceNode) { + boolean hasDescendantIn = false; + outer: for (Edge chToRes: resourceNode.getInEdges()) { + ChannelNode chNode = (ChannelNode) chToRes.getSource(); + Set descendantChannels = chNode.getDescendants(); + for (ChannelNode descendantCh: descendantChannels) { + if (descendantCh.getIndegree() > 0) { + hasDescendantIn = true; + break outer; + } + } + } + return hasDescendantIn; + } + + private boolean addOtherGetterInvocationsToStateGatter(MethodDeclaration stateGetter, ResourceNode resourceNode) { + boolean bDeclareClientField = false; + try { + // Data transfer on the same channel hierarchy. + boolean isContainedPush = false; + DataTransferChannel ch = null; + DataTransferChannel ch2 = null; + HashMap inputResourceToStateAccessor = new HashMap<>(); + for (Edge chToRes: resourceNode.getInEdges()) { + ch2 = ((ChannelNode) chToRes.getSource()).getChannel(); + for (Edge resToCh: chToRes.getSource().getInEdges()) { + DataFlowEdge dIn = (DataFlowEdge) resToCh; + ChannelMember in = null; + for (ChannelMember cm: ch2.getInputChannelMembers()) { + if (((ResourceNode) dIn.getSource()).getOutSideResources().contains(cm.getResource())) { + in = cm; + break; + } + } + if (((PushPullAttribute) dIn.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { + // PUSH transfer + isContainedPush = true; + inputResourceToStateAccessor.put(in, getPushAccessor(platformSpec)); + } else { + // PULL transfer + inputResourceToStateAccessor.put(in, getPullAccessor(platformSpec)); + ch = ((ChannelNode) resToCh.getDestination()).getChannel(); // pull containing input side channel is at most one. + if (!platformSpec.isMonolithic() + && !in.isOutside() + && in.getResource().getCommonPrefix(resourceNode.getInSideResource(ch2)) == null + && platformSpec.isDifferentTreesAsDifferentServices()) { + // for REST API + ResourcePath srcResPath = in.getResource(); + String srcResourceName = langSpec.toVariableName(getComponentName(srcResPath.getResourceHierarchy(), langSpec)); + Type srcResourceType = srcResPath.getResourceStateType(); + List pathParams = new ArrayList<>(); + for (Expression pathExp: srcResPath.getPathParams()) { + String[] sideEffects = new String[] {""}; + pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + generatePullDataTransfer(stateGetter, null, + srcResourceName, srcResPath.getResourceHierarchy().toResourcePath(pathParams), + srcResourceType, true, platformSpec, langSpec); + bDeclareClientField = true; + } + } + } + } + if (ch == null) { + ch = ch2; + } + ChannelMember out = null; + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (resourceNode.getInSideResources().contains(cm.getResource())) { + out = cm; + break; + } + } + + // for reference channel members. + ResourcePath dstResPath = resourceNode.getInSideResource(ch); + for (ChannelMember rc: ch.getReferenceChannelMembers()) { + inputResourceToStateAccessor.put(rc, getPullAccessor(platformSpec)); // by pull data transfer + ResourcePath refResPath = rc.getResource(); + if (!platformSpec.isMonolithic() + && (rc.isOutside() + || (refResPath.getCommonPrefix(dstResPath) == null && platformSpec.isDifferentTreesAsDifferentServices()))) { + // for REST API + String refResourceName = langSpec.toVariableName(getComponentName(refResPath.getResourceHierarchy(), langSpec)); + Type refResourceType = refResPath.getResourceStateType(); + List pathParams = new ArrayList<>(); + for (Expression pathExp: refResPath.getPathParams()) { + String[] sideEffects = new String[] {""}; + pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + generatePullDataTransfer(stateGetter, null, + refResourceName, refResPath.getResourceHierarchy().toResourcePath(pathParams), + refResourceType, true, platformSpec, langSpec); + bDeclareClientField = true; + } + } + + // Construct the base message. + Map.Entry>>, Term> resourcePathsAndMessage; + if (!isContainedPush) { + // All incoming edges are in PULL-style. + resourcePathsAndMessage = ch.fillOutsideResourcePaths(out, getPullAccessor(platformSpec), null); + } else { + // At least one incoming edge is in PUSH-style. + resourcePathsAndMessage = ch.fillOutsideResourcePaths(out, getPullAccessor(platformSpec), inputResourceToStateAccessor); + } + Map>> resourcePaths = resourcePathsAndMessage.getKey(); + Term messageTerm = resourcePathsAndMessage.getValue(); + + // Data transfer from path depending resource. + for (Entry>> pathEnt: resourcePaths.entrySet()) { + ChannelMember cm = pathEnt.getKey(); + ResourcePath srcResPath = pathEnt.getValue().getKey(); + // get outside srcResPath resource state by pull data transfer. + if (!platformSpec.isMonolithic() + && (cm.isOutside() + || (srcResPath.getCommonPrefix(dstResPath)) == null && platformSpec.isDifferentTreesAsDifferentServices())) { + // for REST API + // Data transfer from an outside input resource is regarded as PULL transfer. + List pathParams = new ArrayList<>(); + for (Expression pathExp: srcResPath.getPathParams()) { + String[] sideEffects = new String[] {""}; + pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + // generate a pull data transfer from a depending in/ref resource. + Type srcResourceType = srcResPath.getResourceStateType(); + String srcResName2 = langSpec.toVariableName(getComponentName(srcResPath.getResourceHierarchy(), langSpec)); + String srcPath2 = srcResPath.toResourcePath().replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); + generatePullDataTransfer(stateGetter, null, srcResName2, srcPath2, srcResourceType, false, platformSpec, langSpec); + bDeclareClientField = true; + } + } + + // Data transfer from the descendant channel hierarchies. + Stack> channelItrStack = new Stack<>(); + DataTransferChannel curChannel = ch; + if (curChannel.getChildren() != null && curChannel.getChildren().size() > 0) { + // retrieve descendant channels recursively. + Iterator chItr = curChannel.getChildren().iterator(); + do { + if (!chItr.hasNext()) { + chItr = channelItrStack.pop(); + } else { + curChannel = (DataTransferChannel) chItr.next(); + // generate pull data transfers. + Set chMems = new HashSet<>(curChannel.getInputChannelMembers()); + chMems.addAll(curChannel.getReferenceChannelMembers()); + for (ChannelMember cm2: chMems) { + if (resourcePaths == null || !resourcePaths.keySet().contains(cm2)) { + // not a depending channel member. + ResourcePath src2 = cm2.getResource(); + Type srcResType2 = src2.getResourceStateType(); + String srcResName2 = langSpec.toVariableName(getComponentName(src2.getResourceHierarchy(), langSpec)); + if (platformSpec.isMonolithic()) { + String srcGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(src2, resourceNode.getInSideResource(curChannel)).toImplementation(new String[] {""}); + stateGetter.addStatement(langSpec.newVariableDeclaration(srcResType2, srcResName2) + + langSpec.getAssignment() + srcGetter + langSpec.getStatementDelimiter()); + } else { + String srcPath2 = src2.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); + generatePullDataTransfer(stateGetter, null, srcResName2, srcPath2, srcResType2, false, platformSpec, langSpec); + bDeclareClientField = true; + } + } else { + // a depending channel member. + ResourcePath src2 = resourcePaths.get(cm2).getKey(); + // get outside src2 resource state by pull data transfer. + if (cm2.isOutside() || src2.getCommonPrefix(resourceNode.getInSideResource(curChannel)) == null) { + // generate a pull data transfer from a depending in/ref resource. + Type srcResType2 = src2.getResourceStateType(); + String srcResName2 = langSpec.toVariableName(getComponentName(src2.getResourceHierarchy(), langSpec)); + if (platformSpec.isMonolithic()) { + String dependingGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(src2, resourceNode.getInSideResource(curChannel)).toImplementation(new String[] {""}); + stateGetter.addStatement(langSpec.newVariableDeclaration(srcResType2, srcResName2) + + langSpec.getAssignment() + dependingGetter + langSpec.getStatementDelimiter()); + } else { + String srcPath2 = src2.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); + generatePullDataTransfer(stateGetter, null, srcResName2, srcPath2, srcResType2, false, platformSpec, langSpec); + bDeclareClientField = true; + } + } + } + } + // collect the message constraints by a descendant channel. + List varsForSideEffects = new ArrayList<>(); + int v = 0; + resourcePathsAndMessage = curChannel.fillOutsideResourcePaths(out, getPullAccessor(platformSpec), null); + if (resourcePathsAndMessage != null) { + resourcePaths = resourcePathsAndMessage.getKey(); + Term messageTermSub = resourcePathsAndMessage.getValue(); + for (Entry fieldEnt: ((Term) messageTermSub).getSubTerms(Field.class).entrySet()) { + Position pos = fieldEnt.getKey(); + Field field = fieldEnt.getValue(); + Variable var = new Variable(field.getSymbol().getName(), field.getType()); + ((Term) messageTermSub).replaceSubTerm(pos, var); + } + for (Map.Entry subTermEnt: messageTermSub.getSubTerms(Term.class).entrySet()) { + Term subTerm = subTermEnt.getValue(); + if (!(subTerm instanceof Constant) && subTerm.getSymbol().isImplWithSideEffect()) { + Variable var = new Variable("v" + v, subTerm.getType()); + varsForSideEffects.add(var); + v++; + // Add a side effect statement within the loop + Position pos = new Position(); + pos.addHeadOrder(0); + subTerm.replaceSubTerm(pos, var); + String[] sideEffects = new String[] {""}; + String curState = messageTermSub.toImplementation(sideEffects); + stateGetter.addStatement(sideEffects[0].replaceAll("\n", "")); + // Cancel the side effects in the return value. + pos = subTermEnt.getKey(); + messageTermSub.replaceSubTerm(pos, var); + } + } + if (messageTerm == null) { + messageTerm = messageTermSub; + } else { + messageTerm = (Term) messageTerm.unify(messageTermSub); + } + if (messageTerm == null) { + throw new UnificationFailed(); + } + } + // enclosed by a for loop (for data collecting pull transfer) + Expression selExp = curChannel.getSelectors().get(0).getExpression(); + Type selType = null; + Block forLoopBlock = stateGetter.getBody(); + if (selExp instanceof Variable) { + selType = ((Variable) selExp).getType(); + String forVarName = ((Variable) selExp).getName(); + ChannelMember insideChMem = null; + for (ChannelMember cm2 :curChannel.getInputChannelMembers()) { + if (!cm2.isOutside()) { + insideChMem = cm2; + break; + } + } + if (insideChMem == null) { + for (ChannelMember cm2 :curChannel.getReferenceChannelMembers()) { + if (!cm2.isOutside()) { + insideChMem = cm2; + break; + } + } + } + ResourcePath insideResPath = insideChMem.getResource(); + while (insideResPath.getParent() != null && (insideResPath.getLastParam() == null || !insideResPath.getLastParam().equals(selExp))) { + insideResPath = insideResPath.getParent(); + } + insideResPath = insideResPath.getParent(); + if (insideResPath != null) { + String parent = null; + if (platformSpec.isMonolithic() + || insideResPath.getCommonPrefix(dstResPath) != null + || !platformSpec.isDifferentTreesAsDifferentServices()) { + if (!platformSpec.isMonolithic() && generatesComponent(insideResPath.getResourceHierarchy())) { + Expression parentGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, dstResPath); + Term valueGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); + valueGetter.addChild(parentGetter); + parent = valueGetter.toImplementation(new String[] {""}); + } else { + parent = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, dstResPath).toImplementation(new String[] {""}); + } + } else { + // for REST API + parent = langSpec.toVariableName(getComponentName(insideResPath.getResourceHierarchy(), langSpec)); + } + if (selType.equals(DataConstraintModel.typeInt)) { + // make a for loop (for a list) for data collecting. + ForStatement forLoopToCollectData = langSpec.getForStatementForList(forVarName, parent); + forLoopBlock = new Block(); + forLoopToCollectData.setBody(forLoopBlock); + stateGetter.addStatement(forLoopToCollectData); + } else if (selType.equals(DataConstraintModel.typeString)) { + // make a for loop (for a map) for data collecting. + EnhancedForStatement forLoopToCollectData = langSpec.getForStatementForMap(forVarName, parent); + forLoopBlock = new Block(); + forLoopToCollectData.setBody(forLoopBlock); + stateGetter.addStatement(forLoopToCollectData); + } + if (!platformSpec.isMonolithic() + && insideResPath.getCommonPrefix(dstResPath) == null + && platformSpec.isDifferentTreesAsDifferentServices()) { + // for REST API + Type parentResType = insideResPath.getResourceStateType(); + String parentResName = langSpec.toVariableName(getComponentName(insideResPath.getResourceHierarchy(), langSpec)); + String parentResPath = insideResPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); + generatePullDataTransfer(stateGetter, forLoopBlock, parentResName, parentResPath, parentResType, true, platformSpec, langSpec); + bDeclareClientField = true; + } + } + } + // initialize the variables to hold side effects within the loop + for (Variable var: varsForSideEffects) { + stateGetter.addFirstStatement(langSpec.newVariableDeclaration(var.getType(), var.getName()) + + langSpec.getAssignment() + langSpec.getConstructorInvocation(var.getType().getImplementationTypeName(), null) + langSpec.getStatementDelimiter()); + } + if (curChannel.getChildren() != null && curChannel.getChildren().size() > 0) { + channelItrStack.push(chItr); + chItr = curChannel.getChildren().iterator(); + } + } + } while (!channelItrStack.isEmpty()); + } + + // generate a return statement. + String[] sideEffects = new String[] {""}; + String curState = ch.deriveUpdateExpressionOf(out, messageTerm, getPullAccessor(platformSpec)).toImplementation(sideEffects); + stateGetter.addStatement(sideEffects[0] + langSpec.getReturnStatement(curState)); + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + return bDeclareClientField; + } + + private void declareDescendantGetterMethods(ResourceNode resourceNode, TypeDeclaration component, Map> descendantGetters) { + // Declare the getter methods in this resource to obtain descendant resources. + Set descendants = descendantGetters.get(resourceNode.getResourceHierarchy()); + if (descendants == null) { + descendants = new HashSet<>(); + descendantGetters.put(resourceNode.getResourceHierarchy(), descendants); + } + for (ResourceNode child: resourceNode.getChildren()) { + // A descendant of the child may generate a component. + List params = new ArrayList<>(); + int v = 1; + ResourceNode descendant = child; + Set childNodes; + do { + Expression param = descendant.getPrimaryResourcePath().getLastParam(); + if (param != null) { + if (param instanceof Variable) { + Variable var = (Variable) param; + params.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + } else if (param instanceof Term) { + Term var = (Term) param; + params.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); + } + v++; + } + if (generatesComponent(descendant.getResourceHierarchy())) { + // If the descendant generates a component. + if (!descendants.contains(descendant.getResourceHierarchy())) { + descendants.add(descendant.getResourceHierarchy()); + String descendantCompName = getComponentName(descendant.getResourceHierarchy(), langSpec); + Type descendantType = generationContext.getOrCreateComponentType(descendantCompName); + MethodDeclaration descendantGetter = null; + if (params.size() == 0) { + descendantGetter = langSpec.newMethodDeclaration(getterPrefix + descendantCompName, descendantType); + } else { + descendantGetter = langSpec.newMethodDeclaration(getterPrefix + descendantCompName, false, descendantType, params); + } + + fillDescendantGetterMethod(descendantGetter, descendant.getResourceHierarchy(), child.getResourceHierarchy(), resourceNode.getResourceHierarchy(), component); + component.addMethod(descendantGetter); + } + break; + } + childNodes = descendant.getChildren(); + } while (childNodes != null && childNodes.size() == 1 && (descendant = childNodes.iterator().next()) != null); + } + } + + private Map.Entry, Map>>> declareCacheFieldsAndUpdateMethods( + ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, TypeDeclaration rootComponent) { + // Declare cash fields and update methods in the component. + List constructorStatements = new ArrayList<>(); + Map>> updateStatements = new HashMap<>(); + for (Edge chToRes: resourceNode.getInEdges()) { + ChannelNode directSrcChannel = (ChannelNode) chToRes.getSource(); + DataTransferChannel ch = directSrcChannel.getChannel(); + // Should take into account the channel hierarchy. + Set ancestorSrcChannels = directSrcChannel.getAncestors(); + Set descendantSrcChannels = directSrcChannel.getDescendants(); + Set inEdges = new HashSet<>(); + inEdges.addAll(directSrcChannel.getInEdges()); + for (ChannelNode ancestorSrc: ancestorSrcChannels) { + inEdges.addAll(ancestorSrc.getInEdges()); + } + for (ChannelNode descendantSrc: descendantSrcChannels) { + inEdges.addAll(descendantSrc.getInEdges()); + } + for (Edge resToCh: inEdges) { + // For each data transfer from srcResPath:ResourcePath to resourceNode:ResourceNode. + DataFlowEdge re = (DataFlowEdge) resToCh; + ChannelNode indirectSrcChNode = (ChannelNode) re.getDestination(); + DataTransferChannel indirectSrcCh = indirectSrcChNode.getChannel(); + ResourcePath srcResPath = ((ResourceNode) re.getSource()).getOutSideResource(indirectSrcCh); + String srcResName = langSpec.toVariableName(getComponentName(srcResPath.getResourceHierarchy(), langSpec)); + // Check if the input resource is outside of the channel scope. + boolean outsideInputResource = false; + for (ChannelMember cm: indirectSrcCh.getInputChannelMembers()) { + if (cm.getResource().equals(srcResPath) && cm.isOutside()) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + // Check if the output resource is outside of the channel scope. + boolean outsideOutputResource = false; + ChannelMember out = null; + ResourcePath dstResPath = null; + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (resourceNode.getInSideResources().contains(cm.getResource())) { + out = cm; + dstResPath = cm.getResource(); + if (cm.isOutside()) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } + } + // Also take into account the channel hierarchy to determine push/pull transfer. + if (ancestorSrcChannels.contains(indirectSrcChNode)) { + outsideOutputResource = true; // Regarded as (broadcasting) push transfer. + } + if (descendantSrcChannels.contains(indirectSrcChNode)) { + outsideInputResource = true; // Regarded as (collecting) pull transfer. + } + if ((((PushPullAttribute) re.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { + // For push data transfer + + boolean hasRestAPI = false; + boolean isRestAPI = false; + if (!platformSpec.isMonolithic() + && (outsideOutputResource || (resourceNode.getInSideResource(ch).getCommonPrefix(srcResPath) == null && platformSpec.isDifferentTreesAsDifferentServices()))) { + // Inter-service + hasRestAPI = true; + if (resourceNode.getParent() == null) { + // A root resource + isRestAPI = true; + } + } + // Declare an update method in the type of the destination resource. + ArrayList parameters = new ArrayList<>(); + getUpdateResourcePathAndPathParams(dstResPath, parameters, isRestAPI, platformSpec, langSpec); // Path parameters to identify the self resource. + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + VariableDeclaration chParam = langSpec.newVariableDeclaration(selVar.getType(), selVar.getName()); + if (isRestAPI) ((RestApiSpecific) platformSpec).addFormParamAnnotation(chParam, selVar.getName()); + parameters.add(chParam); // A channel parameter to specify the context of the collaboration. + } + } + VariableDeclaration param = langSpec.newVariableDeclaration(srcResPath.getResourceStateType(), srcResName); + if (isRestAPI) ((RestApiSpecific) platformSpec).addFormParamAnnotation(param, srcResName); + parameters.add(param); // The state of the source resource to carry the data-flow. + // For the refs. + for (ResourcePath ref: ch.getReferenceResources()) { + if (!resourceNode.getInSideResources().contains(ref)) { + String refName = langSpec.toVariableName(getComponentName(ref.getResourceHierarchy(), langSpec)); + param = langSpec.newVariableDeclaration(ref.getResourceStateType(), refName); + if (isRestAPI) ((RestApiSpecific) platformSpec).addFormParamAnnotation(param, refName); + parameters.add(param); + } + } + // Get or declare the update method. + MethodDeclaration update = getOrDeclareUpdateMethod(srcResPath.getResourceHierarchy(), resourceNode.getResourceHierarchy(), ch, parameters); + + // Calculate in-degree (PUSH transfer) of the destination resource. + int inDegree = 0; + for (Edge resToCh2: inEdges) { + DataFlowEdge df =(DataFlowEdge) resToCh2; + if (((PushPullAttribute) df.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { + inDegree++; + } + } + if (isRestAPI) { + // Determine whether the update method is put or post or delete. + if (isPut(out)) { + ((RestApiSpecific) platformSpec).addPutAnnotations(update); + } else { + if (!isDelete(out)) { + ((RestApiSpecific) platformSpec).addPostAnnotations(update); + } else { + ((RestApiSpecific) platformSpec).addDeleteAnnotations(update); + } + } + if (inDegree > 1) { + // If incoming edges are multiple, then a child resource for each source resource is defined in the destination resource so that its state can be updated separately. + if (isRestAPI) ((RestApiSpecific) platformSpec).addPathAnnotation(update, "/" + srcResName); + } + } + + // Add a statement to update the state field + if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { + try { + if (resourceNode.getInSideResources().contains(out.getResource())) { + Term unifiedMassage = null; + for (ChannelNode srcChNode: ancestorSrcChannels) { + DataTransferChannel abcestorSrcCh = (DataTransferChannel) srcChNode.getChannel(); + Term message = abcestorSrcCh.fillOutsideResourcePaths(out, getPushAccessor(platformSpec), null).getValue(); + if (unifiedMassage == null) { + unifiedMassage = message; + } else { + unifiedMassage = (Term) unifiedMassage.unify(message); + } + } + Expression updateExp = null; + if (ch.getReferenceChannelMembers().size() == 0) { + Term message = ch.fillOutsideResourcePaths(out, getPushAccessor(platformSpec), null).getValue(); + if (unifiedMassage == null) { + unifiedMassage = message; + } else { + unifiedMassage = (Term) unifiedMassage.unify(message); + } + updateExp = ch.deriveUpdateExpressionOf(out, unifiedMassage, getPushAccessor(platformSpec)); + } else { + // if there exists one or more reference channel member. + HashMap inputResourceToStateAccessor = new HashMap<>(); + for (ChannelMember in: ch.getInputChannelMembers()) { + inputResourceToStateAccessor.put(in, getPushAccessor(platformSpec)); + } + for (ChannelMember ref: ch.getReferenceChannelMembers()) { + inputResourceToStateAccessor.put(ref, getRefAccessor(platformSpec)); + } + Term message = ch.fillOutsideResourcePaths(out, getPushAccessor(platformSpec), inputResourceToStateAccessor).getValue(); + if (unifiedMassage == null) { + unifiedMassage = message; + } else { + unifiedMassage = (Term) unifiedMassage.unify(message); + } + updateExp = ch.deriveUpdateExpressionOf(out, unifiedMassage, getPushAccessor(platformSpec)); + } + // Replace Json constructor with a constructor of the child resource. + ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); + if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { + ResourceHierarchy descendantRes = outRes; + Set children = descendantRes.getChildren(); + do { + descendantRes = children.iterator().next(); + if (generatesComponent(descendantRes)) { + // If there exists at least one descendant resource whose component is not to be generated. + updateStatements.put(update, new AbstractMap.SimpleEntry<>(updateExp, new AbstractMap.SimpleEntry<>(outRes, descendantRes))); + updateExp = null; + break; + } + children = descendantRes.getChildren(); + } while (children != null && children.size() == 1); + } + // Add statements to the update method. + if (updateExp != null) { + // Replace the type of the state field. + Type fieldType = getImplStateType(outRes, langSpec); + if (updateExp instanceof Term) { + ((Term) updateExp).setType(fieldType); + for (Map.Entry varEnt: ((Term) updateExp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals(fieldOfResourceState)) { + varEnt.getValue().setType(fieldType); + } + } + } else if (updateExp instanceof Variable) { + ((Variable) updateExp).setType(fieldType); + } + // Add statements to the update method. + String[] sideEffects = new String[] {""}; + String newState = updateExp.toImplementation(sideEffects); + int numOfOutResourcesWithTheSameHierarchy = 0; + for (ResourcePath outResPath: ch.getOutputResources()) { + if (outResPath.getResourceHierarchy().equals(outRes)) { + numOfOutResourcesWithTheSameHierarchy++; + } + } + String updateStatement = ""; + if (generatesComponent(outRes)) { + if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + updateStatement = sideEffects[0]; + if (updateStatement.endsWith("\n")) { + updateStatement = updateStatement.substring(0, updateStatement.length() - 1); + } + } else { + updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); // this.value = ... + } + } else { + if (sideEffects[0] != null) { + updateStatement = sideEffects[0]; + String resourceName = langSpec.toVariableName(getComponentName(outRes, langSpec)); + updateStatement = updateStatement.replace(langSpec.getFieldAccessor(fieldOfResourceState), langSpec.getFieldAccessor(resourceName)); + if (updateStatement.endsWith("\n")) { + updateStatement = updateStatement.substring(0, updateStatement.length() - 1); + } + } + if (DataConstraintModel.typeList.isAncestorOf(resourceNode.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); + selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newList = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (DataConstraintModel.typeMap.isAncestorOf(resourceNode.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.insert); + selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); + selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newMap = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (!(updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect())) { + String resourceName = langSpec.toVariableName(getComponentName(outRes, langSpec)); + updateStatement += langSpec.getFieldAccessor(resourceName) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); + } + } + // add an update statement of the state of dst side resource. + if (numOfOutResourcesWithTheSameHierarchy == 1) { + update.addFirstStatement(updateStatement); + } else { + Term conditions = null; + int i = 1; + Map>> resourcePaths = ch.fillOutsideResourcePaths(out, getPushAccessor(platformSpec)); + for (Expression pathParam: out.getResource().getPathParams()) { + if (pathParam instanceof Variable) { + String selfParamName = ((Variable) pathParam).getName(); + Expression arg = null; + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + if (selVar.getName().equals(selfParamName)) { + arg = selVar; + break; + } + } + } + if (arg == null) { + ResourcePath filledPath = resourcePaths.get(out).getKey(); + arg = filledPath.getPathParams().get(i - 1); + } + Term condition = new Term(DataConstraintModel.eq, new Expression[] { + new Parameter("self" + (i > 1 ? i : ""), DataConstraintModel.typeString), + arg}); + if (conditions == null) { + conditions = condition; + } else { + conditions = new Term(DataConstraintModel.and, new Expression[] { + conditions, + condition}); + } + } + i++; + } + Block ifBlock = new Block(); + ifBlock.addStatement(updateStatement); + update.addFirstStatement(langSpec.getIfStatement(conditions, ifBlock)); + } + } + } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e1) { + e1.printStackTrace(); + } + } + + // For a post/put REST API. + if (hasRestAPI) { + if (!isRestAPI) { + // If not a root resource. + // Declare an update accessor method in the type of root resource. + declareUpdateAccessorInTheRootResource(resourceNode, update.getName(), ch, out, srcResPath, dstResPath, + rootComponent, inDegree, platformSpec, langSpec); + } + // to convert a json param to a tuple, pair or map object. + for (VariableDeclaration jsonParam: update.getParameters()) { + Type paramType = jsonParam.getType(); + String paramName = jsonParam.getName(); + String paramTypeName = paramType.getInterfaceTypeName(); + String paramConverter = ""; + if (DataConstraintModel.typeList.isAncestorOf(paramType) && paramType != DataConstraintModel.typeList) { + if (paramType instanceof ListType) { + Type compType = ((ListType) paramType).getElementType(); + if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { + jsonParam.setType(DataConstraintModel.typeListStr); + jsonParam.setName(paramName + "_json"); + paramConverter += langSpec.newVariableDeclaration(paramType, paramName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(paramType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + EnhancedForStatement forStatement = langSpec.getForStatementForCollection(langSpec.newVariableDeclaration(DataConstraintModel.typeString, "str"), jsonParam.getName()); + Block forBlock = new Block(); + Type mapType = convertFromEntryToMapType(compType, langSpec); + forBlock.addStatement(((RestApiSpecific) platformSpec).getConversionFromJsonString("str", "i", mapType.getInterfaceTypeName()) + langSpec.getStatementDelimiter()); + forBlock.addStatement(langSpec.getMethodInvocation(paramName, DataConstraintModel.append.getImplName(), List.of(getCodeForConversionFromMapToTuple(compType, "i", langSpec))) + langSpec.getStatementDelimiter()); + forStatement.setBody(forBlock); + paramConverter += forStatement; + ((RestApiSpecific) platformSpec).addJsonException(update); + } else if (compType != null && DataConstraintModel.typePair.isAncestorOf(compType)) { + jsonParam.setType(DataConstraintModel.typeListStr); + jsonParam.setName(paramName + "_json"); + paramConverter += langSpec.newVariableDeclaration(paramType, paramName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(paramType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + EnhancedForStatement forStatement = langSpec.getForStatementForCollection(langSpec.newVariableDeclaration(DataConstraintModel.typeString, "str"), jsonParam.getName()); + Block forBlock = new Block(); + Type mapType = convertFromEntryToMapType(compType, langSpec); + forBlock.addStatement(((RestApiSpecific) platformSpec).getConversionFromJsonString("str", "i", mapType.getInterfaceTypeName()) + langSpec.getStatementDelimiter()); + forBlock.addStatement(langSpec.getMethodInvocation(paramName, DataConstraintModel.append.getImplName(), List.of(getCodeForConversionFromMapToPair(compType, "i", langSpec))) + langSpec.getStatementDelimiter()); + forStatement.setBody(forBlock); + paramConverter += forStatement; + ((RestApiSpecific) platformSpec).addJsonException(update); + } else if (compType != null && DataConstraintModel.typeMap.isAncestorOf(compType)) { + jsonParam.setType(DataConstraintModel.typeListStr); + // To do. + } + } + } else if (DataConstraintModel.typeTuple.isAncestorOf(paramType)) { + jsonParam.setType(DataConstraintModel.typeString); + jsonParam.setName(paramName + "_json"); + paramConverter += langSpec.newVariableDeclaration(paramType, paramName) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getOpeningScoreDelimiter() + "\n"; + Type mapType = convertFromEntryToMapType(paramType, langSpec); + paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapType.getInterfaceTypeName()) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += "\t" + paramName + langSpec.getAssignment() + getCodeForConversionFromMapToTuple(paramType, "i", langSpec) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getClosingScoreDelimiter(); + ((RestApiSpecific) platformSpec).addJsonException(update); + } else if (DataConstraintModel.typePair.isAncestorOf(paramType)) { + jsonParam.setType(DataConstraintModel.typeString); + jsonParam.setName(paramName + "_json"); + paramConverter += langSpec.newVariableDeclaration(paramType, paramName) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getOpeningScoreDelimiter() + "\n"; + Type mapType = convertFromEntryToMapType(paramType, langSpec); + paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapType.getInterfaceTypeName()) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += "\t" + paramName + langSpec.getAssignment() + getCodeForConversionFromMapToPair(paramType, "i", langSpec) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getClosingScoreDelimiter(); + ((RestApiSpecific) platformSpec).addJsonException(update); + } else if (DataConstraintModel.typeMap.isAncestorOf(paramType)) { + jsonParam.setType(DataConstraintModel.typeString); + jsonParam.setName(paramName + "_json"); + paramConverter += langSpec.newVariableDeclaration(paramType, paramName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(paramType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getOpeningScoreDelimiter() + "\n"; + Type mapType = convertFromEntryToMapType(paramType, langSpec); + paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapType.getInterfaceTypeName()) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += "\t" + getCodeForConversionFromMapToMap(paramType, "i", paramName, langSpec) + "\n"; + paramConverter += langSpec.getClosingScoreDelimiter(); + ((RestApiSpecific) platformSpec).addJsonException(update); + } + if (paramConverter.length() > 0 && (update.getBody() == null || !update.getBody().getStatements().contains(paramConverter))) { + update.addFirstStatement(paramConverter); + } + } + } + + // Declare the field to cache the state of the source resource in the type of the destination resource. + if (inDegree > 1 + || (ch.getInputChannelMembers().size() == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { + // If incoming edges are multiple, or the current state of an input member is needed. + if (langSpec.declareField()) { + // Declare the cache field. + String cacheFieldName = langSpec.toVariableName(getComponentName(srcResPath.getResourceHierarchy(), langSpec)); + FieldDeclaration cacheField = langSpec.newFieldDeclaration(srcResPath.getResourceStateType(), cacheFieldName); + setFieldInitializer(cacheField, srcResPath.getResourceStateType(), srcResPath.getResourceHierarchy().getInitialValue()); + if (component != null) { + component.addField(cacheField); + } else if (parentComponent != null){ + parentComponent.addField(cacheField); + } + + } + // Update the cache field. + String cacheStatement = langSpec.getFieldAccessor(langSpec.toVariableName(srcResName)) + langSpec.getAssignment() + langSpec.toVariableName(srcResName) + langSpec.getStatementDelimiter(); + if (update.getBody() == null || !update.getBody().getStatements().contains(cacheStatement)) { + update.addStatement(cacheStatement); + } + } + + // Update and initialize a field to refer to an outside input resource for PULL transfer. + if (platformSpec.isMonolithic()) { + // For a monolithic application. + Set outsideInputMembers = new HashSet<>(); + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.isOutside()) { + outsideInputMembers.add(cm); + } + } + if (outsideInputMembers.size() > 0) { + Map>> resourcePaths = null; + for (ChannelMember out1: ch.getOutputChannelMembers()) { + if (resourceNode.getInSideResources().contains(out1.getResource())) { + try { + resourcePaths = ch.fillOutsideResourcePaths(out1, getPullAccessor(platformSpec)); + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + break; + } + } + if (resourcePaths != null && resourcePaths.size() > 0) { + for (ChannelMember outsideMember: outsideInputMembers) { + for (ChannelMember dependingMember: resourcePaths.get(outsideMember).getValue()) { + if (dependingMember.getResource().equals(srcResPath)) { + // An outside input resource path depends on srcRes. + ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); + String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); + Expression outsideExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(outsidePath, null); + if (generatesComponent(outsidePath.getResourceHierarchy())) { + outsideExp = ((Term) outsideExp).getChild(0); + } + Expression nextExp = dependingMember.getStateTransition().getNextStateExpression(); + if (nextExp != null && outsideExp instanceof Term) { + if (nextExp instanceof Variable) { + outsideExp = ((Term) outsideExp).substitute((Variable) nextExp, new Field(langSpec.toVariableName(getComponentName(dependingMember.getResource().getResourceHierarchy(), langSpec)))); + } else { + // ToDo. + } + } + String[] sideEffects = new String[] {""}; + String outsideAccessor = outsideExp.toImplementation(sideEffects); + String updateReference = langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter(); + update.addStatement(updateReference); // Update the reference field. + // Update constructor. + if (component != null) { + MethodDeclaration constructor = getConstructor(component); + constructor.addStatement(updateReference); // Initialize the reference field. + } else if (parentComponent != null){ + constructorStatements.add(updateReference); + } + } + } + } + } + } + } + + // Add an invocation to another update method (for a chain of update method invocations). + boolean hasUpdateMethodinvoked = false; + for (Edge resToCh2: resourceNode.getOutEdges()) { + DataFlowEdge dOut = (DataFlowEdge) resToCh2; + ChannelNode directDstChNode = (ChannelNode) resToCh2.getDestination(); + DataTransferChannel directDstCh = directDstChNode.getChannel(); + // Check if the input resource is outside of the channel scope. + boolean outsideInputResource2 = false; + ChannelMember in = null; + Set outsideInputMembers2 = new HashSet<>(); + for (ChannelMember cm: directDstCh.getInputChannelMembers()) { + if (cm.getResource().equals(resourceNode.getOutSideResource(directDstCh))) { + if (cm.isOutside()) { + outsideInputResource2 = true; // Regarded as pull transfer. + } + in = cm; + } + if (cm.isOutside()) { + outsideInputMembers2.add(cm); + } + } + // Should take into account the channel hierarchy. + Set ancestorDstChannels = directDstChNode.getAncestors(); + Set descendantDstChannels = directDstChNode.getDescendants(); + Set outEdges = new HashSet<>(); + outEdges.addAll(directDstChNode.getOutEdges()); + for (ChannelNode ancestorDst: ancestorDstChannels) { + outEdges.addAll(ancestorDst.getOutEdges()); + } + for (ChannelNode descendantDst: descendantDstChannels) { + outEdges.addAll(descendantDst.getOutEdges()); + } + for (Edge chToRes2: outEdges) { + // For each data transfer to dstNode:ResourceNode. + ResourceNode dstNode = ((ResourceNode) chToRes2.getDestination()); + ChannelNode chNode2 = (ChannelNode) chToRes2.getSource(); + DataTransferChannel ch2 = chNode2.getChannel(); + // Check if the output resource is outside of the channel scope. + boolean outsideOutputResource2 = false; + ChannelMember out1 = null; + for (ChannelMember cm: ch2.getOutputChannelMembers()) { + if (dstNode.getInSideResources().contains(cm.getResource())) { + out1 = cm; + if (cm.isOutside()) { + outsideOutputResource2 = true; + break; + } + } + } + // Also take into account the channel hierarchy to determine push/pull transfer. + if (descendantDstChannels.contains(chNode2)) { + outsideOutputResource2 = true; // Regarded as (broadcasting) push transfer. + } + if (ancestorDstChannels.contains(chNode2)) { + outsideInputResource2 = true; // Regarded as (collecting) pull transfer. + } + if ((((PushPullAttribute) dOut.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource2) || outsideOutputResource2) { + // PUSH transfer + Block forLoopBlock = update.getBody(); + if (descendantDstChannels.contains(chNode2)) { + // For hierarchical channels (broadcasting push transfer). + if (ch2.getSelectors() != null && ch2.getSelectors().size() > 0) { + Expression selExp = ch2.getSelectors().get(0).getExpression(); + Type selType = null; + if (selExp instanceof Variable) { + selType = ((Variable) selExp).getType(); + String forVarName = ((Variable) selExp).getName(); + ChannelMember insideChMem = null; + for (ChannelMember cm :ch2.getInputChannelMembers()) { + if (!cm.isOutside()) { + insideChMem = cm; + break; + } + } + if (insideChMem == null) { + for (ChannelMember cm :ch2.getReferenceChannelMembers()) { + if (!cm.isOutside()) { + insideChMem = cm; + break; + } + } + } + if (insideChMem == null) { + for (ChannelMember cm :ch2.getOutputChannelMembers()) { + if (!cm.isOutside()) { + insideChMem = cm; + break; + } + } + } + ResourcePath insideResPath = insideChMem.getResource(); + while (insideResPath.getParent() != null && (insideResPath.getLastParam() == null || !insideResPath.getLastParam().equals(selExp))) { + insideResPath = insideResPath.getParent(); + } + insideResPath = insideResPath.getParent(); + if (insideResPath != null) { + String parent = null; + if (platformSpec.isMonolithic() + || insideResPath.getCommonPrefix(resourceNode.getOutSideResource(directDstCh)) != null + || !platformSpec.isDifferentTreesAsDifferentServices()) { + if (!platformSpec.isMonolithic() && generatesComponent(insideResPath.getResourceHierarchy())) { + Expression getter = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, resourceNode.getOutSideResource(directDstCh)); + Term valueGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); + valueGetter.addChild(getter); + parent = valueGetter.toImplementation(new String[] {""}); + } else { + parent = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, resourceNode.getOutSideResource(directDstCh)).toImplementation(new String[] {""}); + } + } else { + // for REST API + parent = langSpec.toVariableName(getComponentName(insideResPath.getResourceHierarchy(), langSpec)); + } + if (selType.equals(DataConstraintModel.typeInt)) { + // make a for loop (for a list) for broadcasting. + ForStatement forLoopToCollectData = langSpec.getForStatementForList(forVarName, parent); + forLoopBlock = new Block(); + forLoopToCollectData.setBody(forLoopBlock); + update.addStatement(forLoopToCollectData); + } else if (selType.equals(DataConstraintModel.typeString)) { + // make a for loop (for a map) for broadcasting. + EnhancedForStatement forLoopToCollectData = langSpec.getForStatementForMap(forVarName, parent); + forLoopBlock = new Block(); + forLoopToCollectData.setBody(forLoopBlock); + update.addStatement(forLoopToCollectData); + } + if (!platformSpec.isMonolithic() + && insideResPath.getCommonPrefix(resourceNode.getOutSideResource(directDstCh)) == null + && platformSpec.isDifferentTreesAsDifferentServices()) { + // for REST API + Type parentResType = insideResPath.getResourceStateType(); + String parentResName = langSpec.toVariableName(getComponentName(insideResPath.getResourceHierarchy(), langSpec)); + String parentResPath = insideResPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); + generatePullDataTransfer(update, forLoopBlock, parentResName, parentResPath, parentResType, true, platformSpec, langSpec); + if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); + } else if (parentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); + } + } + } + } else if (selExp instanceof Term) { + // not supported. + } + } + } + // Get the value of reference member to call the update method. + List>> refParams = new ArrayList<>(); + Map> referredResources = new HashMap<>(); + Set referredSet = referredResources.get(update); + for (ChannelMember rc: ch2.getReferenceChannelMembers()) { + ResourcePath ref = rc.getResource(); + if (referredSet == null) { + referredSet = new HashSet<>(); + referredResources.put(update, referredSet); + } + if (!resourceNode.getInSideResources().contains(ref)) { + String refVarName = langSpec.toVariableName(getComponentName(ref.getResourceHierarchy(), langSpec)); + Type refResourceType = ref.getResourceStateType(); + if (!referredSet.contains(ref)) { + referredSet.add(ref); + String[] sideEffects = new String[] {""}; + ResourcePath srcRes = in.getResource(); + if (!generatesComponent(srcRes.getResourceHierarchy())) { + srcRes = srcRes.getParent(); + } + if (!platformSpec.isMonolithic() + && (rc.isOutside() || (ref.getCommonPrefix(srcRes) == null && platformSpec.isDifferentTreesAsDifferentServices()))) { + List pathParams = new ArrayList<>(); + for (Expression pathExp: ref.getPathParams()) { + pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + generatePullDataTransfer(update, forLoopBlock, refVarName, ref.getResourceHierarchy().toResourcePath(pathParams), refResourceType, false, platformSpec, langSpec); + if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); + } else if (parentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); + } + } else { + Expression refGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(ref, srcRes); + String refExp = refGetter.toImplementation(sideEffects); + String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); + forLoopBlock.addStatement(sideEffects[0] + langSpec.newVariableDeclaration(ref.getResourceStateType(), refVarName) + + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); + } + } + refParams.add(new AbstractMap.SimpleEntry<>(ref.getResourceStateType(), + new AbstractMap.SimpleEntry<>(refVarName, + refVarName))); + } + } + // Add an update method invocation. + hasUpdateMethodinvoked = addUpdateMethodInvocation(resourceNode, dstNode, update, forLoopBlock, refParams, + ch2, in, out1, inDegree, outsideOutputResource2, hasUpdateMethodinvoked); + } + } + + // Add an invocation to output native event channel. + if (directDstCh.isNative() && platformSpec.isMonolithic()) { + addNativeMethodInvocation(resourceNode, presenter, update, ch, directDstCh, out, in); + if (component != null) { + component.addField(langSpec.newFieldDeclaration(presenterType, presenter)); + } else if (parentComponent != null) { + parentComponent.addField(langSpec.newFieldDeclaration(presenterType, presenter)); + } + Map nameToParam = constructorParams.getOrDefault(resourceNode.getResourceHierarchy(), new HashMap<>()); + nameToParam.put(presenter,langSpec.newVariableDeclaration(presenterType, presenter)); + constructorParams.put(resourceNode.getResourceHierarchy(), nameToParam); + } + + if (outsideInputMembers2.size() > 0) { + if (!generatesComponent(resourceNode.getResourceHierarchy())) { + // srcRes2 does not have a component. + ResourcePath srcRes2 = resourceNode.getOutSideResource(directDstCh); + for (Edge chToRes2: outEdges) { + ChannelNode chNode2 = (ChannelNode) chToRes2.getSource(); + DataTransferChannel ch2 = chNode2.getChannel(); + for (ChannelMember out2: ch2.getOutputChannelMembers()) { + if (!generatesComponent(out2.getResource().getResourceHierarchy())) { + // Also dstRes2 does not have a component. + ResourcePath dstRes2 = out2.getResource(); + if (srcRes2.getParent().equals(dstRes2.getParent())) { + Map>> resourcePaths = null; + try { + resourcePaths = ch2.fillOutsideResourcePaths(out2, getPullAccessor(platformSpec)); + if (resourcePaths != null && resourcePaths.size() > 0) { + for (ChannelMember outsideMember: outsideInputMembers2) { + for (ChannelMember dependedMember: resourcePaths.get(outsideMember).getValue()) { + if (dependedMember.getResource().equals(srcRes2)) { + // An outside input resource path depends on srcRes. + ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); + if (!generatesComponent(outsidePath.getResourceHierarchy())) { + outsidePath = outsidePath.getParent(); + } + String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); + Expression outsideExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(outsidePath, null); + if (generatesComponent(outsidePath.getResourceHierarchy())) { + outsideExp = ((Term) outsideExp).getChild(0); + } + String[] sideEffects = new String[] {""}; + String outsideAccessor = outsideExp.toImplementation(sideEffects); + String updateReference = langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter(); + update.addStatement(updateReference); // Update the reference field. + // Update constructor. + if (component != null) { + MethodDeclaration constructor = getConstructor(component); + constructor.addStatement(updateReference); // Initialize the reference field. + } else if (parentComponent != null) { + constructorStatements.add(updateReference); + } + } + } + } + } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + } + } + } + } + } + } + } + } + } + } + return new AbstractMap.SimpleEntry<>(constructorStatements, updateStatements); + } + + private Map.Entry, Map>>> declareInputMethodsInThisAndMainComponents(ResourceNode resourceNode, TypeDeclaration component, + TypeDeclaration parentComponent, TypeDeclaration mainComponent, TypeDeclaration rootComponent, DataTransferModel model, Map priorMemberForInputChannel) { + // Declare input methods. + String resName = resourceNode.getResourceName(); + List constructorStatements = new ArrayList<>(); + Map>> inputStatements = new HashMap<>(); + for (Channel ch: model.getInputChannels()) { + for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) { + if (!cm.isOutside()) { + if (priorMemberForInputChannel.get(ch) == null) { + priorMemberForInputChannel.put(ch, cm); // The receiver of the input event when multiple output resources are defined for the channel. + } + } + } + for (ChannelMember out: ((DataTransferChannel) ch).getOutputChannelMembers()) { + if (resourceNode.getInSideResources().contains(out.getResource())) { + Expression message = out.getStateTransition().getMessageExpression(); + MethodDeclaration input = null; + MethodDeclaration mainInputAccessor = null; + MethodDeclaration rootInputAccessor = null; + if (message instanceof Term) { + // Declare an input method in this component. + ArrayList resInputParams = new ArrayList<>(); + ArrayList mainInputParams = new ArrayList<>(); + ArrayList rootInputParams = new ArrayList<>(); + String resourcePath = null; + if (!platformSpec.isMonolithic()) { + resourcePath = getInputMethodResourcePathAndPathParams(out.getResource(), rootInputParams, platformSpec, langSpec); // Path parameters for the input REST API. + if (resourcePath.indexOf('/') > 0) { + // Remove the root resource from the path + resourcePath = resourcePath.substring(resourcePath.indexOf('/')); + } else { + resourcePath = ""; + } + } + // The path parameters are not to be passed to the input method of each resource (resInputParams) + // because they are always equal to either channel selectors or message parameters. + + // Channel parameters to specify the context of the collaboration. + int v = 1; + for (Selector selector: ch.getSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + resInputParams.add(langSpec.newVariableDeclaration(selVar.getType(), selVar.getName())); + mainInputParams.add(langSpec.newVariableDeclaration(selVar.getType(), selVar.getName())); + } else if (selector.getExpression() instanceof Term) { + Term var = (Term) selector.getExpression(); + resInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); + mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); + } + v++; + } + if (ch.getParent() != null) { + for (Selector selector: ch.getParent().getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + mainInputParams.add(langSpec.newVariableDeclaration(selVar.getType(), selVar.getName())); + } else if (selector.getExpression() instanceof Term) { + Term var = (Term) selector.getExpression(); + mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); + } + v++; + } + } + // Message parameters to carry the data-flows. + for (Map.Entry varEnt: message.getVariables().entrySet()) { + Variable var = varEnt.getValue(); + String refVarName = null; + for (ChannelMember refCm: ((DataTransferChannel) ch).getReferenceChannelMembers()) { + Expression varExp = refCm.getStateTransition().getMessageExpression().getSubTerm(varEnt.getKey()); + if (varExp != null && varExp instanceof Variable) { + if (refCm.getStateTransition().getCurStateExpression().contains(varExp)) { + refVarName = refCm.getResource().getLeafResourceName(); + break; + } + } + } + if (refVarName != null) { + // var has come from a reference resource. + resInputParams.add(langSpec.newVariableDeclaration(var.getType(), refVarName)); + } else { + // var has not come from a reference resource. + resInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + boolean bExists = false; + for (VariableDeclaration mainParam: mainInputParams) { + if (mainParam.getName().equals(var.getName()) ) { + bExists = true; + break; + } + } + if (!bExists) { + mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + } + if (!platformSpec.isMonolithic() && !resourcePath.contains("{" + var.getName()+ "}")) { + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), var.getName()); + ((RestApiSpecific) platformSpec).addFormParamAnnotation(param, var.getName()); + rootInputParams.add(param); + } + } + } + if (platformSpec.isMonolithic() + || (resourceNode.getResourceHierarchy().getParent() != null && (component != null || resourceNode.getResourceHierarchy().getParent().getParent() != null))) { + // The case that the input accessor is needed. + String inputMethodName = ((Term) message).getSymbol().getImplName(); + if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) { + inputMethodName += _for + getComponentName(out.getResource().getResourceHierarchy(), langSpec); + } + if (component != null) { + // A component is created for this resource. + for (MethodDeclaration method: component.getMethods()) { + if (method.getName().equals(inputMethodName)) { + input = method; + break; + } + } + if (input == null) { + input = langSpec.newMethodDeclaration(inputMethodName, false, null, resInputParams); + component.addMethod(input); + } + } else if (parentComponent != null) { + // No component is created for this resource. + for (MethodDeclaration method: parentComponent.getMethods()) { + if (method.getName().equals(inputMethodName)) { + input = method; + break; + } + } + if (input == null) { + input = langSpec.newMethodDeclaration(inputMethodName, false, null, resInputParams); + parentComponent.addMethod(input); + } + } + } + + // Declare the accessor in the main component to call the input method. (for monolithic application) + if (platformSpec.hasMain()) { + String messageSymbol = ((Term) message).getSymbol().getImplName(); + mainInputAccessor = getMethod(mainComponent, messageSymbol); + if (mainInputAccessor == null) { + mainInputAccessor = langSpec.newMethodDeclaration(messageSymbol, false, null, mainInputParams); + mainComponent.addMethod(mainInputAccessor); + } else { + // Add type to a parameter without type. + if (mainInputAccessor.getParameters() != null) { + for (VariableDeclaration param: mainInputAccessor.getParameters()) { + if (param.getType() == null) { + for (VariableDeclaration p: mainInputParams) { + if (param.getName().equals(p.getName()) && p.getType() != null) { + param.setType(p.getType()); + } + } + } + } + } + } + } + + // For the root resource. (for REST API) + if (!platformSpec.isMonolithic()) { + if (priorMemberForInputChannel.get(ch) == null || out == priorMemberForInputChannel.get(ch)) { + // If out is the receiver of the input event. + priorMemberForInputChannel.put(ch, out); + String messageSymbol = ((Term) message).getSymbol().getImplName(); + rootInputAccessor = declareInputAccessorInTheRootResource(messageSymbol, rootInputParams, out, resourcePath, + rootComponent, platformSpec, langSpec); + if (input == null) { + input = rootInputAccessor; + rootInputAccessor = null; + } + } + } + } else if (message instanceof Variable) { + // Declare an input method in this component. + ArrayList resInputParams = new ArrayList<>(); + ArrayList mainInputParams = new ArrayList<>(); + int v = 1; + if (out.getResource().getLastParam() != null) { + Expression param = out.getResource().getLastParam(); + if (param instanceof Variable) { + Variable var = (Variable) param; + resInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + } else if (param instanceof Term) { + Term var = (Term) param; + resInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); + mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); + } + v++; + } + if (out.getResource().getParent() != null) { + for (Expression param: out.getResource().getParent().getPathParams()) { + if (param instanceof Variable) { + Variable var = (Variable) param; + mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + } else if (param instanceof Term) { + Term var = (Term) param; + mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); + } + v++; + } + } + if (platformSpec.isMonolithic() + || (resourceNode.getResourceHierarchy().getParent() != null && resourceNode.getResourceHierarchy().getParent().getParent() != null)) { + String inputMethodName = ((Variable) message).getName(); + if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) { + inputMethodName += _for + getComponentName(out.getResource().getResourceHierarchy(), langSpec); + } + if (component != null) { + // A component is created for this resource. + for (MethodDeclaration method: component.getMethods()) { + if (method.getName().equals(inputMethodName)) { + input = method; + break; + } + } + if (input == null) { + if (resInputParams.size() == 0) { + input = langSpec.newMethodDeclaration(inputMethodName, null); + } else { + input = langSpec.newMethodDeclaration(inputMethodName, false, null, resInputParams); + } + component.addMethod(input); + } + } else if (parentComponent != null) { + // No component is created for this resource. + for (MethodDeclaration method: parentComponent.getMethods()) { + if (method.getName().equals(inputMethodName)) { + input = method; + break; + } + } + if (input == null) { + if (resInputParams.size() == 0) { + input = langSpec.newMethodDeclaration(inputMethodName, null); + } else { + input = langSpec.newMethodDeclaration(inputMethodName, false, null, resInputParams); + } + parentComponent.addMethod(input); + } + } + } + + // Declare the accessor in the main component to call the input method. (for monolithic application) + if (platformSpec.hasMain()) { + String messageSymbol = ((Variable) message).getName(); + mainInputAccessor = getMethod(mainComponent, messageSymbol, mainInputParams); + if (mainInputAccessor == null) { + if (mainInputParams.size() == 0) { + mainInputAccessor = langSpec.newMethodDeclaration(messageSymbol, null); + } else { + mainInputAccessor = langSpec.newMethodDeclaration(messageSymbol, false, null, mainInputParams); + } + mainComponent.addMethod(mainInputAccessor); + } + } + + // For the root resource. (for REST API) + if (!platformSpec.isMonolithic()) { + if (priorMemberForInputChannel.get(ch) == null || out == priorMemberForInputChannel.get(ch)) { + // If out is the receiver of the input event. + priorMemberForInputChannel.put(ch, out); + ArrayList rootInputParams = new ArrayList<>(); + String resourcePath = getGetterResourcePathAndPathParams(out.getResource(), rootInputParams, platformSpec, langSpec); + if (resourcePath.indexOf('/') > 0) { + // Remove the root resource from the path + resourcePath = resourcePath.substring(resourcePath.indexOf('/')); + } else { + resourcePath = ""; + } + String messageSymbol = ((Variable) message).getName(); + rootInputAccessor = declareInputAccessorInTheRootResource(messageSymbol, rootInputParams, out, resourcePath, + rootComponent, platformSpec, langSpec); + if (input == null) { + input = rootInputAccessor; + rootInputAccessor = null; + } + } + } + } + + // Add an invocation to the accessor method. + if (mainInputAccessor != null) { + if (platformSpec.hasMain()) { + // For an application with a main component, the reference resource is accessed from the main component. + for (ChannelMember rc: ((DataTransferChannel) ch).getReferenceChannelMembers()) { + // For each reference channel member, get the current state of the reference resource by pull data transfer. + ResourcePath ref = rc.getResource(); + if (!out.getResource().equals(ref)) { + String refVarName = ref.getLeafResourceName(); + Expression refGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(ref, null); + String[] sideEffects = new String[] {""}; + String refExp = refGetter.toImplementation(sideEffects); + String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); + mainInputAccessor.addFirstStatement(sideEffects[0] + langSpec.newVariableDeclaration(ref.getResourceStateType(), refVarName) + + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); + } + } + } + Expression resExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(out.getResource(), null); + List args = new ArrayList<>(); + if (resExp instanceof Term) { + // To access the parent resource if the leaf resource is primitive and cannot declare the input method, or to remove getValue(). + if (((Term) resExp).getChildren().size() > 1 && ((Term) resExp).getChild(1) instanceof Variable) { + args.add(((Variable)((Term) resExp).getChild(1)).getName()); + } + resExp = ((Term) resExp).getChild(0); + } + // Values of channel parameters. + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + if (!args.contains(selVar.getName())) { + args.add(selVar.getName()); + } + } + } + // Values of message parameters. + if (message instanceof Term) { + for (Map.Entry varEnt: message.getVariables().entrySet()) { + String refVarName = null; + for (ChannelMember rc: ((DataTransferChannel) ch).getReferenceChannelMembers()) { + Expression varExp = rc.getStateTransition().getMessageExpression().getSubTerm(varEnt.getKey()); + if (varExp != null && rc.getStateTransition().getCurStateExpression().contains(varExp)) { + refVarName = rc.getResource().getLeafResourceName(); + break; + } + } + if (refVarName != null) { + if (!args.contains(refVarName)) { + args.add(refVarName); + } + } else { + if (!args.contains(varEnt.getValue().getName())) args.add(varEnt.getValue().getName()); + } + } + } + if (resExp != null) { + String resourceAccess = resExp.toImplementation(new String[] {""}); + mainInputAccessor.addStatement(langSpec.getMethodInvocation(resourceAccess, input.getName(), args) + langSpec.getStatementDelimiter()); + } else { + mainInputAccessor.addStatement(langSpec.getMethodInvocation(input.getName(), args) + langSpec.getStatementDelimiter()); + } + } + + if (input != null) { + // Add a statement to update the state field to the input method. + try { + Expression updateExp = ((DataTransferChannel) ch).deriveUpdateExpressionOf(out, getRefAccessor(platformSpec)).getKey(); + // Replace Json constructor with a constructor of a descendant resource. + ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); + if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { + ResourceHierarchy descendantRes = outRes; + Set children = descendantRes.getChildren(); + do { + descendantRes = children.iterator().next(); + if (generatesComponent(descendantRes)) { + inputStatements.put(input, new AbstractMap.SimpleEntry<>(updateExp, new AbstractMap.SimpleEntry<>(outRes, descendantRes))); + updateExp = null; + break; + } + children = descendantRes.getChildren(); + } while (children != null && children.size() == 1); + } + // Add statements to the input method. + if (updateExp != null) { + String[] sideEffects = new String[] {""}; + String newState = updateExp.toImplementation(sideEffects); + ResourceHierarchy resource = resourceNode.getResourceHierarchy(); + if (generatesComponent(resource)) { + String updateStatement; + if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + updateStatement = sideEffects[0]; + if (updateStatement.endsWith("\n")) { + updateStatement = updateStatement.substring(0, updateStatement.length() - 1); + } + } else { + updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); + } + input.addFirstStatement(updateStatement); + } else { + String updateStatement = ""; + if (sideEffects[0] != null) { + updateStatement = sideEffects[0]; + String resourceName = langSpec.toVariableName(getComponentName(resource, langSpec)); + updateStatement = updateStatement.replace(langSpec.getFieldAccessor(fieldOfResourceState), langSpec.getFieldAccessor(resourceName)); + if (updateStatement.endsWith("\n")) { + updateStatement = updateStatement.substring(0, updateStatement.length() - 1); + } + } + if (DataConstraintModel.typeList.isAncestorOf(resourceNode.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); + selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newList = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (DataConstraintModel.typeMap.isAncestorOf(resourceNode.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.insert); + selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); + selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newMap = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (!(updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect())) { + String resourceName = langSpec.toVariableName(getComponentName(resource, langSpec)); + updateStatement += langSpec.getFieldAccessor(resourceName) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); + } + if (updateStatement != null) { + input.addFirstStatement(updateStatement); + } + } + } + if (!platformSpec.hasMain()) { + // For an application with no main component, the reference resource is accessed from each resource. + for (ChannelMember rc: ((DataTransferChannel) ch).getReferenceChannelMembers()) { + // For each reference channel member, get the current state of the reference side resource by pull data transfer. + ResourcePath ref = rc.getResource(); + if (!out.getResource().equals(ref)) { + String refResourceName = ref.getLeafResourceName(); + Type refResourceType = ref.getResourceStateType(); + String[] sideEffects = new String[] {""}; + ResourcePath dstRes = out.getResource(); + if (!generatesComponent(dstRes.getResourceHierarchy())) { + dstRes = dstRes.getParent(); + } + if (!platformSpec.isMonolithic() + && (rc.isOutside() || (ref.getCommonPrefix(dstRes) == null && platformSpec.isDifferentTreesAsDifferentServices()))) { + List pathParams = new ArrayList<>(); + for (Expression pathExp: ref.getPathParams()) { + pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + generatePullDataTransfer(input, null, refResourceName, ref.getResourceHierarchy().toResourcePath(pathParams), refResourceType, true, platformSpec, langSpec); + if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); + } else if (parentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); + } + } else { + Expression refGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(ref, dstRes); + String refExp = refGetter.toImplementation(sideEffects); + String refTypeName = refResourceType.getInterfaceTypeName(); + input.addFirstStatement(sideEffects[0] + langSpec.newVariableDeclaration(refResourceType, refResourceName) + + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); + } + } + } + } + + if (rootInputAccessor != null) { + // In the root resource + // The expression of the receiver (resource) of the input method. + ResourcePath outResPath = new ResourcePath(out.getResource()); + for (int i = 0; i < outResPath.getPathParams().size(); i++) { + Parameter pathParam = new Parameter(rootInputAccessor.getParameters().get(i).getName()); + outResPath.replacePathParam(i, pathParam, null); + } + Expression resExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(outResPath, outResPath.getRoot()); + List args = new ArrayList<>(); + if (resExp instanceof Term) { + // To access the parent resource if the leaf resource is primitive and cannot declare the input method, or to remove getValue(). + if (((Term) resExp).getChildren().size() > 1 && ((Term) resExp).getChild(1) instanceof Variable) { + args.add(((Variable)((Term) resExp).getChild(1)).getName()); + } + resExp = ((Term) resExp).getChild(0); + } + // Values of channel parameters. + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + args.add(selVar.getName()); + } + } + // Values of message parameters. + if (message instanceof Term) { + for (Variable mesVar: message.getVariables().values()) { + args.add(mesVar.getName()); + } + } + if (resExp != null) { + String resourceAccess = resExp.toImplementation(new String[] {""}); + rootInputAccessor.addStatement(langSpec.getMethodInvocation(resourceAccess, input.getName(), args) + langSpec.getStatementDelimiter()); + } else { + rootInputAccessor.addStatement(langSpec.getMethodInvocation(input.getName(), args) + langSpec.getStatementDelimiter()); + } + if (input != null && input.getThrows() != null && ((RestApiSpecific) platformSpec).hasJsonException(input)) { + ((RestApiSpecific) platformSpec).addJsonException(rootInputAccessor); + } + } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + + // Add an invocation to an update method (for a chain of update method invocations). + boolean hasUpdateMethodinvoked = false; + for (Edge resToCh: resourceNode.getOutEdges()) { + DataFlowEdge dOut = (DataFlowEdge) resToCh; + ChannelNode directDstChNode = (ChannelNode) resToCh.getDestination(); + DataTransferChannel directDstCh = directDstChNode.getChannel(); + // Check if the input resource is outside of the channel scope. + boolean outsideInputResource2 = false; + ChannelMember in = null; + Set outsideInputMembers2 = new HashSet<>(); + for (ChannelMember cm: directDstCh.getInputChannelMembers()) { + if (resourceNode.getOutSideResources().contains(cm.getResource())) { + if (cm.isOutside()) { + outsideInputResource2 = true; // Regarded as pull transfer. + } + in = cm; + } + if (cm.isOutside()) { + outsideInputMembers2.add(cm); + } + } + // Should take into account the channel hierarchy. + Set ancestorDstChannels = directDstChNode.getAncestors(); + Set descendantDstChannels = directDstChNode.getDescendants(); + Set outEdges = new HashSet<>(); + outEdges.addAll(directDstChNode.getOutEdges()); + for (ChannelNode ancestorDst: ancestorDstChannels) { + outEdges.addAll(ancestorDst.getOutEdges()); + } + for (ChannelNode descendantDst: descendantDstChannels) { + outEdges.addAll(descendantDst.getOutEdges()); + } + // Calculate in-degree (PUSH transfer) of the destination resource. + Set inEdges = new HashSet<>(); + inEdges.addAll(directDstChNode.getInEdges()); + for (ChannelNode ancestorSrc: ancestorDstChannels) { + inEdges.addAll(ancestorSrc.getInEdges()); + } + for (ChannelNode descendantSrc: descendantDstChannels) { + inEdges.addAll(descendantSrc.getInEdges()); + } + int inDegree = 0; + for (Edge resToCh2: inEdges) { + DataFlowEdge df =(DataFlowEdge) resToCh2; + if (((PushPullAttribute) df.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { + inDegree++; + } + } + for (Edge chToRes: outEdges) { + // For each data transfer to dstNode:ResourceNode. + ResourceNode dstNode = ((ResourceNode) chToRes.getDestination()); + ChannelNode chNode2 = (ChannelNode) chToRes.getSource(); + DataTransferChannel ch2 = chNode2.getChannel(); + // Check if the output resource is outside of the channel scope. + boolean outsideOutputResource2 = false; + ChannelMember out2 = null; + for (ChannelMember cm: ch2.getOutputChannelMembers()) { + if (dstNode.getInSideResources().contains(cm.getResource())) { + out2 = cm; + if (cm.isOutside()) { + outsideOutputResource2 = true; + break; + } + } + } + // Also take into account the channel hierarchy to determine push/pull transfer. + if (descendantDstChannels.contains(chNode2)) { + outsideOutputResource2 = true; // Regarded as (broadcasting) push transfer. + } + if (ancestorDstChannels.contains(chNode2)) { + outsideInputResource2 = true; // Regarded as (collecting) pull transfer. + } + if ((((PushPullAttribute) dOut.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource2) || outsideOutputResource2) { + // PUSH transfer + Block forLoopBlock = input.getBody(); + if (descendantDstChannels.contains(chNode2)) { + // For hierarchical channels (broadcasting push transfer). + if (ch2.getSelectors() != null && ch2.getSelectors().size() > 0) { + Expression selExp = ch2.getSelectors().get(0).getExpression(); + Type selType = null; + if (selExp instanceof Variable) { + selType = ((Variable) selExp).getType(); + String forVarName = ((Variable) selExp).getName(); + ChannelMember insideChMem = null; + for (ChannelMember cm :ch2.getInputChannelMembers()) { + if (!cm.isOutside()) { + insideChMem = cm; + break; + } + } + if (insideChMem == null) { + for (ChannelMember cm :ch2.getReferenceChannelMembers()) { + if (!cm.isOutside()) { + insideChMem = cm; + break; + } + } + } + if (insideChMem == null) { + for (ChannelMember cm :ch2.getOutputChannelMembers()) { + if (!cm.isOutside()) { + insideChMem = cm; + break; + } + } + } + ResourcePath insideResPath = insideChMem.getResource(); + while (insideResPath.getParent() != null && (insideResPath.getLastParam() == null || !insideResPath.getLastParam().equals(selExp))) { + insideResPath = insideResPath.getParent(); + } + insideResPath = insideResPath.getParent(); + if (insideResPath != null) { + String parent = null; + if (platformSpec.isMonolithic() + || insideResPath.getCommonPrefix(resourceNode.getOutSideResource(directDstCh)) != null + || !platformSpec.isDifferentTreesAsDifferentServices()) { + if (!platformSpec.isMonolithic() && generatesComponent(insideResPath.getResourceHierarchy())) { + Expression getter = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, resourceNode.getOutSideResource(directDstCh)); + Term valueGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); + valueGetter.addChild(getter); + parent = valueGetter.toImplementation(new String[] {""}); + } else { + parent = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, resourceNode.getOutSideResource(directDstCh)).toImplementation(new String[] {""}); + } + } else { + // for REST API + parent = langSpec.toVariableName(getComponentName(insideResPath.getResourceHierarchy(), langSpec)); + } + if (selType.equals(DataConstraintModel.typeInt)) { + // make a for loop (for a list) for broadcasting. + ForStatement forLoopToCollectData = langSpec.getForStatementForList(forVarName, parent); + forLoopBlock = new Block(); + forLoopToCollectData.setBody(forLoopBlock); + input.addStatement(forLoopToCollectData); + } else if (selType.equals(DataConstraintModel.typeString)) { + // make a for loop (for a map) for broadcasting. + EnhancedForStatement forLoopToCollectData = langSpec.getForStatementForMap(forVarName, parent); + forLoopBlock = new Block(); + forLoopToCollectData.setBody(forLoopBlock); + input.addStatement(forLoopToCollectData); + } + if (!platformSpec.isMonolithic() + && insideResPath.getCommonPrefix(resourceNode.getOutSideResource(directDstCh)) == null + && platformSpec.isDifferentTreesAsDifferentServices()) { + // for REST API + Type parentResType = insideResPath.getResourceStateType(); + String parentResName = langSpec.toVariableName(getComponentName(insideResPath.getResourceHierarchy(), langSpec)); + String parentResPath = insideResPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); + generatePullDataTransfer(input, forLoopBlock, parentResName, parentResPath, parentResType, true, platformSpec, langSpec); + if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); + } else if (parentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); + } + } + } + } else if (selExp instanceof Term) { + // not supported. + } + } + } + // Get the value of reference member to call the update method. + List>> refParams = new ArrayList<>(); + Map> referredResources = new HashMap<>(); + Set referredSet = referredResources.get(input); + for (ChannelMember rc: ch2.getReferenceChannelMembers()) { + ResourcePath ref = rc.getResource(); + if (referredSet == null) { + referredSet = new HashSet<>(); + referredResources.put(input, referredSet); + } + if (!resourceNode.getOutSideResources().contains(ref)) { + String refVarName = langSpec.toVariableName(getComponentName(ref.getResourceHierarchy(), langSpec)); + if (!referredSet.contains(ref)) { + referredSet.add(ref); + ResourcePath srcRes = in.getResource(); + if (!generatesComponent(srcRes.getResourceHierarchy())) { + srcRes = srcRes.getParent(); + } + Expression refGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(ref, srcRes); + String[] sideEffects = new String[] {""}; + String refExp = refGetter.toImplementation(sideEffects); + String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); + forLoopBlock.addStatement(sideEffects[0] + langSpec.newVariableDeclaration(ref.getResourceStateType(), refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); + } + refParams.add(new AbstractMap.SimpleEntry<>(ref.getResourceStateType(), + new AbstractMap.SimpleEntry<>(refVarName, + refVarName))); + } + } + // Add an update method invocation. + hasUpdateMethodinvoked = addUpdateMethodInvocation(resourceNode, dstNode, input, forLoopBlock, refParams, + ch2, in, out2, inDegree, outsideOutputResource2, hasUpdateMethodinvoked); + } + } + + // Add an invocation to output native event channel. + if (directDstCh.isNative() && platformSpec.isMonolithic()) { + addNativeMethodInvocation(resourceNode, presenter, input, ((DataTransferChannel) ch), directDstCh, out, in); + if (component != null) { + component.addField(langSpec.newFieldDeclaration(presenterType, presenter)); + } else if (parentComponent != null) { + parentComponent.addField(langSpec.newFieldDeclaration(presenterType, presenter)); + } + Map nameToParam = constructorParams.getOrDefault(resourceNode.getResourceHierarchy(), new HashMap<>()); + nameToParam.put(presenter,langSpec.newVariableDeclaration(presenterType, presenter)); + constructorParams.put(resourceNode.getResourceHierarchy(), nameToParam); + } + + // Update and initialize a field to refer to an outside input resource for PULL transfer. + if (platformSpec.isMonolithic()) { + // For a monolithic application. + if (outsideInputMembers2.size() > 0) { + if (!generatesComponent(resourceNode.getResourceHierarchy())) { + ResourcePath srcRes2 = resourceNode.getOutSideResource(directDstCh); + for (ChannelMember out2: directDstCh.getOutputChannelMembers()) { + if (!generatesComponent(out2.getResource().getResourceHierarchy())) { + ResourcePath dstRes2 = out2.getResource(); + if (srcRes2.getParent().equals(dstRes2.getParent())) { + Map>> resourcePaths = null; + try { + resourcePaths = directDstCh.fillOutsideResourcePaths(out2, getPullAccessor(platformSpec)); + if (resourcePaths != null && resourcePaths.size() > 0) { + for (ChannelMember outsideMember: outsideInputMembers2) { + for (ChannelMember dependedMember: resourcePaths.get(outsideMember).getValue()) { + if (dependedMember.getResource().equals(srcRes2)) { + // An outside input resource path depends on srcRes. + ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); + if (!generatesComponent(outsidePath.getResourceHierarchy())) { + outsidePath = outsidePath.getParent(); + } + String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); + Expression outsideExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(outsidePath, null); + if (generatesComponent(outsidePath.getResourceHierarchy())) { + outsideExp = ((Term) outsideExp).getChild(0); + } + String[] sideEffects = new String[] {""}; + String outsideAccessor = outsideExp.toImplementation(sideEffects); + input.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. + // Update constructor. + String initializingStatement = langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter(); + if (component != null) { + MethodDeclaration constructor = getConstructor(component); + constructor.addStatement(initializingStatement); // initialize the reference field. + } else { + constructorStatements.add(initializingStatement); // initialize the reference field. + } + } + } + } + } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + } + } + } + } + } + } + } + } + } + } + } + return new AbstractMap.SimpleEntry<>(constructorStatements, inputStatements); + } + + private boolean addUpdateMethodInvocation(ResourceNode srcNode, ResourceNode dstNode, + MethodDeclaration callerMethod, Block callerBlock, List>> refParams, + DataTransferChannel ch, ChannelMember in, ChannelMember out, int inDegree, boolean outsideOutputResource, boolean hasUpdateMethodinvoked) { + if (callerBlock == null) { + callerBlock = callerMethod.getBody(); + } + List>> pathParams = new ArrayList<>(); + if (platformSpec.isMonolithic()) { + // Update fields to refer to outside resources. + ResourcePath filledOutsideResourcePath = null; + try { + Map>> resourcePaths = ch.fillOutsideResourcePaths(out, getPullAccessor(platformSpec)); + if (resourcePaths != null && resourcePaths.size() > 0) { + for (ChannelMember outsideMember: resourcePaths.keySet()) { + ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); + if (out.equals(outsideMember)) { + filledOutsideResourcePath = outsidePath; + } + if (!generatesComponent(outsidePath.getResourceHierarchy())) { + outsidePath = outsidePath.getParent(); + } + String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); + Expression outsideExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(outsidePath, null); + if (generatesComponent(outsidePath.getResourceHierarchy())) { + outsideExp = ((Term) outsideExp).getChild(0); + } + if (outsideExp instanceof Field) { + outsideExp = new Variable(((Field) outsideExp).getSymbol().getName(), ((Field) outsideExp).getType()); + } else if (outsideExp instanceof Term) { + for (Entry fieldEnt: ((Term) outsideExp).getSubTerms(Field.class).entrySet()) { + Position pos = fieldEnt.getKey(); + Field field = fieldEnt.getValue(); + Variable var = new Variable(field.getSymbol().getName(), field.getType()); + ((Term) outsideExp).replaceSubTerm(pos, var); + } + } + String[] sideEffects = new String[] {""}; + String outsideAccessor = outsideExp.toImplementation(sideEffects); + callerBlock.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. + } + } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + // Values of path parameters to call the update method. + if (filledOutsideResourcePath == null) { + filledOutsideResourcePath = out.getResource(); + } + for (Expression pathParam: filledOutsideResourcePath.getPathParams()) { + if (pathParam instanceof Variable) { + Variable pathVar = (Variable) pathParam; + pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), + new AbstractMap.SimpleEntry<>(pathVar.getName(), + pathVar.getName()))); + } else if (pathParam instanceof Constant) { + Constant pathVar = (Constant) pathParam; + pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), + new AbstractMap.SimpleEntry<>(pathVar.getSymbol().getName(), + pathVar.getSymbol().getName()))); + } + } + } else { + // Values of path parameters to call the update method. + for (Expression pathParam: out.getResource().getPathParams()) { + if (pathParam instanceof Variable) { + Variable pathVar = (Variable) pathParam; + pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), + new AbstractMap.SimpleEntry<>(pathVar.getName(), + pathVar.getName()))); + } + } + } + // Values of channel parameters to call the update method. + List>> params = new ArrayList<>(); + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + params.add(new AbstractMap.SimpleEntry<>(selVar.getType(), + new AbstractMap.SimpleEntry<>(selVar.getName(), + selVar.getName()))); + } + } + // Value of the source side (input side) resource to call the update method. + ResourceHierarchy srcRes = srcNode.getResourceHierarchy(); + if (generatesComponent(srcRes)) { + params.add(new AbstractMap.SimpleEntry<>(srcRes.getResourceStateType(), + new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes.getResourceName()), + langSpec.getFieldAccessor(fieldOfResourceState)))); + } else { + params.add(new AbstractMap.SimpleEntry<>(srcRes.getResourceStateType(), + new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes.getResourceName()), + langSpec.getFieldAccessor(langSpec.toVariableName(srcRes.getResourceName()))))); + srcRes = srcRes.getParent(); + } + params.addAll(refParams); + + // Create a guard condition. + Term guardCondition = null; + for (Map.Entry paramEnt: in.getResource().getPathParamsAndConstraints()) { + if (paramEnt.getValue() != null) { + Term newCondition = new Term(DataConstraintModel.eq); + newCondition.addChild(paramEnt.getKey(), true); + newCondition.addChild(paramEnt.getValue(), true); + if (guardCondition == null) { + guardCondition = newCondition; + } else { + Term composedCondition = new Term(DataConstraintModel.and); + composedCondition.addChild(guardCondition, true); + composedCondition.addChild(newCondition, true); + guardCondition = composedCondition; + } + } + } + + // Call the update method. + ResourceHierarchy dstRes = dstNode.getResourceHierarchy(); + String updateMethodName = getUpdateMethodName(srcNode.getResourceHierarchy(), dstRes, ch); // Get the method name. + if (!generatesComponent(dstRes)) { + dstRes = dstRes.getParent(); + } + String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); + if (outsideOutputResource + || (!platformSpec.isMonolithic() && in.getResource().getCommonPrefix(out.getResource()) == null && platformSpec.isDifferentTreesAsDifferentServices())) { + // Inter-servces + if (!platformSpec.isMonolithic()) { + // REST API + RestApiSpecific restApiSpec = (RestApiSpecific) platformSpec; + String httpMethod = null; + if (out.getStateTransition().isRightUnary()) { + httpMethod = "put"; + } else { + httpMethod = "post"; + } + String[] sideEffects = new String[] {""}; + List pathParamsUrl = new ArrayList<>(); + for (Expression pathExp: out.getResource().getPathParams()) { + pathParamsUrl.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + String srcResName = langSpec.toVariableName(getComponentName(srcNode.getResourceHierarchy(), langSpec)); + if (inDegree <= 1) { + srcResName = null; + } + Map>> filledPaths = null; + try { + filledPaths = ch.fillOutsideResourcePaths(out, getPushAccessor(platformSpec)); + } catch (ParameterizedIdentifierIsFutureWork + | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage + | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + String dstPath = null; + if (filledPaths != null && filledPaths.get(out) != null) { + ResourcePath filledDstPath = filledPaths.get(out).getKey(); + dstPath = filledDstPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); + } else { + dstPath = dstRes.toResourcePath(pathParamsUrl); + } + // Call the update method. + TypeDeclaration srcComponent = null; + TypeDeclaration srcParentComponent = null; + if (generatesComponent(srcRes)) { + srcComponent = generationContext.getComponent(srcRes); + } else if (srcRes.getParent() != null) { + srcParentComponent = generationContext.getComponent(srcRes.getParent()); + } + if (!hasUpdateMethodinvoked) { + // The first call to an update method in this method + callerBlock.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, true)); + String httpMethodCall = langSpec.newVariableDeclaration(DataConstraintModel.typeString, "result") + + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, srcResName, httpMethod); + if (guardCondition == null) { + // Non-conditional http method call. + callerBlock.addStatement(httpMethodCall); + } else { + // Conditional http method call by a guarded state transition. + Block ifBlock = new Block(); + ifBlock.addStatement(httpMethodCall); + callerBlock.addStatement(langSpec.getIfStatement(guardCondition, ifBlock)); + } + if (srcComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcComponent); + } else if (srcParentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcParentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcParentComponent); + } + if (!((RestApiSpecific) platformSpec).hasJsonException(callerMethod)) { + ((RestApiSpecific) platformSpec).addJsonException(callerMethod); + } + hasUpdateMethodinvoked = true; + } else { + // After the second time of call to update methods in this method + callerBlock.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, false)); + String httpMethodCall = "result" + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, srcResName, httpMethod); + if (guardCondition == null) { + // Non-conditional http method call. + callerBlock.addStatement(httpMethodCall); + } else { + // Conditional http method call by a guarded state transition. + Block ifBlock = new Block(); + ifBlock.addStatement(httpMethodCall); + callerBlock.addStatement(langSpec.getIfStatement(guardCondition, ifBlock)); + } + if (srcComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcComponent); + } else if (srcParentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcParentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcParentComponent); + } + if (!((RestApiSpecific) platformSpec).hasJsonException(callerMethod)) { + ((RestApiSpecific) platformSpec).addJsonException(callerMethod); + } + } + } else { + // Use the reference field to refer to outside destination resource. + List args = new ArrayList<>(); + for (Map.Entry> paramEnt: pathParams) { + args.add(paramEnt.getValue().getValue()); + } + for (Map.Entry> paramEnt: params) { + args.add(paramEnt.getValue().getValue()); + } + String methodInvocation = null; + methodInvocation = langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) + + langSpec.getStatementDelimiter(); // this.dst.updateDstFromSrc(value, refParams); + if (guardCondition == null) { + // Non-conditional invocation. + callerBlock.addStatement(methodInvocation); + } else { + // Conditional invocation by a guarded state transition. + Block ifBlock = new Block(); + ifBlock.addStatement(methodInvocation); + callerBlock.addStatement(langSpec.getIfStatement(guardCondition, ifBlock)); + } + } + } else { + // Intra-service + // The destination resource is not outside. + List args = new ArrayList<>(); + for (Map.Entry> paramEnt: pathParams) { + args.add(paramEnt.getValue().getValue()); + } + for (Map.Entry> paramEnt: params) { + args.add(paramEnt.getValue().getValue()); + } + String methodInvocation = null; + if (srcRes != dstRes) { + methodInvocation = langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) + + langSpec.getStatementDelimiter(); // this.dst.updateDstFromSrc(value, refParams); + } else { + methodInvocation = langSpec.getMethodInvocation(updateMethodName, args) + + langSpec.getStatementDelimiter(); // this.updateDstFromSrc(value, refParams); + } + if (guardCondition == null) { + // Non-conditional invocation. + callerBlock.addStatement(methodInvocation); + } else { + // Conditional invocation by a guarded state transition. + Block ifBlock = new Block(); + ifBlock.addStatement(methodInvocation); + callerBlock.addStatement(langSpec.getIfStatement(guardCondition, ifBlock)); + } + } + return hasUpdateMethodinvoked; + } + + private void addNativeMethodInvocation(ResourceNode srcNode, String receiverName, MethodDeclaration callerMethod, + DataTransferChannel inCh, DataTransferChannel ch, ChannelMember out, ChannelMember in) { + // Values of channel parameters to call the update method. + List>> params = new ArrayList<>(); + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + params.add(new AbstractMap.SimpleEntry<>(selVar.getType(), + new AbstractMap.SimpleEntry<>(selVar.getName(), + selVar.getName()))); + } + } + // Call the native method. + try { + List args = new ArrayList<>(); + for (Map.Entry> paramEnt: params) { + args.add(paramEnt.getValue().getValue()); + } + IResourceStateAccessor resouceStateAccessor = new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + return getPushAccessor(platformSpec).getCurrentStateAccessorFor(out, out); + } + + @Override + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + try { + return inCh.deriveUpdateExpressionOf(out, getPushAccessor(platformSpec)).getKey(); + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + return getPushAccessor(platformSpec).getNextStateAccessorFor(out, out); + } + } + + @Override + public Expression getDirectStateAccessorFor(ResourcePath target, ResourcePath from) { + return getPushAccessor(platformSpec).getDirectStateAccessorFor(target, from); + } + }; + Map> substitutedPositionsInMessageFromChannels = new HashMap<>(); + Expression message = ch.calcMessageConstraintForInputMember(in, in, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + if (message instanceof Term) { + String updateMethodName = ((Term) message).getSymbol().getName(); + for (Expression messageArg: ((Term) message).getChildren()) { + args.add(messageArg.toImplementation(new String[] {null})); + } + callerMethod.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(receiverName), updateMethodName, args) + + langSpec.getStatementDelimiter()); + } + } catch (ResolvingMultipleDefinitionIsFutureWork | InvalidMessage e) { + } + } + + protected MethodDeclaration getOrDeclareUpdateMethod(ResourceHierarchy srcRes, ResourceHierarchy dstRes, DataTransferChannel ch, ArrayList parameters) { + MethodDeclaration update = null; + String updateMethodName = getUpdateMethodName(srcRes, dstRes, ch); + if (generatesComponent(dstRes)) { + // A component is created for this resource. + TypeDeclaration dstComponent = generationContext.getComponent(dstRes); + for (MethodDeclaration method: dstComponent.getMethods()) { + if (method.getName().equals(updateMethodName)) { + update = method; + break; + } + } + if (update == null) { + update = langSpec.newMethodDeclaration(updateMethodName, false, null, parameters); + dstComponent.addMethod(update); + } + } else if (dstRes.getParent() != null) { + // No component is created for this resource. + TypeDeclaration dstParentComponent = generationContext.getComponent(dstRes.getParent()); + for (MethodDeclaration method: dstParentComponent.getMethods()) { + if (method.getName().equals(updateMethodName)) { + update = method; + break; + } + } + if (update == null) { + update = langSpec.newMethodDeclaration(updateMethodName, false, null, parameters); + dstParentComponent.addMethod(update); + } + } + return update; + } + + protected void declareGetterAccessorInTheRootResource(ResourceNode resourceNode, TypeDeclaration rootComponent) { + if (resourceNode.getResourceHierarchy().getParent() != null) { + // For a non-root resource + MethodDeclaration getterAccessor = null; + List mainGetterParams = new ArrayList<>(); + String resourcePath = getGetterResourcePathAndPathParams(resourceNode.getPrimaryResourcePath(), mainGetterParams, platformSpec, langSpec); + if (resourcePath.indexOf('/') > 0) { + // Remove the root resource from the path + resourcePath = resourcePath.substring(resourcePath.indexOf('/')); + } else { + resourcePath = ""; + } + if (mainGetterParams.size() > 0) { + getterAccessor = langSpec.newMethodDeclaration(getterPrefix + getComponentName(resourceNode.getResourceHierarchy(), langSpec) + methoNameOfResourceState, + false, + getImplStateType(resourceNode.getResourceHierarchy(), langSpec), + mainGetterParams); + } else { + getterAccessor = langSpec.newMethodDeclaration(getterPrefix + getComponentName(resourceNode.getResourceHierarchy(), langSpec) + methoNameOfResourceState, + getImplStateType(resourceNode.getResourceHierarchy(), langSpec)); + } + getterAccessor.setBody(new Block()); + ResourcePath resPath = new ResourcePath(resourceNode.getPrimaryResourcePath()); + for (int i = 0; i < mainGetterParams.size(); i++) { + Parameter pathParam = new Parameter(mainGetterParams.get(i).getName()); + resPath.replacePathParam(i, pathParam, null); + } + Expression getState = getPullAccessor(platformSpec).getDirectStateAccessorFor(resPath, resPath.getRoot()); + getterAccessor.getBody().addStatement(langSpec.getReturnStatement(getState.toImplementation(new String[] {null}))); + if (!platformSpec.isMonolithic()) { + ((RestApiSpecific) platformSpec).addGetAnnotations(getterAccessor); + if (resourcePath.length() > 0) { + ((RestApiSpecific) platformSpec).addPathAnnotation(getterAccessor, resourcePath); + } + } + rootComponent.addMethod(getterAccessor); + } + } + + protected void declareUpdateAccessorInTheRootResource(ResourceNode resourceNode, String updateMethodName, + DataTransferChannel ch, ChannelMember cm, ResourcePath srcResPath, ResourcePath dstResPath, TypeDeclaration rootComponent, + int inDegree, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + ArrayList parameters; + VariableDeclaration param; + parameters = new ArrayList<>(); + String resourcePath = getUpdateResourcePathAndPathParams(dstResPath, parameters, true, platformSpec, langSpec); // Path parameters to identify the self resource. + if (resourcePath.indexOf('/') > 0) { + // Remove the root resource from the path + resourcePath = resourcePath.substring(resourcePath.indexOf('/')); + } else { + resourcePath = ""; + } + ResourcePath resPath = new ResourcePath(dstResPath); + for (int i = 0; i < parameters.size(); i++) { + Parameter pathParam = new Parameter(parameters.get(i).getName()); + resPath.replacePathParam(i, pathParam, null); + } + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + VariableDeclaration chParam = langSpec.newVariableDeclaration(selVar.getType(), selVar.getName()); + if (!platformSpec.isMonolithic()) { + ((RestApiSpecific) platformSpec).addFormParamAnnotation(chParam, selVar.getName()); + } + parameters.add(chParam); // A channel parameter to specify the context of the collaboration. + } + } + Type srcType = srcResPath.getResourceStateType(); + String srcResName = langSpec.toVariableName(getComponentName(srcResPath.getResourceHierarchy(), langSpec)); + param = langSpec.newVariableDeclaration(srcType, srcResName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addFormParamAnnotation(param, srcResName); + parameters.add(param); // The state of the source resource to carry the data-flow. + for (ResourcePath refRes: ch.getReferenceResources()) { + if (!refRes.equals(resourceNode.getInSideResource(ch))) { + String refName = langSpec.toVariableName(getComponentName(refRes.getResourceHierarchy(), langSpec)); + param = langSpec.newVariableDeclaration(refRes.getResourceStateType(), refName); + if (!platformSpec.isMonolithic()) { + ((RestApiSpecific) platformSpec).addFormParamAnnotation(param, refName); + } + parameters.add(param); + } + } + MethodDeclaration updateAccessor = langSpec.newMethodDeclaration(updateMethodName, false, null, parameters); + if (!platformSpec.isMonolithic()) { + if (isPut(cm)) { + ((RestApiSpecific) platformSpec).addPutAnnotations(updateAccessor); + } else { + if (!isDelete(cm)) { + ((RestApiSpecific) platformSpec).addPostAnnotations(updateAccessor); + } else { + ((RestApiSpecific) platformSpec).addDeleteAnnotations(updateAccessor); + } + } + } + if (inDegree > 1) { + // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. + resourcePath += "/" + langSpec.toVariableName(srcResName); + } + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathAnnotation(updateAccessor, resourcePath); + + // To make the accessor call the update method. + Expression resExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(resPath, resPath.getRoot()); + List args = new ArrayList<>(); + if (resExp instanceof Term) { + // To access the parent resource if the leaf resource is primitive and cannot declare the update method, or to remove getValue(). + if (((Term) resExp).getChildren().size() > 1 && ((Term) resExp).getChild(1) instanceof Variable) { + args.add(((Variable)((Term) resExp).getChild(1)).getName()); + } + resExp = ((Term) resExp).getChild(0); + } + for (VariableDeclaration var: updateAccessor.getParameters()) { + args.add(var.getName()); + } + if (resExp != null) { + String resourceAccess = resExp.toImplementation(new String[] {""}); + updateAccessor.addStatement(langSpec.getMethodInvocation(resourceAccess, updateMethodName, args) + langSpec.getStatementDelimiter()); + } else { + updateAccessor.addStatement(langSpec.getMethodInvocation(updateMethodName, args) + langSpec.getStatementDelimiter()); + } + rootComponent.addMethod(updateAccessor); + } + + protected MethodDeclaration declareInputAccessorInTheRootResource(String inputMethodName, + ArrayList rootInputParams, ChannelMember cm, String resourcePath, + TypeDeclaration rootComponent, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + MethodDeclaration rootInputAccessor; + rootInputAccessor = langSpec.newMethodDeclaration(inputMethodName, false, null, rootInputParams); + if (!platformSpec.isMonolithic()) { + if (isPut(cm)) { + ((RestApiSpecific) platformSpec).addPutAnnotations(rootInputAccessor); + } else { + if (!isDelete(cm)) { + ((RestApiSpecific) platformSpec).addPostAnnotations(rootInputAccessor); + } else { + ((RestApiSpecific) platformSpec).addDeleteAnnotations(rootInputAccessor); + } + } + if (resourcePath.length() > 0) { + ((RestApiSpecific) platformSpec).addPathAnnotation(rootInputAccessor, resourcePath); + } + } + rootComponent.addMethod(rootInputAccessor); + return rootInputAccessor; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/DataTransferMethodAnalyzer.java b/AlgebraicDataflowArchitectureModel/src/generators/DataTransferMethodAnalyzer.java index 8e68103..d15f6ad 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/DataTransferMethodAnalyzer.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/DataTransferMethodAnalyzer.java @@ -15,7 +15,7 @@ * */ public class DataTransferMethodAnalyzer { - static private HashSet reachableNodes = new HashSet<>(); + static private HashSet reachableNodes = new HashSet<>(); /** * Determine whether each resource state is stored or not depending on selected data transfer methods. @@ -24,7 +24,7 @@ */ static public void decideToStoreResourceStates(DataFlowGraph graph) { reachableNodes.clear(); - for (Node n : graph.getNodes()) { + for (ResourceNode n: graph.getResourceNodes()) { ResourceNode resource = (ResourceNode) n; trackNode(resource); } @@ -35,11 +35,13 @@ return; reachableNodes.add(resource); boolean flag = true; - for (Edge e : resource.getInEdges()) { - if (((PushPullAttribute) e.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { - // Traverse pull edges only. - trackNode((ResourceNode) e.getSource()); - flag = false; + for (Edge chToRes: resource.getInEdges()) { + for (Edge resToCh: chToRes.getSource().getInEdges()) { + if (((PushPullAttribute) resToCh.getAttribute()).getSelectedOption() != PushPullValue.PUSH) { + // Traverse pull edges only. + trackNode((ResourceNode) resToCh.getSource()); + flag = false; + } } } ((StoreAttribute) resource.getAttribute()).setStored(flag); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java new file mode 100644 index 0000000..2dfe533 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java @@ -0,0 +1,61 @@ +package generators; + +import java.util.List; + +import code.ast.*; +import models.algebra.Term; +import models.algebra.Type; +import models.dataConstraintModel.JsonType; +import models.dataConstraintModel.ListType; +import models.dataConstraintModel.MapType; +import models.dataConstraintModel.TupleType; + +public interface ILanguageSpecific { + CompilationUnit newCompilationUnit(TypeDeclaration component); + TypeDeclaration newTypeDeclaration(String typeName); + VariableDeclaration newVariableDeclaration(Type type, String varName); + MethodDeclaration newMethodDeclaration(String methodName, Type returnType); + MethodDeclaration newMethodDeclaration(String methodName, boolean isConstructor, Type returnType, List parameters); + FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName); + FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName, String fieldInitializer); + ListType newListType(Type compType); + ListType newListType(Type compType, Type parentListType); + MapType newMapType(Type keyType, String compTypeName); + MapType newMapType(Type keyType, String compTypeName, Type parentMapType); + MapType newMapType(Type keyType, Type valueType); + MapType newMapType(Type keyType, Type valueType, Type parentMapType); + TupleType newTupleType(List compTypes); + TupleType newTupleType(List componentTypes, Type parentTupleType); + JsonType newJsonType(); + JsonType newJsonType(Type parentJsonType); + boolean declareField(); + String getSelfExp(); + String getFieldAccessor(String fieldName); + String getMethodInvocation(String methodName); + String getMethodInvocation(String receiverName, List parameters); + String getMethodInvocation(String receiverName, String methodName); + String getMethodInvocation(String receiverName, String methodName, List parameters); + String getConstructorInvocation(String componentName, List parameters); + ReturnStatement getReturnStatement(String returnValue); + IfStatement getIfStatement(Term condition, Statement block); + ForStatement getForStatementForList(String varName, String list); + EnhancedForStatement getForStatementForCollection(VariableDeclaration varDeclaration, String collection); + EnhancedForStatement getForStatementForMap(String varName, String map); + String toComponentName(String name); + String toVariableName(String name); + String getMainComponentName(); + String getAssignment(); + String getStatementDelimiter(); + String getStringDelimiter(); + String getOpeningScoreDelimiter(); + String getClosingScoreDelimiter(); + String getValueToStringExp(String typeName, String valueExp); + String getStringToValueExp(String typeName, String strExp); + String getPairExp(String first, String second); + String getFirstEntryFromMapExp(String map); + String getTupleGet(String tupleExp, int idx, int length); + String getDecomposedTuple(String tupleExp, VariableDeclaration tupleVar, List vars); + boolean isValueType(Type type); + boolean isVoidType(Type type); + Type getWrapperType(Type type); +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/IPlatformSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/IPlatformSpecific.java new file mode 100644 index 0000000..c609b7a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/IPlatformSpecific.java @@ -0,0 +1,9 @@ +package generators; + +import java.util.List; + +public interface IPlatformSpecific { + boolean hasMain(); + boolean isMonolithic(); + boolean isDifferentTreesAsDifferentServices(); +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java deleted file mode 100644 index 314e81a..0000000 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ /dev/null @@ -1,475 +0,0 @@ -package generators; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - - -import code.ast.Block; -import code.ast.CompilationUnit; -import code.ast.FieldDeclaration; -import code.ast.ImportDeclaration; -import code.ast.MethodDeclaration; -import code.ast.TypeDeclaration; -import code.ast.VariableDeclaration; -import models.Edge; -import models.Node; -import models.algebra.Expression; -import models.algebra.Field; -import models.algebra.Parameter; -import models.algebra.Symbol; -import models.algebra.Term; -import models.algebra.Type; -import models.algebra.Variable; -import models.dataConstraintModel.Channel; -import models.dataConstraintModel.ChannelMember; -import models.dataConstraintModel.DataConstraintModel; -import models.dataConstraintModel.ResourcePath; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.DataTransferChannel; -import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; -import models.dataFlowModel.PushPullAttribute; -import models.dataFlowModel.PushPullValue; -import models.dataFlowModel.DataFlowEdge; -import models.dataFlowModel.DataFlowGraph; -import models.dataFlowModel.ResourceNode; -import models.dataFlowModel.StoreAttribute; - -/** - * Generator for plain Java prototypes - * - * @author Nitta - * - */ -public class JavaCodeGenerator { - public static final Type typeVoid = new Type("Void", "void"); - private static String defaultMainTypeName = "Main"; - static String mainTypeName = defaultMainTypeName; - - public static String getMainTypeName() { - return mainTypeName; - } - - public static void setMainTypeName(String mainTypeName) { - JavaCodeGenerator.mainTypeName = mainTypeName; - } - - public static void resetMainTypeName() { - JavaCodeGenerator.mainTypeName = defaultMainTypeName; - } - - static public ArrayList doGenerate(DataFlowGraph graph, DataTransferModel model) { - ArrayList codes = new ArrayList<>(); - ArrayList resources = determineResourceOrder(graph); - - TypeDeclaration mainType = new TypeDeclaration(mainTypeName); - CompilationUnit mainCU = new CompilationUnit(mainType); - mainCU.addImport(new ImportDeclaration("java.util.*")); - codes.add(mainCU); - - // Declare the constructor of the main type. - MethodDeclaration mainConstructor = new MethodDeclaration(mainTypeName, true); - mainType.addMethod(mainConstructor); - - // For each resource. - for (ResourceNode rn: resources) { - boolean f = false; - String resourceName = rn.getResource().getResourceName().substring(0, 1).toUpperCase() - + rn.getResource().getResourceName().substring(1); - TypeDeclaration type = new TypeDeclaration(resourceName); - - // Declare the field to refer to each resource in the main type. - String fieldInitializer = "new " + resourceName + "("; - Set depends = new HashSet<>(); - for (Edge e : rn.getOutEdges()) { - DataFlowEdge re = (DataFlowEdge) e; - ResourcePath dstRes = ((ResourceNode) re.getDestination()).getResource(); - String resName = dstRes.getResourceName().substring(0, 1).toUpperCase() + dstRes.getResourceName().substring(1); - if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - depends.add(dstRes); - fieldInitializer += resName.toLowerCase() + ","; - f = true; - } - } - for (Edge e : rn.getInEdges()) { - DataFlowEdge re = (DataFlowEdge) e; - ResourcePath srcRes = ((ResourceNode) re.getSource()).getResource(); - String resName = srcRes.getResourceName().substring(0, 1).toUpperCase() + srcRes.getResourceName().substring(1); - if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { - depends.add(srcRes); - fieldInitializer += resName.toLowerCase() + ","; - f = true; - } else { - if (rn.getIndegree() > 1) { - // Declare a field to cash the state of the source resource in the type of the destination resource. - ResourcePath cashResId = ((ResourceNode) re.getSource()).getResource(); - type.addField(new FieldDeclaration( - cashResId.getResourceStateType(), ((ResourceNode) re.getSource()).getResource().getResourceName(), getInitializer(cashResId))); - } - } - } - Set refs = new HashSet<>(); - for (Channel cg : model.getChannels()) { - DataTransferChannel c = (DataTransferChannel) cg; - if (c.getInputResources().contains(rn.getResource())) { - for (ResourcePath id: c.getReferenceResources()) { - if (!refs.contains(id) && !depends.contains(id)) { - refs.add(id); - String refResName = id.getResourceName(); - fieldInitializer += refResName.toLowerCase() + ","; - f = true; - } - } - } - } - if (f) fieldInitializer = fieldInitializer.substring(0, fieldInitializer.length() - 1); - fieldInitializer += ")"; - FieldDeclaration field = new FieldDeclaration(new Type(resourceName, resourceName), rn.getResource().getResourceName()); - mainType.addField(field); - Block manConstructorBody = mainConstructor.getBody(); - if (manConstructorBody == null) { - manConstructorBody = new Block(); - mainConstructor.setBody(manConstructorBody); - } - manConstructorBody.addStatement(rn.getResource().getResourceName() + " = " + fieldInitializer + ";"); - - // Declare a constructor, fields and update methods in the type of each resource. - MethodDeclaration constructor = new MethodDeclaration(resourceName, true); - Block block = new Block(); - depends = new HashSet<>(); - for (Edge e : rn.getOutEdges()) { - DataFlowEdge re = (DataFlowEdge) e; - ResourcePath dstRes = ((ResourceNode) re.getDestination()).getResource(); - String dstResName = dstRes.getResourceName().substring(0, 1).toUpperCase() + dstRes.getResourceName().substring(1); - if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - // Declare a field to refer to the destination resource of push transfer. - depends.add(dstRes); - type.addField(new FieldDeclaration(new Type(dstResName, dstResName), dstRes.getResourceName())); - constructor.addParameter(new VariableDeclaration(new Type(dstResName, dstResName), dstRes.getResourceName())); - block.addStatement("this." + dstResName.toLowerCase() + " = " + dstResName.toLowerCase() + ";"); - } - } - for (Edge e : rn.getInEdges()) { - DataFlowEdge re = (DataFlowEdge) e; - ResourcePath srcRes = ((ResourceNode) re.getSource()).getResource(); - String srcResName = srcRes.getResourceName().substring(0, 1).toUpperCase() + srcRes.getResourceName().substring(1); - if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { - // Declare a field to refer to the source resource of pull transfer. - depends.add(srcRes); - type.addField(new FieldDeclaration(new Type(srcResName, srcResName), srcRes.getResourceName())); - constructor.addParameter(new VariableDeclaration(new Type(srcResName, srcResName), srcRes.getResourceName())); - block.addStatement("this." + srcResName.toLowerCase() + " = " + srcResName.toLowerCase() + ";"); - } else { - // Declare an update method in the type of the destination resource. - ArrayList vars = new ArrayList<>(); - vars.add(new VariableDeclaration(srcRes.getResourceStateType(), srcRes.getResourceName())); - DataTransferChannel c = (DataTransferChannel) re.getChannel(); - for (ResourcePath ref: c.getReferenceResources()) { - if (ref != rn.getResource()) { - vars.add(new VariableDeclaration(ref.getResourceStateType(), ref.getResourceName())); - } - } - type.addMethod(new MethodDeclaration("update" + srcResName, false, typeVoid, vars)); - } - } - // Declare a field to refer to the reference resource. - refs = new HashSet<>(); - for (Channel cg : model.getChannels()) { - DataTransferChannel c = (DataTransferChannel) cg; - if (c.getInputResources().contains(rn.getResource())) { - for (ResourcePath id: c.getReferenceResources()) { - if (!refs.contains(id) && !depends.contains(id)) { - refs.add(id); - String refResName = id.getResourceName(); - refResName = refResName.substring(0, 1).toUpperCase() + refResName.substring(1); - type.addField(new FieldDeclaration(new Type(refResName, refResName), id.getResourceName())); - constructor.addParameter(new VariableDeclaration(new Type(refResName, refResName), id.getResourceName())); - block.addStatement("this." + id.getResourceName() + " = " + id.getResourceName() + ";"); - } - } - } - } - constructor.setBody(block); - if (constructor.getParameters() != null) - type.addMethod(constructor); - - // Declare input methods in resources and the main type. - for (Channel cg : model.getIOChannels()) { - for (ChannelMember cm : ((DataTransferChannel) cg).getOutputChannelMembers()) { - if (cm.getResource().equals(rn.getResource())) { - Expression message = cm.getStateTransition().getMessageExpression(); - if (message.getClass() == Term.class) { - ArrayList params = new ArrayList<>(); - for (Variable var: message.getVariables().values()) { - params.add(new VariableDeclaration(var.getType(), var.getName())); - } - MethodDeclaration input = new MethodDeclaration( - ((Term) cm.getStateTransition().getMessageExpression()).getSymbol().getImplName(), - false, typeVoid, params); - type.addMethod(input); - String str = ((Term) cm.getStateTransition().getMessageExpression()).getSymbol().getImplName(); - input = getMethod(mainType, str); - if (input == null) { - input = new MethodDeclaration(str, false, typeVoid, params); - mainType.addMethod(input); - } else { - // Add type to a parameter without type. - for (VariableDeclaration param: input.getParameters()) { - if (param.getType() == null) { - for (VariableDeclaration p: params) { - if (param.getName().equals(p.getName()) && p.getType() != null) { - param.setType(p.getType()); - } - } - } - } - } - } else if (message.getClass() == Variable.class) { - MethodDeclaration input = new MethodDeclaration( - ((Variable) cm.getStateTransition().getMessageExpression()).getName(), - false, typeVoid, null); - type.addMethod(input); - String str = ((Variable) cm.getStateTransition().getMessageExpression()).getName(); - input = getMethod(mainType, str); - if (input == null) { - input = new MethodDeclaration(str, false, typeVoid, null); - mainType.addMethod(input); - } - } - } - } - } - - // Declare the field to store the state in the type of each resource. - if (((StoreAttribute) rn.getAttribute()).isStored()) { - ResourcePath resId = rn.getResource(); - type.addField(new FieldDeclaration(resId.getResourceStateType(), "value", getInitializer(resId))); - } - - // Declare the getter method to obtain the state in the type of each resource. - type.addMethod(new MethodDeclaration("getValue", - rn.getResource().getResourceStateType())); - - // Add compilation unit for each resource. - CompilationUnit cu = new CompilationUnit(type); - cu.addImport(new ImportDeclaration("java.util.*")); - codes.add(cu); - } - - // Declare the Pair class. - boolean isCreatedPair = false; - for(ResourceNode rn : resources) { - if(isCreatedPair) continue; - if(model.getType("Pair").isAncestorOf(rn.getResource().getResourceStateType())) { - TypeDeclaration type = new TypeDeclaration("Pair"); - type.addField(new FieldDeclaration(new Type("Double", "T"), "left")); - type.addField(new FieldDeclaration(new Type("Double", "T"), "right")); - - MethodDeclaration constructor = new MethodDeclaration("Pair", true); - constructor.addParameter(new VariableDeclaration(new Type("Double", "T"), "left")); - constructor.addParameter(new VariableDeclaration(new Type("Double", "T"), "right")); - Block block = new Block(); - block.addStatement("this.left = left;"); - block.addStatement("this.right = right;"); - constructor.setBody(block); - type.addMethod(constructor); - - for(FieldDeclaration field : type.getFields()) { - MethodDeclaration getter = new MethodDeclaration( - "get" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1), - new Type("Double","T")); - getter.setBody(new Block()); - getter.getBody().addStatement("return " + field.getName() + ";"); - type.addMethod(getter); - } - - CompilationUnit cu = new CompilationUnit(type); - cu.addImport(new ImportDeclaration("java.util.*")); - codes.add(cu); - - isCreatedPair = true; - } - } - - // Declare getter methods in the main type. - for (Node n : graph.getNodes()) { - ResourceNode rn = (ResourceNode) n; - MethodDeclaration getter = new MethodDeclaration( - "get" + rn.getResource().getResourceName().substring(0, 1).toUpperCase() - + rn.getResource().getResourceName().substring(1), - rn.getResource().getResourceStateType()); - getter.setBody(new Block()); - getter.getBody().addStatement( - "return " + rn.getResource().getResourceName() + ".getValue();"); - mainType.addMethod(getter); - } - - - HashSet tmps = new HashSet<>(); - HashSet cont = new HashSet<>(); - for (MethodDeclaration method : mainType.getMethods()) { - if (!tmps.contains(method.getName())) - tmps.add(method.getName()); - else - cont.add(method.getName()); - } - for (MethodDeclaration method : mainType.getMethods()) { - if (cont.contains(method.getName())) { - method.setName(method.getName() + method.getParameters().get(0).getName().substring(0, 1).toUpperCase() - + method.getParameters().get(0).getName().substring(1)); - } - } - return codes; - } - - private static String getInitializer(ResourcePath resId) { - Type stateType = resId.getResourceStateType(); - String initializer = null; - if (resId.getInitialValue() != null) { - initializer = resId.getInitialValue().toImplementation(new String[] {""}); - } else { - if (DataConstraintModel.typeList.isAncestorOf(stateType)) { - initializer = "new " + resId.getResourceStateType().getImplementationTypeName() + "()"; - } else if (DataConstraintModel.typeMap.isAncestorOf(stateType)) { - initializer = "new " + resId.getResourceStateType().getImplementationTypeName() + "()"; - } - } - return initializer; - } - - static public ArrayList getCodes(ArrayList codeTree) { - ArrayList codes = new ArrayList<>(); - for (TypeDeclaration type : codeTree) { - codes.add("public class " + type.getTypeName() + "{"); - for (FieldDeclaration field : type.getFields()) { - if (type.getTypeName() != mainTypeName) { - String cons = "\t" + "private " + field.getType().getInterfaceTypeName() + " " - + field.getName(); - if (DataConstraintModel.isListType(field.getType())) - cons += " = new ArrayList<>()"; - cons += ";"; - codes.add(cons); - } else { - String cons = "\t" + "private " + field.getType().getInterfaceTypeName() + " " - + field.getName() + " = new " + field.getType().getTypeName() + "("; - cons += ");"; - codes.add(cons); - } - } - codes.add(""); - for (MethodDeclaration method : type.getMethods()) { - String varstr = "\t" + "public " + method.getReturnType().getInterfaceTypeName() + " " - + method.getName() + "("; - if (method.getParameters() != null) { - for (VariableDeclaration var : method.getParameters()) { - varstr += var.getType().getInterfaceTypeName() + " " + var.getName() + ","; - } - if (!method.getParameters().isEmpty()) - varstr = varstr.substring(0, varstr.length() - 1); - } - if (method.getBody() != null) { - for (String str : method.getBody().getStatements()) { - codes.add("\t\t" + str + ";"); - } - } - codes.add(varstr + ")" + "{"); - codes.add("\t" + "}"); - codes.add(""); - } - codes.add("}"); - codes.add(""); - } - return codes; - } - - static private ArrayList determineResourceOrder(DataFlowGraph graph) { - ArrayList resources = new ArrayList<>(); - Set visited = new HashSet<>(); - for (Node n : graph.getNodes()) { - ResourceNode rn = (ResourceNode) n; - topologicalSort(graph, rn, visited, resources); - } - return resources; - } - - static private void topologicalSort(DataFlowGraph graph, ResourceNode curNode, Set visited, List orderedList) { - if (visited.contains(curNode)) return; - visited.add(curNode); - for (Edge e : curNode.getInEdges()) { - DataFlowEdge re = (DataFlowEdge) e; - if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - topologicalSort(graph, (ResourceNode) re.getSource(), visited, orderedList); - } - } - for (Edge e : curNode.getOutEdges()) { - DataFlowEdge re = (DataFlowEdge) e; - if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { - topologicalSort(graph, (ResourceNode) re.getDestination(), visited, orderedList); - } - } - for (Node n: graph.getNodes()) { // for reference resources. - ResourceNode rn = (ResourceNode) n; - for (Edge e : rn.getOutEdges()) { - DataFlowEdge re = (DataFlowEdge) e; - for (ChannelMember m: re.getChannel().getReferenceChannelMembers()) { - if (m.getResource() == curNode.getResource()) { - topologicalSort(graph, rn, visited, orderedList); - } - } - } - } - orderedList.add(0, curNode); - } - - private static MethodDeclaration getMethod(TypeDeclaration type, String methodName) { - for (MethodDeclaration m: type.getMethods()) { - if (m.getName().equals(methodName)) return m; - } - return null; - } - - static public IResourceStateAccessor pushAccessor = new IResourceStateAccessor() { - @Override - public Expression getCurrentStateAccessorFor(ResourcePath target, ResourcePath from) { - if (target.equals(from)) { - return new Field("value", - target.getResourceStateType() != null ? target.getResourceStateType() - : DataConstraintModel.typeInt); - } - // for reference channel member - return new Parameter(target.getResourceName(), - target.getResourceStateType() != null ? target.getResourceStateType() - : DataConstraintModel.typeInt); - } - - @Override - public Expression getNextStateAccessorFor(ResourcePath target, ResourcePath from) { - return new Parameter(target.getResourceName(), - target.getResourceStateType() != null ? target.getResourceStateType() - : DataConstraintModel.typeInt); - } - }; - static public IResourceStateAccessor pullAccessor = new IResourceStateAccessor() { - @Override - public Expression getCurrentStateAccessorFor(ResourcePath target, ResourcePath from) { - if (target.equals(from)) { - return new Field("value", - target.getResourceStateType() != null ? target.getResourceStateType() - : DataConstraintModel.typeInt); - } - // for reference channel member - Term getter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); - getter.addChild(new Field(target.getResourceName(), target.getResourceStateType())); - return getter; - } - - @Override - public Expression getNextStateAccessorFor(ResourcePath target, ResourcePath from) { - Term getter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); - getter.addChild(new Field(target.getResourceName(), target.getResourceStateType())); - return getter; - } - }; -} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaImplementationVisitor.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaImplementationVisitor.java new file mode 100644 index 0000000..3b1d8ce --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaImplementationVisitor.java @@ -0,0 +1,193 @@ +package generators; + +import models.algebra.*; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonAccessor; +import models.dataConstraintModel.JsonTerm; + +/** + * This class is a Java implementation of {@link IExpressionVisitor} + * which holds and manages the actual method of implementation code generation + * + * @author s-yamagiwa + */ +public class JavaImplementationVisitor implements IExpressionVisitor { + private static int jsonCount = 0; + + @Override + public String visit(Term term, String[] sideEffects) { + int[] implParamOrder = term.getSymbol().getImplParamOrder(); + if (term.getSymbol().isImplLambda()) { + String[] components = term.getSymbol().getImplName().split("->"); + String component0 = components[0].replace("(", "").replace(")", ""); + String[] params = component0.split(","); + String exp = components[1]; + String receiver = ""; + if (implParamOrder == null) { + receiver = term.getChildren().get(0).accept(this, sideEffects); + exp = exp.replace(params[0], receiver); + for (int i = 1; i < params.length; i++) { + exp = exp.replace(params[i], term.getChildren().get(i).accept(this, sideEffects)); + } + } else { + receiver = term.getChildren().get(implParamOrder[0]).accept(this, sideEffects); + exp = exp.replace(params[0], receiver); + for (int i = 1; i < params.length; i++) { + exp = exp.replace(params[i], term.getChildren().get(implParamOrder[i]).accept(this, sideEffects)); + } + } + if (term.getSymbol().isImplWithSideEffect()) { + sideEffects[0] = sideEffects[0] + exp + ";\n"; + exp = receiver; + } + return exp; + } + if (term.getSymbol().isImplGenerative()) { + Type[] childrenTypes = new Type[term.getChildren().size()]; + String[] childrenImpl = new String[term.getChildren().size()]; + String[] childrenSideEffects = new String[term.getChildren().size()]; + if (implParamOrder == null) { + for (int i = 0; i < term.getChildren().size(); i++) { + Expression child = term.getChildren().get(i); + if (child instanceof Variable) { + childrenTypes[i] = ((Variable) child).getType(); + } else if (child instanceof Term) { + childrenTypes[i] = ((Term) child).getType(); + } + String[] childSideEffect = new String[]{""}; + childrenImpl[i] = child.accept(this, childSideEffect); + childrenSideEffects[i] = childSideEffect[0]; + } + String exp = term.getSymbol().generate(term.getType(), childrenTypes, childrenImpl, childrenSideEffects, sideEffects); + if (term.getSymbol().isImplWithSideEffect()) { + sideEffects[0] = sideEffects[0] + exp; + exp = childrenImpl[0]; // the value of this term + } + return exp; + } else { + for (int i = 0; i < term.getChildren().size(); i++) { + Expression child = term.getChildren().get(implParamOrder[i]); + if (child instanceof Variable) { + childrenTypes[i] = ((Variable) child).getType(); + } else if (child instanceof Term) { + childrenTypes[i] = ((Term) child).getType(); + } + String[] childSideEffect = new String[]{""}; + childrenImpl[i] = child.accept(this, childSideEffect); + childrenSideEffects[i] = childSideEffect[0]; + } + String exp = term.getSymbol().generate(term.getType(), childrenTypes, childrenImpl, childrenSideEffects, sideEffects); + if (term.getSymbol().isImplWithSideEffect()) { + sideEffects[0] = sideEffects[0] + exp; + exp = childrenImpl[0]; // the value of this term + } + return exp; + } + } + if (term.getArity() == 2 && term.getSymbol().isImplInfix()) { + if (implParamOrder == null) { + return "(" + term.getChildren().get(0).accept(this, sideEffects) + term.getSymbol().toImplementation() + term.getChildren().get(1).accept(this, sideEffects) + ")"; + } else { + return "(" + term.getChildren().get(implParamOrder[0]).accept(this, sideEffects) + term.getSymbol().toImplementation() + term.getChildren().get(implParamOrder[1]).accept(this, sideEffects) + ")"; + } + } + if ((term.getArity() >= 1 || term.getArity() == -1) && term.getSymbol().isImplMethod()) { + if (implParamOrder == null) { + String exp = null; + String receiver = ""; + if (term.getChildren().size() > 0 && term.getChildren().get(0) != null) { + receiver = term.getChildren().get(0).accept(this, sideEffects); + exp = receiver + "." + term.getSymbol().toImplementation() + "("; + } else { + exp = term.getSymbol().toImplementation() + "("; + } + String delimiter = ""; + for (int i = 1; i < term.getChildren().size(); i++) { + Expression e = term.getChildren().get(i); + exp += (delimiter + e.accept(this, sideEffects)); + delimiter = ","; + } + exp += ")"; + if (term.getSymbol().isImplWithSideEffect()) { + sideEffects[0] = sideEffects[0] + exp + ";\n"; + exp = receiver; + } + return exp; + } else { + String receiver = term.getChildren().get(implParamOrder[0]).accept(this, sideEffects); + String exp = receiver + "." + term.getSymbol().toImplementation() + "("; + String delimiter = ""; + for (int i = 1; i < term.getChildren().size(); i++) { + Expression e = term.getChildren().get(implParamOrder[i]); + exp += (delimiter + e.accept(this, sideEffects)); + delimiter = ","; + } + exp += ")"; + if (term.getSymbol().isImplWithSideEffect()) { + sideEffects[0] = sideEffects[0] + exp + ";\n"; + exp = receiver; + } + return exp; + } + } else { + if (implParamOrder == null) { + String exp = term.getSymbol().toImplementation() + "("; + String delimiter = ""; + for (Expression e : term.getChildren()) { + exp += (delimiter + e.accept(this, sideEffects)); + delimiter = ","; + } + return exp + ")"; + } else { + String exp = term.getSymbol().toImplementation() + "("; + String delimiter = ""; + for (int i = 0; i < term.getChildren().size(); i++) { + Expression e = term.getChildren().get(implParamOrder[i]); + exp += (delimiter + e.accept(this, sideEffects)); + delimiter = ","; + } + return exp + ")"; + } + } + } + + @Override + public String visit(Field field, String[] sideEffects) { + return "this." + visit((Constant) field, sideEffects); + } + + @Override + public String visit(Constant constant, String[] sideEffects) { + if (constant.getSymbol().isImplGenerative()) { + String exp = constant.getSymbol().generate(constant.getType(), new Type[]{}, new String[]{}, new String[]{}, sideEffects); + return exp; + } + return constant.getSymbol().getImplName(); + } + + @Override + public String visit(Variable variable, String[] sideEffects) { + return variable.getName(); + } + + @Override + public String visit(JsonTerm jsonTerm, String[] sideEffects) { + String temp = "temp_json" + jsonCount; + jsonCount++; + String impl = ""; + impl += "Map " + temp + " = new HashMap<>();\n"; + for (String key : jsonTerm.keySet()) { + impl += temp + ".put(\"" + key + "\", " + jsonTerm.get(key).accept(this, sideEffects) + ");\n"; + } + sideEffects[0] += impl; + return temp; + } + + @Override + public String visit(JsonAccessor jsonAccessor, String[] sideEffects) { + if (jsonAccessor.getSymbol().equals(DataConstraintModel.dotParam)) { + return jsonAccessor.getChildren().get(0).accept(this, sideEffects) + "." + jsonAccessor.getSymbol().toImplementation() + "(" + jsonAccessor.getChildren().get(1).accept(this, sideEffects) + ")"; + } + return visit((Term) jsonAccessor, sideEffects); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java deleted file mode 100644 index 86cd28a..0000000 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ /dev/null @@ -1,350 +0,0 @@ -package generators; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import code.ast.CompilationUnit; -import code.ast.MethodDeclaration; -import code.ast.TypeDeclaration; -import models.Edge; -import models.Node; -import models.algebra.Expression; -import models.algebra.InvalidMessage; -import models.algebra.ParameterizedIdentifierIsFutureWork; -import models.algebra.Term; -import models.algebra.Type; -import models.algebra.UnificationFailed; -import models.algebra.ValueUndefined; -import models.algebra.Variable; -import models.dataConstraintModel.Channel; -import models.dataConstraintModel.ChannelMember; -import models.dataConstraintModel.DataConstraintModel; -import models.dataConstraintModel.ResourcePath; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.DataTransferChannel; -import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; -import models.dataFlowModel.PushPullAttribute; -import models.dataFlowModel.PushPullValue; -import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; -import models.dataFlowModel.DataFlowEdge; -import models.dataFlowModel.DataFlowGraph; -import models.dataFlowModel.ResourceNode; -import models.dataFlowModel.StoreAttribute; - -public class JavaMethodBodyGenerator { - public static ArrayList doGenerate(DataFlowGraph graph, DataTransferModel model, ArrayList codes) { - // Create a map from type names (lower case) to their types. - Map typeMap = new HashMap<>(); - for (CompilationUnit code: codes) { - for (TypeDeclaration type: code.types()) { - typeMap.put(type.getTypeName().substring(0,1).toLowerCase() + type.getTypeName().substring(1), type); - } - } - - // Generate the body of each update or getter method. - try { - Map> referredResources = new HashMap<>(); - for (Edge e: graph.getEdges()) { - DataFlowEdge d = (DataFlowEdge) e; - PushPullAttribute pushPull = (PushPullAttribute) d.getAttribute(); - ResourceNode src = (ResourceNode) d.getSource(); - ResourceNode dst = (ResourceNode) d.getDestination(); - String srcResourceName = src.getResource().getResourceName(); - String dstResourceName = dst.getResource().getResourceName(); - TypeDeclaration srcType = typeMap.get(srcResourceName); - TypeDeclaration dstType = typeMap.get(dstResourceName); - for (ChannelMember out: d.getChannel().getOutputChannelMembers()) { - if (out.getResource() == dst.getResource()) { - if (pushPull.getOptions().get(0) == PushPullValue.PUSH && srcType != null) { - // for push data transfer - MethodDeclaration update = getUpdateMethod(dstType, srcType); - if (((StoreAttribute) dst.getAttribute()).isStored()) { - // update stored state of dst side resource (when every incoming edge is in push style) - Expression updateExp = d.getChannel().deriveUpdateExpressionOf(out, JavaCodeGenerator.pushAccessor); - String[] sideEffects = new String[] {""}; - String curState = updateExp.toImplementation(sideEffects); - String updateStatement; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - updateStatement = sideEffects[0]; - } else { - updateStatement = sideEffects[0] + "value = " + curState + ";"; - } - if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { - update.addFirstStatement(updateStatement); - } - } - if (dst.getIndegree() > 1) { - // update a cash of src side resource (when incoming edges are multiple) - String cashStatement = "this." + srcResourceName + " = " + srcResourceName + ";"; - if (update.getBody() == null || !update.getBody().getStatements().contains(cashStatement)) { - update.addFirstStatement(cashStatement); - } - } - MethodDeclaration getter = getGetterMethod(dstType); - if (((StoreAttribute) dst.getAttribute()).isStored()) { - // returns the current state stored in a field. - if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - Type resourceType = dst.getResource().getResourceStateType(); - if (model.isPrimitiveType(resourceType)) { - getter.addStatement("return value;"); - } else { - // copy the current state to be returned as a 'value' - String implTypeName = resourceType.getImplementationTypeName(); -// String interfaceTypeName = resourceType.getInterfaceTypeName(); -// String concreteTypeName; -// if (interfaceTypeName.contains("<")) { -// String typeName = implTypeName.substring(0, implTypeName.indexOf("<")); -//// String generics = interfaceTypeName.substring(interfaceTypeName.indexOf("<") + 1, interfaceTypeName.lastIndexOf(">")); -// concreteTypeName = typeName + "<>"; -// } else { -// concreteTypeName = implTypeName; -// } - getter.addStatement("return new " + implTypeName + "(value);"); - } - } - } - // src side (for a chain of update method invocations) - for (MethodDeclaration srcUpdate: getUpdateMethods(srcType)) { - String refParams = ""; - Set referredSet = referredResources.get(srcUpdate); - for (ChannelMember rc: d.getChannel().getReferenceChannelMembers()) { - // to get the value of reference member. - ResourcePath ref = rc.getResource(); - if (referredSet == null) { - referredSet = new HashSet<>(); - referredResources.put(srcUpdate, referredSet); - } - if (ref != dst.getResource()) { - String refVarName = ref.getResourceName(); - if (!referredSet.contains(ref)) { - referredSet.add(ref); - Expression refGetter = JavaCodeGenerator.pullAccessor.getCurrentStateAccessorFor(ref, src.getResource()); - String[] sideEffects = new String[] {""}; - String refExp = refGetter.toImplementation(sideEffects); - String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); - srcUpdate.addFirstStatement(sideEffects[0] + refTypeName + " " + refVarName + " = " + refExp + ";"); - } - refParams += ", " + refVarName; - } - } - srcUpdate.addStatement("this." + dstResourceName + ".update" + srcType.getTypeName() + "(value" + refParams + ");"); - } - for (MethodDeclaration srcInput: getInputMethods(srcType, src, model)) { - String refParams = ""; - Set referredSet = referredResources.get(srcInput); - for (ChannelMember rc: d.getChannel().getReferenceChannelMembers()) { - // to get the value of reference member. - ResourcePath ref = rc.getResource(); - if (referredSet == null) { - referredSet = new HashSet<>(); - referredResources.put(srcInput, referredSet); - } - if (ref != dst.getResource()) { - String refVarName = ref.getResourceName(); - if (!referredSet.contains(ref)) { - referredSet.add(ref); - Expression refGetter = JavaCodeGenerator.pullAccessor.getCurrentStateAccessorFor(ref, src.getResource()); - String[] sideEffects = new String[] {""}; - String refExp = refGetter.toImplementation(sideEffects); - String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); - srcInput.addFirstStatement(sideEffects[0] + refTypeName + " " + refVarName + " = " + refExp + ";"); - } - refParams += ", " + refVarName; - } - } - srcInput.addStatement("this." + dstResourceName + ".update" + srcType.getTypeName() + "(value" + refParams + ");"); - } - } else { - // for pull (or push/pull) data transfer - MethodDeclaration getter = getGetterMethod(dstType); - if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - boolean isContainedPush = false; - HashMap inputResourceToStateAccessor = new HashMap<>(); - for (Edge eIn: dst.getInEdges()) { - DataFlowEdge dIn = (DataFlowEdge) eIn; - if (((PushPullAttribute) dIn.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - isContainedPush = true; - inputResourceToStateAccessor.put(((ResourceNode) dIn.getSource()).getResource(), JavaCodeGenerator.pushAccessor); - } else { - inputResourceToStateAccessor.put(((ResourceNode) dIn.getSource()).getResource(), JavaCodeGenerator.pullAccessor); - } - } - // for reference channel members - for (ChannelMember c: d.getChannel().getReferenceChannelMembers()) { - inputResourceToStateAccessor.put(c.getResource(), JavaCodeGenerator.pullAccessor); // by pull data transfer - } - String[] sideEffects = new String[] {""}; - // generate a return statement. - if (!isContainedPush) { - // All incoming edges are in PULL style. - String curState = d.getChannel().deriveUpdateExpressionOf(out, JavaCodeGenerator.pullAccessor).toImplementation(sideEffects); - getter.addStatement(sideEffects[0] + "return " + curState + ";"); - } else { - // At least one incoming edge is in PUSH style. - String curState = d.getChannel().deriveUpdateExpressionOf(out, JavaCodeGenerator.pullAccessor, inputResourceToStateAccessor).toImplementation(sideEffects); - getter.addStatement(sideEffects[0] + "return " + curState + ";"); - } - } - } - } - } - } - // for source nodes - String mainTypeName = JavaCodeGenerator.mainTypeName.substring(0,1).toLowerCase() + JavaCodeGenerator.mainTypeName.substring(1); - TypeDeclaration mainType = typeMap.get(mainTypeName); - for (Node n: graph.getNodes()) { - ResourceNode resource = (ResourceNode) n; - String resourceName = resource.getResource().getResourceName(); - TypeDeclaration type = typeMap.get(resourceName); - if (type != null) { - // getter method - MethodDeclaration getter = getGetterMethod(type); - if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - Type resourceType = resource.getResource().getResourceStateType(); - if (model.isPrimitiveType(resourceType)) { - getter.addStatement("return value;"); - } else { - // copy the current state to be returned as a 'value' - String implTypeName = resourceType.getImplementationTypeName(); -// String interfaceTypeName = resourceType.getInterfaceTypeName(); -// String concreteTypeName; -// if (interfaceTypeName.contains("<")) { -// String typeName = implTypeName.substring(0, implTypeName.indexOf("<")); -// String generics = interfaceTypeName.substring(interfaceTypeName.indexOf("<") + 1, interfaceTypeName.lastIndexOf(">")); -// concreteTypeName = typeName + "<" + generics + ">"; -// } else { -// concreteTypeName = implTypeName; -// } - getter.addStatement("return new " + implTypeName + "(value);"); - } - } - // methods for input events - Map> ioChannelsAndMembers = getIOChannelsAndMembers(resource, model); - for (Map.Entry> entry: ioChannelsAndMembers.entrySet()) { - Set outs = entry.getValue(); - for (ChannelMember out: outs) { - MethodDeclaration input = getInputMethod(type, out); - if (input != null) { - String[] sideEffects = new String[] {""}; - Expression updateExp = entry.getKey().deriveUpdateExpressionOf(out, JavaCodeGenerator.pushAccessor); - String newState = updateExp.toImplementation(sideEffects); - String updateStatement; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - updateStatement = sideEffects[0]; - } else { - updateStatement = sideEffects[0] + "this.value = " + newState + ";"; - } - if (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement)) { - input.addFirstStatement(updateStatement); - } - if (mainType != null) { - MethodDeclaration mainInput = getMethod(mainType, input.getName()); - if (mainInput != null) { - String args = ""; - String delimitar = ""; - if (out.getStateTransition().getMessageExpression() instanceof Term) { - Term message = (Term) out.getStateTransition().getMessageExpression(); - for (Variable var: message.getVariables().values()) { - args += delimitar + var.getName(); - delimitar = ", "; - } - } - mainInput.addStatement("this." + resourceName + "." + input.getName() + "(" + args + ");"); - } - } - } - } - } - } - } - } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork - | InvalidMessage | UnificationFailed | ValueUndefined e1) { - e1.printStackTrace(); - } - return codes; - } - - private static MethodDeclaration getUpdateMethod(TypeDeclaration type, TypeDeclaration from) { - for (MethodDeclaration m: type.getMethods()) { - if (m.getName().equals("update" + from.getTypeName())) return m; - } - return null; - } - - private static List getUpdateMethods(TypeDeclaration type) { - List updates = new ArrayList<>(); - for (MethodDeclaration m: type.getMethods()) { - if (m.getName().startsWith("update")) { - updates.add(m); - } - } - return updates; - } - - private static MethodDeclaration getGetterMethod(TypeDeclaration type) { - for (MethodDeclaration m: type.getMethods()) { - if (m.getName().startsWith("get")) return m; - } - return null; - } - - private static Map> getIOChannelsAndMembers(ResourceNode resource, DataTransferModel model) { - Map> ioChannelsAndMembers = new HashMap<>(); - for (Channel c: model.getIOChannels()) { - DataTransferChannel ch = (DataTransferChannel) c; - // I/O channel - for (ChannelMember out: ch.getOutputChannelMembers()) { - if (out.getResource().equals(resource.getResource())) { - if (out.getStateTransition().getMessageExpression() instanceof Term || out.getStateTransition().getMessageExpression() instanceof Variable) { - Set channelMembers = ioChannelsAndMembers.get(ch); - if (channelMembers == null) { - channelMembers = new HashSet<>(); - ioChannelsAndMembers.put(ch, channelMembers); - } - channelMembers.add(out); - } - } - } - } - return ioChannelsAndMembers; - } - - private static List getInputMethods(TypeDeclaration type, ResourceNode resource, DataTransferModel model) { - List inputs = new ArrayList<>(); - for (Channel c: model.getIOChannels()) { - DataTransferChannel channel = (DataTransferChannel) c; - // I/O channel - for (ChannelMember out: channel.getOutputChannelMembers()) { - if (out.getResource().equals(resource.getResource())) { - MethodDeclaration input = getInputMethod(type, out); - inputs.add(input); - } - } - } - return inputs; - } - - private static MethodDeclaration getInputMethod(TypeDeclaration type, ChannelMember out) { - MethodDeclaration input = null; - if (out.getStateTransition().getMessageExpression() instanceof Term) { - Term message = (Term) out.getStateTransition().getMessageExpression(); - input = getMethod(type, message.getSymbol().getImplName()); - } else if (out.getStateTransition().getMessageExpression() instanceof Variable) { - Variable message = (Variable) out.getStateTransition().getMessageExpression(); - input = getMethod(type, message.getName()); - } - return input; - } - - private static MethodDeclaration getMethod(TypeDeclaration type, String methodName) { - for (MethodDeclaration m: type.getMethods()) { - if (m.getName().equals(methodName)) return m; - } - return null; - } -} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java new file mode 100644 index 0000000..6548d62 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java @@ -0,0 +1,469 @@ +package generators; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import code.ast.*; +import code.ast.Expression; +import code.ast.Variable; +import models.algebra.*; +import models.algebra.Type; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonType; +import models.dataConstraintModel.ListType; +import models.dataConstraintModel.MapType; +import models.dataConstraintModel.TupleType; + +public class JavaSpecific implements ILanguageSpecific { + public static final Type typeVoid = new Type("Void", new code.ast.SimpleType("void")); + public static final code.ast.SimpleType typeObject = new code.ast.SimpleType("Object"); + public static final code.ast.SimpleType typeBoolean = new code.ast.SimpleType("Boolean"); + public static final code.ast.SimpleType typeInteger = new code.ast.SimpleType("Integer"); + public static final code.ast.SimpleType typeLong = new code.ast.SimpleType("Long"); + public static final code.ast.SimpleType typeFloat = new code.ast.SimpleType("Float"); + public static final code.ast.SimpleType typeDouble = new code.ast.SimpleType("Double"); + public static final code.ast.SimpleType typeString = new code.ast.SimpleType("String"); + public static final code.ast.SimpleType typeList = new code.ast.SimpleType("List"); + public static final code.ast.SimpleType typeArrayList = new code.ast.SimpleType("ArrayList"); + public static final code.ast.SimpleType typeMap = new code.ast.SimpleType("Map"); + public static final code.ast.SimpleType typeMapEntry = new code.ast.SimpleType("Map.Entry"); + public static final code.ast.SimpleType typeHashMap = new code.ast.SimpleType("HashMap"); + public static final code.ast.SimpleType typePair = new code.ast.SimpleType("Pair"); + public static final String self = "this"; + + @Override + public CompilationUnit newCompilationUnit(TypeDeclaration component) { + CompilationUnit cu = new CompilationUnit(component); + cu.addImport(new ImportDeclaration("java.util.*")); + return cu; + } + + @Override + public TypeDeclaration newTypeDeclaration(String typeName) { + return new TypeDeclaration(typeName); + } + + @Override + public VariableDeclaration newVariableDeclaration(Type type, String varName) { + return new VariableDeclaration(type, varName); + } + + @Override + public MethodDeclaration newMethodDeclaration(String methodName, Type returnType) { + if (returnType == null) { + returnType = typeVoid; + } + return new MethodDeclaration(methodName, returnType); + } + + @Override + public MethodDeclaration newMethodDeclaration(String methodName, boolean isConstructor, Type returnType, List parameters) { + if (returnType == null && !isConstructor) { + returnType = typeVoid; + } + return new MethodDeclaration(methodName, isConstructor, returnType, parameters); + } + + @Override + public FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName) { + return new FieldDeclaration(fieldType, fieldName); + } + + @Override + public FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName, String fieldInitializer) { + return new FieldDeclaration(fieldType, fieldName, fieldInitializer); + } + + @Override + public ListType newListType(Type compType) { + return newListType(compType, DataConstraintModel.typeList); + } + + @Override + public ListType newListType(Type compType, Type parentListType) { + List typeArgs = new ArrayList<>(); + if (isValueType(compType)) { + typeArgs.add((code.ast.Type) getWrapperType(compType).getInterfaceType()); + } else { + typeArgs.add((code.ast.Type) compType.getInterfaceType()); + } + return new ListType("List", new code.ast.ParameterizedType(typeArrayList), new code.ast.ParameterizedType(JavaSpecific.typeList, typeArgs), parentListType, compType); + } + + @Override + public MapType newMapType(Type keyType, String valueTypeName) { + return newMapType(keyType, valueTypeName, DataConstraintModel.typeMap); + } + + @Override + public MapType newMapType(Type keyType, String valueTypeName, Type parentMapType) { + Type valueType = new Type(valueTypeName, new code.ast.SimpleType(valueTypeName)); + List typeArgs = new ArrayList<>(); + typeArgs.add((code.ast.Type) keyType.getInterfaceType()); + typeArgs.add((code.ast.Type) valueType.getInterfaceType()); + return new MapType("Map", new code.ast.ParameterizedType(typeHashMap), new code.ast.ParameterizedType(JavaSpecific.typeMap, typeArgs), parentMapType, keyType, valueType); + } + + @Override + public MapType newMapType(Type keyType, Type valueType) { + return newMapType(keyType, valueType, DataConstraintModel.typeMap); + } + + @Override + public MapType newMapType(Type keyType, Type valueType, Type parentMapType) { + List typeArgs = new ArrayList<>(); + typeArgs.add((code.ast.Type) keyType.getInterfaceType()); + if (isValueType(valueType)) { + typeArgs.add((code.ast.Type) getWrapperType(valueType).getInterfaceType()); + } else { + typeArgs.add((code.ast.Type) valueType.getInterfaceType()); + } + return new MapType("Map", new code.ast.ParameterizedType(typeHashMap), new code.ast.ParameterizedType(JavaSpecific.typeMap, typeArgs), parentMapType, keyType, valueType); + } + + @Override + public TupleType newTupleType(List componentTypes) { + return newTupleType(componentTypes, DataConstraintModel.typeTuple); + } + + @Override + public TupleType newTupleType(List componentTypes, Type parentTupleType) { + code.ast.Type implType = new code.ast.SimpleType("AbstractMap.SimpleEntry"); + code.ast.Type interfaceType = typeMapEntry; + if (componentTypes.size() >= 2) { + Type compType = componentTypes.get(componentTypes.size() - 1); + if (isValueType(compType)) { + interfaceType = (code.ast.Type) getWrapperType(compType).getInterfaceType(); + } else { + interfaceType = (code.ast.Type) compType.getInterfaceType(); + } + for (int i = componentTypes.size() - 2; i >= 0; i--) { + List typeArgs = new ArrayList<>(); + compType = componentTypes.get(i); + if (isValueType(compType)) { + typeArgs.add((code.ast.Type) getWrapperType(compType).getInterfaceType()); + } else { + typeArgs.add((code.ast.Type) compType.getInterfaceType()); + } + typeArgs.add(interfaceType); + interfaceType = new code.ast.ParameterizedType(typeMapEntry, typeArgs); + } + } + return new TupleType("Tuple", implType, interfaceType, parentTupleType, componentTypes); + } + + @Override + public JsonType newJsonType() { + return new JsonType("Json", new code.ast.ParameterizedType(typeHashMap), new code.ast.ParameterizedType(typeMap, List.of(typeString, typeObject))); + } + + @Override + public JsonType newJsonType(Type parentJsonType) { + JsonType jsonType = newJsonType(); + jsonType.addParentType(parentJsonType); + return jsonType; + } + + @Override + public boolean declareField() { + return true; + } + + @Override + public String getSelfExp() { + return self; + } + + @Override + public String getFieldAccessor(String fieldName) { + return self + "." + fieldName; + } + + @Override + public String getMethodInvocation(String methodName) { + return self + "." + methodName + "()"; + } + + @Override + public String getMethodInvocation(String methodName, List parameters) { + if (parameters == null) return getMethodInvocation( methodName); + String invocation = self + "." + methodName + "("; + if (parameters.size() > 0) { + for (int i = 0; i < parameters.size(); i++) { + if (i < parameters.size() - 1) { + invocation += parameters.get(i) + ", "; + } else { + invocation += parameters.get(i); + } + } + } + invocation += ")"; + return invocation; + } + + @Override + public String getMethodInvocation(String receiverName, String methodName) { + return receiverName + "." + methodName + "()"; + } + + @Override + public String getMethodInvocation(String receiverName, String methodName, List parameters) { + if (parameters == null) return getMethodInvocation(receiverName, methodName); + String invocation = receiverName + "." + methodName + "("; + if (parameters.size() > 0) { + for (int i = 0; i < parameters.size(); i++) { + if (i < parameters.size() - 1) { + invocation += parameters.get(i) + ", "; + } else { + invocation += parameters.get(i); + } + } + } + invocation += ")"; + return invocation; + } + + @Override + public String getConstructorInvocation(String componentName, List parameters) { + String invocation = "new " + componentName + "("; + if (parameters != null && parameters.size() > 0) { + for (int i = 0; i < parameters.size(); i++) { + if (i < parameters.size() - 1) { + invocation += parameters.get(i) + ", "; + } else { + invocation += parameters.get(i); + } + } + } + invocation += ")"; + return invocation; + } + + @Override + public ReturnStatement getReturnStatement(String returnValue) { + ReturnStatement returnStatement = new ReturnStatement(); + returnStatement.setExpression(new code.ast.Variable(returnValue) { + }); + return returnStatement; + } + + @Override + public IfStatement getIfStatement(Term condition, Statement block) { + IfStatement ifStatement = new IfStatement(); + String conditionSource = condition.toImplementation(new String[]{""}); + ifStatement.setExpression(new code.ast.Variable(conditionSource)); + ifStatement.setThenStatement(block); + return ifStatement; + } + + @Override + public ForStatement getForStatementForList(String varName, String list) { + VariableDeclaration varDec = new VariableDeclaration(DataConstraintModel.typeInt, varName, new code.ast.Constant("0")); + VariableDeclarationStatement varDecStmt = new VariableDeclarationStatement(); + varDecStmt.addFragment(varDec); + ForStatement forStatement = new ForStatement(); + forStatement.getInitializers().add(varDecStmt); + InfixExpression condition = new InfixExpression( + new Symbol("<", 2, Symbol.Type.INFIX), + new code.ast.Variable(varName), + new code.ast.Variable(list + ".size()") + ); + forStatement.setExpression(condition); + PostfixExpression increment = new PostfixExpression( + new code.ast.Variable(varName), + PostfixExpression.Operator.INCREMENT + ); + forStatement.setUpdaters(Arrays.asList(new ExpressionStatement(increment))); + return forStatement; + } + + @Override + public EnhancedForStatement getForStatementForCollection(VariableDeclaration varDeclaration, String collection) { + EnhancedForStatement enhancedForStatement = new EnhancedForStatement(); + + enhancedForStatement.setParameter(varDeclaration); + enhancedForStatement.setExpression(new code.ast.Variable(collection)); + + return enhancedForStatement; + } + + @Override + public EnhancedForStatement getForStatementForMap(String varName, String map) { + VariableDeclaration varDeclaration = new VariableDeclaration(DataConstraintModel.typeString, varName); + EnhancedForStatement enhancedForStatement = new EnhancedForStatement(); + + enhancedForStatement.setParameter(varDeclaration); + enhancedForStatement.setExpression(new code.ast.Variable(map + ".keySet()")); + + return enhancedForStatement; + } + + @Override + public String toComponentName(String name) { + return name.substring(0, 1).toUpperCase() + name.substring(1); + } + + @Override + public String toVariableName(String name) { + return name.substring(0, 1).toLowerCase() + name.substring(1); + } + + @Override + public String getMainComponentName() { + return "Main"; + } + + @Override + public String getAssignment() { + return " = "; + } + + @Override + public String getStatementDelimiter() { + return ";"; + } + + @Override + public String getStringDelimiter() { + return "\""; + } + + @Override + public String getOpeningScoreDelimiter() { + return "{"; + } + + @Override + public String getClosingScoreDelimiter() { + return "}"; + } + + @Override + public String getValueToStringExp(String typeName, String valueExp) { + if (typeName.equals("int")) { + return "Integer.toString(" + valueExp + ")"; + } else if (typeName.equals("float")) { + return "Float.toString(" + valueExp + ")"; + } else if (typeName.equals("double")) { + return "Double.toString(" + valueExp + ")"; + } else if (typeName.equals("boolean")) { + return "Boolean.toString(" + valueExp + ")"; + } else { + return valueExp + ".toString()"; + } + } + + @Override + public String getStringToValueExp(String typeName, String strExp) { + if (typeName.equals("int")) { + return "Integer.parseInt(" + strExp + ")"; + } else if (typeName.equals("float")) { + return "Float.parseFloat(" + strExp + ")"; + } else if (typeName.equals("double")) { + return "Double.parseDouble(" + strExp + ")"; + } else if (typeName.equals("boolean")) { + return "Boolean.parseBoolean(" + strExp + ")"; + } else if (typeName.startsWith("ArrayList") || typeName.startsWith("List")) { + return "Arrays.asList(" + strExp + ".replace(\"[\",\"\").replace(\"]\",\"\").split(\",\",0))"; + } else { + return strExp; + } + } + + @Override + public String getPairExp(String first, String second) { + return getConstructorInvocation(DataConstraintModel.typeTuple.getImplementationTypeName() + "<>", List.of(first, second)); + } + + @Override + public String getFirstEntryFromMapExp(String map) { + return getMethodInvocation(map, "entrySet().iterator().next"); + } + + @Override + public String getTupleGet(String tupleExp, int idx, int length) { + models.algebra.Expression t = new models.algebra.Variable(tupleExp); + for (int i = 0; i < idx; i++) { + Term next = new Term(DataConstraintModel.snd); + next.addChild(t); + t = next; + } + if (idx < length - 1) { + Term last = new Term(DataConstraintModel.fst); + last.addChild(t); + t = last; + } + return t.toImplementation(new String[]{""}); + } + + @Override + public String getDecomposedTuple(String tupleExp, VariableDeclaration tupleVar, List vars) { + String statements = ""; + statements += newVariableDeclaration(tupleVar.getType(), tupleVar.getName()) + + getAssignment() + tupleExp + getStatementDelimiter(); + for (int i = 0; i < vars.size(); i++) { + VariableDeclaration var = vars.get(i); + statements += "\n" + newVariableDeclaration(var.getType(), var.getName()) + + getAssignment() + + getTupleGet(tupleVar.getName(), i, vars.size()) + + getStatementDelimiter(); + } + return statements; + } + + @Override + public boolean isValueType(Type type) { + if (type == DataConstraintModel.typeInt + || type == DataConstraintModel.typeLong + || type == DataConstraintModel.typeFloat + || type == DataConstraintModel.typeDouble + || type == DataConstraintModel.typeBoolean) { + return true; + } + return false; + } + + + @Override + public boolean isVoidType(Type type) { + if (type == typeVoid) { + return true; + } + return false; + } + + @Override + public Type getWrapperType(Type type) { + if (type == DataConstraintModel.typeInt) { + return new Type("Integer", typeInteger); + } else if (type == DataConstraintModel.typeLong) { + return new Type("Long", typeLong); + } else if (type == DataConstraintModel.typeFloat) { + return new Type("Float", typeFloat); + } else if (type == DataConstraintModel.typeDouble) { + return new Type("Double", typeDouble); + } else if (type == DataConstraintModel.typeBoolean) { + return new Type("Boolean", typeBoolean); + } + return type; + } + + private String getImplementationTypeName(Type type) { + if (type == null) + return "Object"; + String wrapperType = DataConstraintModel.getWrapperType(type); + if (wrapperType != null) + return wrapperType; + return type.getImplementationTypeName(); + } + + private String getInterfaceTypeName(Type type) { + if (type == null) + return "Object"; + String wrapperType = DataConstraintModel.getWrapperType(type); + if (wrapperType != null) + return wrapperType; + return type.getInterfaceTypeName(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java deleted file mode 100644 index dbd0b45..0000000 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ /dev/null @@ -1,356 +0,0 @@ -package generators; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; - -import code.ast.Annotation; -import code.ast.Block; -import code.ast.CompilationUnit; -import code.ast.FieldDeclaration; -import code.ast.ImportDeclaration; -import code.ast.MethodDeclaration; -import code.ast.TypeDeclaration; -import code.ast.VariableDeclaration; -import models.Edge; -import models.Node; -import models.algebra.Expression; -import models.algebra.Field; -import models.algebra.Parameter; -import models.algebra.Symbol; -import models.algebra.Term; -import models.algebra.Type; -import models.algebra.Variable; -import models.dataConstraintModel.Channel; -import models.dataConstraintModel.ChannelMember; -import models.dataConstraintModel.DataConstraintModel; -import models.dataConstraintModel.ResourcePath; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.DataTransferChannel; -import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; -import models.dataFlowModel.PushPullAttribute; -import models.dataFlowModel.PushPullValue; -import models.dataFlowModel.DataFlowEdge; -import models.dataFlowModel.DataFlowGraph; -import models.dataFlowModel.ResourceNode; -import models.dataFlowModel.StoreAttribute; - -/** - * Generator for Jersey prototypes - * - * @author Nitta - * - */ -public class JerseyCodeGenerator { - public static final Type typeVoid = new Type("Void", "void"); - public static final Type typeClient = new Type("Client", "Client"); - private static String defaultMainTypeName = "Main"; - static String mainTypeName = defaultMainTypeName; - - public static String getMainTypeName() { - return mainTypeName; - } - - public static void setMainTypeName(String mainTypeName) { - JerseyCodeGenerator.mainTypeName = mainTypeName; - } - - public static void resetMainTypeName() { - JerseyCodeGenerator.mainTypeName = defaultMainTypeName; - } - - static public ArrayList doGenerate(DataFlowGraph graph, DataTransferModel model) { - ArrayList codes = new ArrayList<>(); -// ArrayList resources = StoreResourceCheck(graph); - Set resources = graph.getNodes(); - - for (Node n : resources) { - ResourceNode rn = (ResourceNode) n; - String resourceName = rn.getResource().getResourceName().substring(0, 1).toUpperCase() - + rn.getResource().getResourceName().substring(1); - - // Declare the field to refer each resource in the main type. - TypeDeclaration type = new TypeDeclaration(resourceName); - type.addAnnotation(new Annotation("Component")); - type.addAnnotation(new Annotation("Path", "\"/" + rn.getResource().getResourceName() + "\"")); - - // Declare a client field and update methods from other resources. - boolean bDeclareClientField = false; - for (Edge e : rn.getOutEdges()) { - DataFlowEdge re = (DataFlowEdge) e; - if (!bDeclareClientField && ((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - // Declare a client field to connect to the destination resource of push transfer. - type.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); - bDeclareClientField = true; - } - } - for (Edge e : rn.getInEdges()) { - DataFlowEdge re = (DataFlowEdge) e; - ResourcePath srcRes = ((ResourceNode) re.getSource()).getResource(); - String srcResName = srcRes.getResourceName().substring(0, 1).toUpperCase() + srcRes.getResourceName().substring(1); - if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { - if (!bDeclareClientField) { - // Declare a client field to connect to the source resource of pull transfer. - type.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); - bDeclareClientField = true; - } - } else { - // Declare an update method in the type of the destination resource. - ArrayList vars = new ArrayList<>(); - String srcName = srcRes.getResourceName(); - Type srcType = srcRes.getResourceStateType(); - VariableDeclaration param = new VariableDeclaration(srcType, srcName); - param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); - vars.add(param); - for (ResourcePath refRes: re.getChannel().getReferenceResources()) { - if (refRes != rn.getResource()) { - param = new VariableDeclaration(refRes.getResourceStateType(), refRes.getResourceName()); - param.addAnnotation(new Annotation("FormParam", "\"" + refRes.getResourceName() + "\"")); - vars.add(param); - } - } - MethodDeclaration update = new MethodDeclaration("update" + srcResName, false, typeVoid, vars); - for (ChannelMember cm: re.getChannel().getOutputChannelMembers()) { - if (cm.getResource() == rn.getResource()) { - if (cm.getStateTransition().isRightUnary()) { - update.addAnnotation(new Annotation("PUT")); - } else { - update.addAnnotation(new Annotation("POST")); - } - } - } - if (rn.getInEdges().size() > 1) { - // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. - update.addAnnotation(new Annotation("Path", "\"/" + srcName + "\"")); - // Declare a field to cash the state of the source resource in the type of the destination resource. - ResourcePath cashResId = ((ResourceNode) re.getSource()).getResource(); - type.addField(new FieldDeclaration(cashResId.getResourceStateType(), srcName, getInitializer(cashResId))); - } - type.addMethod(update); - } - } - -// // Declare a client field to connect to the source resource of reference transfer. -// if (!bDeclareClientField) { -// for (ChannelGenerator cg : model.getChannelGenerators()) { -// DataflowChannelGenerator dcg = ((DataflowChannelGenerator) cg); -// for (ChannelMember cm : dcg.getOutputChannelMembers()) { -// if (cm.getIdentifierTemplate().getResourceName().equals(type.getTypeName().toLowerCase())) { -// if (dcg.getReferenceChannelMembers().size() > 0) { -// // If there exists one or more reference channel member. -// type.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); -// bDeclareClientField = true; -// break; -// } -// } -// } -// if (bDeclareClientField) break; -// } -// } - - // Declare input methods in resources. - for (Channel cg : model.getIOChannels()) { - for (ChannelMember cm : ((DataTransferChannel) cg).getOutputChannelMembers()) { - if (cm.getResource().equals(rn.getResource())) { - Expression message = cm.getStateTransition().getMessageExpression(); - if (message.getClass() == Term.class) { - ArrayList params = new ArrayList<>(); - for (Variable var: message.getVariables().values()) { - String paramName = var.getName(); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("FormParam", "\"" + paramName + "\"")); - params.add(param); - } - MethodDeclaration input = new MethodDeclaration( - ((Term) cm.getStateTransition().getMessageExpression()).getSymbol().getImplName(), - false, typeVoid, params); - if (cm.getStateTransition().isRightUnary()) { - input.addAnnotation(new Annotation("PUT")); - } else { - input.addAnnotation(new Annotation("POST")); - } - type.addMethod(input); - } else if (message.getClass() == Variable.class) { - MethodDeclaration input = new MethodDeclaration( - ((Variable) cm.getStateTransition().getMessageExpression()).getName(), - false, typeVoid, null); - if (cm.getStateTransition().isRightUnary()) { - input.addAnnotation(new Annotation("PUT")); - } else { - input.addAnnotation(new Annotation("POST")); - } - type.addMethod(input); - } - } - } - } - - // Declare the field to store the state in the type of each resource. - if (((StoreAttribute) rn.getAttribute()).isStored()) { - ResourcePath resId = rn.getResource(); - type.addField(new FieldDeclaration(resId.getResourceStateType(), "value", getInitializer(resId))); - } - - // Declare the getter method to obtain the state in the type of each resource. - MethodDeclaration getter = new MethodDeclaration("getValue", rn.getResource().getResourceStateType()); - getter.addAnnotation(new Annotation("Produces", "MediaType.APPLICATION_JSON")); - getter.addAnnotation(new Annotation("GET")); - type.addMethod(getter); - - // Add compilation unit for each resource. - CompilationUnit cu = new CompilationUnit(type); - cu.addImport(new ImportDeclaration("java.util.*")); - cu.addImport(new ImportDeclaration("javax.ws.rs.*")); - cu.addImport(new ImportDeclaration("javax.ws.rs.client.*")); - cu.addImport(new ImportDeclaration("javax.ws.rs.core.*")); - cu.addImport(new ImportDeclaration("org.springframework.stereotype.Component")); - cu.addImport(new ImportDeclaration("com.fasterxml.jackson.databind.ObjectMapper")); - cu.addImport(new ImportDeclaration("com.fasterxml.jackson.core.JsonProcessingException")); - codes.add(cu); - } - - // Declare the Pair class. - boolean isCreatedPair = false; - for(Node n : resources) { - ResourceNode rn = (ResourceNode) n; - if(isCreatedPair) continue; - if(model.getType("Pair").isAncestorOf(rn.getResource().getResourceStateType())) { - TypeDeclaration type = new TypeDeclaration("Pair"); - type.addField(new FieldDeclaration(new Type("Double", "T"), "left")); - type.addField(new FieldDeclaration(new Type("Double", "T"), "right")); - - MethodDeclaration constructor = new MethodDeclaration("Pair", true); - constructor.addParameter(new VariableDeclaration(new Type("Double", "T"), "left")); - constructor.addParameter(new VariableDeclaration(new Type("Double", "T"), "right")); - Block block = new Block(); - block.addStatement("this.left = left;"); - block.addStatement("this.right = right;"); - constructor.setBody(block); - type.addMethod(constructor); - - for(FieldDeclaration field : type.getFields()) { - MethodDeclaration getter = new MethodDeclaration( - "get" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1), - new Type("Double","T")); - getter.setBody(new Block()); - getter.getBody().addStatement("return " + field.getName() + ";"); - type.addMethod(getter); - } - -// MethodDeclaration toStr = new MethodDeclaration("toString", false, DataConstraintModel.typeString, null); -// block = new Block(); -// block.addStatement("return \"{\\\"\" + left + \"\\\":\\\"\" + right + \"\\\"}\";"); -// toStr.setBody(block); -// type.addMethod(toStr); - - CompilationUnit cu = new CompilationUnit(type); - cu.addImport(new ImportDeclaration("java.util.*")); - codes.add(cu); - - isCreatedPair = true; - } - } - - return codes; - } - - private static String getInitializer(ResourcePath resId) { - Type stateType = resId.getResourceStateType(); - String initializer = null; - if (resId.getInitialValue() != null) { - initializer = resId.getInitialValue().toImplementation(new String[] {""}); - } else { - if (DataConstraintModel.typeList.isAncestorOf(stateType)) { - initializer = "new " + resId.getResourceStateType().getImplementationTypeName() + "()"; - } else if (DataConstraintModel.typeMap.isAncestorOf(stateType)) { - initializer = "new " + resId.getResourceStateType().getImplementationTypeName() + "()"; - } - } - return initializer; - } - - static public ArrayList getCodes(ArrayList codeTree) { - ArrayList codes = new ArrayList<>(); - for (TypeDeclaration type : codeTree) { - codes.add("public class " + type.getTypeName() + "{"); - for (FieldDeclaration field : type.getFields()) { - if (type.getTypeName() != mainTypeName) { - String cons = "\t" + "private " + field.getType().getInterfaceTypeName() + " " - + field.getName(); - if (DataConstraintModel.isListType(field.getType())) - cons += " = new " + field.getType().getImplementationTypeName() + "()"; - cons += ";"; - codes.add(cons); - } else { - String cons = "\t" + "private " + field.getType().getInterfaceTypeName() + " " - + field.getName() + " = new " + field.getType().getTypeName() + "("; - cons += ");"; - codes.add(cons); - } - } - codes.add(""); - for (MethodDeclaration method : type.getMethods()) { - String varstr = "\t" + "public " + method.getReturnType().getInterfaceTypeName() + " " - + method.getName() + "("; - if (method.getParameters() != null) { - for (VariableDeclaration var : method.getParameters()) { - varstr += var.getType().getInterfaceTypeName() + " " + var.getName() + ","; - } - if (!method.getParameters().isEmpty()) - varstr = varstr.substring(0, varstr.length() - 1); - } - if (method.getBody() != null) { - for (String str : method.getBody().getStatements()) { - codes.add("\t\t" + str + ";"); - } - } - codes.add(varstr + ")" + "{"); - codes.add("\t" + "}"); - codes.add(""); - } - codes.add("}"); - codes.add(""); - } - return codes; - } - - static public IResourceStateAccessor pushAccessor = new IResourceStateAccessor() { - @Override - public Expression getCurrentStateAccessorFor(ResourcePath target, ResourcePath from) { - if (target.equals(from)) { - return new Field("value", - target.getResourceStateType() != null ? target.getResourceStateType() - : DataConstraintModel.typeInt); - } - return null; - } - - @Override - public Expression getNextStateAccessorFor(ResourcePath target, ResourcePath from) { - return new Parameter(target.getResourceName(), - target.getResourceStateType() != null ? target.getResourceStateType() - : DataConstraintModel.typeInt); - } - }; - static public IResourceStateAccessor pullAccessor = new IResourceStateAccessor() { - @Override - public Expression getCurrentStateAccessorFor(ResourcePath target, ResourcePath from) { - if (target.equals(from)) { - return new Field("value", - target.getResourceStateType() != null ? target.getResourceStateType() - : DataConstraintModel.typeInt); - } - // for reference channel member - return new Parameter(target.getResourceName(), - target.getResourceStateType() != null ? target.getResourceStateType() - : DataConstraintModel.typeInt); - } - - @Override - public Expression getNextStateAccessorFor(ResourcePath target, ResourcePath from) { - return new Parameter(target.getResourceName(), - target.getResourceStateType() != null ? target.getResourceStateType() - : DataConstraintModel.typeInt); - } - }; -} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java deleted file mode 100644 index cdaf898..0000000 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ /dev/null @@ -1,597 +0,0 @@ -package generators; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import algorithms.TypeInference; -import code.ast.CodeUtil; -import code.ast.CompilationUnit; -import code.ast.MethodDeclaration; -import code.ast.TypeDeclaration; -import code.ast.VariableDeclaration; -import models.Edge; -import models.Node; -import models.algebra.Expression; -import models.algebra.InvalidMessage; -import models.algebra.ParameterizedIdentifierIsFutureWork; -import models.algebra.Term; -import models.algebra.Type; -import models.algebra.UnificationFailed; -import models.algebra.ValueUndefined; -import models.algebra.Variable; -import models.dataConstraintModel.Channel; -import models.dataConstraintModel.ChannelMember; -import models.dataConstraintModel.DataConstraintModel; -import models.dataConstraintModel.ResourcePath; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.DataTransferChannel; -import models.dataFlowModel.PushPullAttribute; -import models.dataFlowModel.PushPullValue; -import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; -import models.dataFlowModel.DataFlowEdge; -import models.dataFlowModel.DataFlowGraph; -import models.dataFlowModel.ResourceNode; -import models.dataFlowModel.StoreAttribute; -import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; - -public class JerseyMethodBodyGenerator { - private static String baseURL = "http://localhost:8080"; - - public static ArrayList doGenerate(DataFlowGraph graph, DataTransferModel model, ArrayList codes) { - // Create a map from type names (lower case) to their types. - Map typeMap = new HashMap<>(); - for (CompilationUnit code: codes) { - for (TypeDeclaration type: code.types()) { - typeMap.put(type.getTypeName().substring(0,1).toLowerCase() + type.getTypeName().substring(1), type); - } - } - - // Generate the body of each update or getter method. - try { - Set chainedCalls = new HashSet<>(); - Map> referredResources = new HashMap<>(); - for (Edge e: graph.getEdges()) { - DataFlowEdge d = (DataFlowEdge) e; - PushPullAttribute pushPull = (PushPullAttribute) d.getAttribute(); - ResourceNode src = (ResourceNode) d.getSource(); - ResourceNode dst = (ResourceNode) d.getDestination(); - String srcResourceName = src.getResource().getResourceName(); - String dstResourceName = dst.getResource().getResourceName(); - TypeDeclaration srcType = typeMap.get(srcResourceName); - TypeDeclaration dstType = typeMap.get(dstResourceName); - for (ChannelMember out: d.getChannel().getOutputChannelMembers()) { - if (out.getResource() == dst.getResource()) { - if (pushPull.getOptions().get(0) == PushPullValue.PUSH && srcType != null) { - // for push data transfer - MethodDeclaration update = getUpdateMethod(dstType, srcType); - if (((StoreAttribute) dst.getAttribute()).isStored()) { - // update stored state of dst side resource (when every incoming edge is in push style) - Expression updateExp = null; - if (d.getChannel().getReferenceChannelMembers().size() == 0) { - updateExp = d.getChannel().deriveUpdateExpressionOf(out, JerseyCodeGenerator.pushAccessor); - } else { - // if there exists one or more reference channel member. - HashMap inputResourceToStateAccessor = new HashMap<>(); - for (Edge eIn: dst.getInEdges()) { - DataFlowEdge dIn = (DataFlowEdge) eIn; - inputResourceToStateAccessor.put(((ResourceNode) dIn.getSource()).getResource(), JerseyCodeGenerator.pushAccessor); - } - for (ChannelMember c: d.getChannel().getReferenceChannelMembers()) { - inputResourceToStateAccessor.put(c.getResource(), JerseyCodeGenerator.pullAccessor); - } - updateExp = d.getChannel().deriveUpdateExpressionOf(out, JerseyCodeGenerator.pushAccessor, inputResourceToStateAccessor); - } - String[] sideEffects = new String[] {""}; - String curState = updateExp.toImplementation(sideEffects); - String updateStatement; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - updateStatement = sideEffects[0]; - } else { - updateStatement = sideEffects[0] + "this.value = " + curState + ";"; - } - if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { - // add an update statement of the state of dst side resource. - update.addFirstStatement(updateStatement); - } - } - if (dst.getIndegree() > 1) { - // update a cash of src side resource (when incoming edges are multiple) - String cashStatement = "this." + srcResourceName + " = " + srcResourceName + ";"; - if (update.getBody() == null || !update.getBody().getStatements().contains(cashStatement)) { - update.addFirstStatement(cashStatement); - } - } - // to convert a json param to a tuple, pair or map object. - for (VariableDeclaration param: update.getParameters()) { - Type paramType = param.getType(); - String paramName = param.getName(); - String paramConverter = ""; - if (DataConstraintModel.typeList.isAncestorOf(paramType) && paramType != DataConstraintModel.typeList) { - Type compType = TypeInference.getListComponentType(paramType); - if (DataConstraintModel.typeTuple.isAncestorOf(compType)) { - param.setType(DataConstraintModel.typeListStr); - param.setName(paramName + "_json"); - paramConverter += paramType.getInterfaceTypeName() + " " + paramName + " = new " + paramType.getImplementationTypeName() + "();\n"; - paramConverter += "for (String str: " + param.getName() + ") {\n"; - String mapTypeName = convertFromEntryToMapType(compType); - paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(str, HashMap.class);\n"; - paramConverter += "\t" + paramName + ".add(" + getCodeForConversionFromMapToTuple(compType, "i") + ");\n"; - paramConverter += "}"; - update.addThrow("JsonProcessingException"); - } else if (DataConstraintModel.typePair.isAncestorOf(compType)) { - param.setType(DataConstraintModel.typeListStr); - param.setName(paramName + "_json"); - paramConverter += paramType.getInterfaceTypeName() + " " + paramName + " = new " + paramType.getImplementationTypeName() + "();\n"; - paramConverter += "for (String str: " + param.getName() + ") {\n"; - String mapTypeName = convertFromEntryToMapType(compType); - paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(str, HashMap.class);\n"; - paramConverter += "\t" + paramName + ".add(" + getCodeForConversionFromMapToPair(compType, "i") + ");\n"; - paramConverter += "}"; - update.addThrow("JsonProcessingException"); - } else if (DataConstraintModel.typeMap.isAncestorOf(compType)) { - param.setType(DataConstraintModel.typeListStr); - // To do. - } - } else if (DataConstraintModel.typeTuple.isAncestorOf(paramType)) { - param.setType(DataConstraintModel.typeString); - param.setName(paramName + "_json"); - paramConverter += paramType.getInterfaceTypeName() + " " + paramName + ";\n"; - paramConverter += "{\n"; - String mapTypeName = convertFromEntryToMapType(paramType); - paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(" + paramName + "_json" + ", HashMap.class);\n"; - paramConverter += "\t" + paramName + " = " + getCodeForConversionFromMapToTuple(paramType, "i") + ";\n"; - paramConverter += "}"; - update.addThrow("JsonProcessingException"); - } else if (DataConstraintModel.typePair.isAncestorOf(paramType)) { - param.setType(DataConstraintModel.typeString); - param.setName(paramName + "_json"); - paramConverter += paramType.getInterfaceTypeName() + " " + paramName + ";\n"; - paramConverter += "{\n"; - String mapTypeName = convertFromEntryToMapType(paramType); - paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(" + paramName + "_json" + ", HashMap.class);\n"; - paramConverter += "\t" + paramName + " = " + getCodeForConversionFromMapToPair(paramType, "i") + ";\n"; - paramConverter += "}"; - update.addThrow("JsonProcessingException"); - } else if (DataConstraintModel.typeMap.isAncestorOf(paramType)) { - param.setType(DataConstraintModel.typeString); - param.setName(paramName + "_json"); - paramConverter += paramType.getInterfaceTypeName() + " " + paramName + " = " + "new " + paramType.getImplementationTypeName() + "();\n"; - paramConverter += "{\n"; - String mapTypeName = convertFromEntryToMapType(paramType); - paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(" + paramName + "_json" + ", HashMap.class);\n"; - paramConverter += "\t" + getCodeForConversionFromMapToMap(paramType, "i", paramName) + "\n"; - paramConverter += "}"; - update.addThrow("JsonProcessingException"); - } - if (paramConverter.length() > 0) update.addFirstStatement(paramConverter); - } - MethodDeclaration getter = getGetterMethod(dstType); - if (((StoreAttribute) dst.getAttribute()).isStored()) { - // returns the state stored in a field. - if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - getter.addStatement("return value;"); - } - } - // src side (for a chain of update method invocations) - String httpMethod = null; - if (out.getStateTransition().isRightUnary()) { - httpMethod = "put"; - } else { - httpMethod = "post"; - } - for (MethodDeclaration srcUpdate: getUpdateMethods(srcType)) { - if (srcUpdate != null) { - List>> params = new ArrayList<>(); - Set referredSet = referredResources.get(srcUpdate); - if (d.getChannel().getReferenceChannelMembers().size() > 0) { - for (ChannelMember rc: d.getChannel().getReferenceChannelMembers()) { - // For each reference channel member, get the current state of the reference side resource by pull data transfer. - ResourcePath ref = rc.getResource(); - if (referredSet == null) { - referredSet = new HashSet<>(); - referredResources.put(srcUpdate, referredSet); - } - if (ref != dst.getResource()) { - String refResourceName = ref.getResourceName(); - Type refResourceType = ref.getResourceStateType(); - if (!referredSet.contains(ref)) { - referredSet.add(ref); - generatePullDataTransfer(srcUpdate, refResourceName, refResourceType); - } - // Value of a reference side resource. - params.add(new AbstractMap.SimpleEntry<>(refResourceType, new AbstractMap.SimpleEntry<>(refResourceName, refResourceName))); - } - } - } - String srcResName = null; - if (dst.getIndegree() > 1) { - srcResName = srcResourceName; - } - if (!chainedCalls.contains(srcUpdate)) { - // The first call to an update method in this method - // Value of the source side (input side) resource. - params.add(0, new AbstractMap.SimpleEntry<>(src.getResource().getResourceStateType(), new AbstractMap.SimpleEntry<>(srcResourceName, "this.value"))); - srcUpdate.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), params, true)); - srcUpdate.addStatement("String result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); - chainedCalls.add(srcUpdate); - } else { - // After the second time of call to update methods in this method - // Value of the source side (input side) resource. - params.add(0, new AbstractMap.SimpleEntry<>(src.getResource().getResourceStateType(), new AbstractMap.SimpleEntry<>(srcResourceName, "this.value"))); - srcUpdate.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), params, false)); - srcUpdate.addStatement("result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); - } - srcUpdate.addThrow("JsonProcessingException"); - } - } - for (MethodDeclaration srcInput: getInputMethods(srcType, src, model)) { - List>> params = new ArrayList<>(); - Set referredSet = referredResources.get(srcInput); - for (ChannelMember rc: d.getChannel().getReferenceChannelMembers()) { - // For each reference channel member, get the current state of the reference side resource by pull data transfer. - ResourcePath ref = rc.getResource(); - if (referredSet == null) { - referredSet = new HashSet<>(); - referredResources.put(srcInput, referredSet); - } - if (ref != dst.getResource()) { - String refResourceName = ref.getResourceName(); - Type refResourceType = ref.getResourceStateType(); - if (!referredSet.contains(ref)) { - referredSet.add(ref); - generatePullDataTransfer(srcInput, refResourceName, refResourceType); - } - // Value of a reference side resource. - params.add(new AbstractMap.SimpleEntry<>(refResourceType, new AbstractMap.SimpleEntry<>(refResourceName, refResourceName))); - } - } - String srcResName = null; - if (dst.getIndegree() > 1) { - srcResName = srcResourceName; - } - if (!chainedCalls.contains(srcInput)) { - // First call to an update method in this method - // Value of the source side (input side) resource. - params.add(0, new AbstractMap.SimpleEntry<>(src.getResource().getResourceStateType(), new AbstractMap.SimpleEntry<>(srcResourceName, "this.value"))); - srcInput.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), params, true)); - srcInput.addStatement("String result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); - chainedCalls.add(srcInput); - } else { - // After the second time of call to update methods in this method - // Value of the source side (input side) resource. - params.add(0, new AbstractMap.SimpleEntry<>(src.getResource().getResourceStateType(), new AbstractMap.SimpleEntry<>(srcResourceName, "this.value"))); - srcInput.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), params, false)); - srcInput.addStatement("result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); - } - srcInput.addThrow("JsonProcessingException"); - } - } else { - // for pull (or push/pull) data transfer - MethodDeclaration getter = getGetterMethod(dstType); - if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - // generate a return statement. - String[] sideEffects = new String[] {""}; - String curState = d.getChannel().deriveUpdateExpressionOf(out, JerseyCodeGenerator.pullAccessor).toImplementation(sideEffects); // no pull data transfer is included. - getter.addStatement(sideEffects[0] + "return " + curState + ";"); - // For each reference channel member, get the current state of the reference side resource by pull data transfer. - for (ChannelMember c: d.getChannel().getReferenceChannelMembers()) { - String refResourceName = c.getResource().getResourceName(); - Type refResourceType = c.getResource().getResourceStateType(); - generatePullDataTransfer(getter, refResourceName, refResourceType); - } - } - // get src side resource state by pull data transfer. - Type srcResourceType = src.getResource().getResourceStateType(); - generatePullDataTransfer(getter, srcResourceName, srcResourceType); - } - } - } - } - // for source nodes - for (Node n: graph.getNodes()) { - ResourceNode resource = (ResourceNode) n; - String resourceName = resource.getResource().getResourceName(); - TypeDeclaration type = typeMap.get(resourceName); - if (type != null) { - // getter method - MethodDeclaration getter = getGetterMethod(type); - if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - getter.addStatement("return value;"); - } - // methods for input events - Map> ioChannelsAndMembers = getIOChannelsAndMembers(resource, model); - for (Map.Entry> entry: ioChannelsAndMembers.entrySet()) { - Set outs = entry.getValue(); - for (ChannelMember out: outs) { - MethodDeclaration input = getInputMethod(type, out); - if (input != null) { - Expression updateExp = entry.getKey().deriveUpdateExpressionOf(out, JerseyCodeGenerator.pushAccessor); - String[] sideEffects = new String[] {""}; - String newState = updateExp.toImplementation(sideEffects); - String updateStatement; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - updateStatement = sideEffects[0]; - } else { - updateStatement = sideEffects[0] + "this.value = " + newState + ";"; - } - if (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement)) { - input.addFirstStatement(updateStatement); - } - } - } - } - } - } - } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork - | InvalidMessage | UnificationFailed | ValueUndefined e1) { - e1.printStackTrace(); - } - return codes; - } - - private static void generatePullDataTransfer(MethodDeclaration methodBody, String fromResourceName, Type fromResourceType) { - String varName = new String(fromResourceName); - String respTypeName = fromResourceType.getInterfaceTypeName(); - String respImplTypeName = fromResourceType.getImplementationTypeName(); - String respConverter = ""; - if (DataConstraintModel.typeList.isAncestorOf(fromResourceType) && fromResourceType != DataConstraintModel.typeList) { - Type compType = TypeInference.getListComponentType(fromResourceType); - if (DataConstraintModel.typeTuple.isAncestorOf(compType)) { - varName += "_json"; - String mapTypeName = convertFromEntryToMapType(compType); - respTypeName = "List<" + mapTypeName + ">"; - respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + " = new " + fromResourceType.getImplementationTypeName() + "();\n"; - respConverter += "for (" + mapTypeName + " i: " + varName + ") {\n"; - respConverter += "\t" + fromResourceName + ".add(" + getCodeForConversionFromMapToTuple(compType, "i") + ");\n"; - respConverter += "}"; - methodBody.addThrow("JsonProcessingException"); - } else if (DataConstraintModel.typeMap.isAncestorOf(compType)) { - // To do. - } - } else if (DataConstraintModel.typeTuple.isAncestorOf(fromResourceType)) { - varName += "_json"; - respTypeName = convertFromEntryToMapType(fromResourceType); - respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + " = " + getCodeForConversionFromMapToTuple(fromResourceType, varName) + ";"; - respImplTypeName = "HashMap"; - } else if (DataConstraintModel.typePair.isAncestorOf(fromResourceType)) { - varName += "_json"; - respTypeName = convertFromEntryToMapType(fromResourceType); - respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + " = " + getCodeForConversionFromMapToPair(fromResourceType, varName) + ";"; - respImplTypeName = "HashMap"; - } else if (DataConstraintModel.typeMap.isAncestorOf(fromResourceType)) { - varName += "_json"; - respTypeName = convertFromEntryToMapType(fromResourceType); - respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + " = new " + fromResourceType.getImplementationTypeName() + "();\n"; - respConverter += getCodeForConversionFromMapToMap(fromResourceType, varName, fromResourceName); - respImplTypeName = "HashMap"; - } - if (respConverter.length() > 0) { - methodBody.addFirstStatement(respConverter); - } - methodBody.addFirstStatement(respTypeName + " " + varName + " = " + getHttpMethodCallStatementWithResponse(baseURL, fromResourceName, "get", respImplTypeName)); - } - - private static String convertFromEntryToMapType(Type type) { - String mapTypeName = null; - if (DataConstraintModel.typePair.isAncestorOf(type)) { - Type compType = TypeInference.getPairComponentType(type); - String wrapperType = DataConstraintModel.getWrapperType(compType); - if (wrapperType != null) { - mapTypeName = "Map"; - } else { - mapTypeName = "Map"; - } - } else if (DataConstraintModel.typeMap.isAncestorOf(type)) { - List compTypes = TypeInference.getMapComponentTypes(type); - String wrapperType = DataConstraintModel.getWrapperType(compTypes.get(1)); - if (wrapperType != null) { - mapTypeName = "Map"; - } else { - mapTypeName = "Map"; - } - } else { - mapTypeName = type.getInterfaceTypeName(); - mapTypeName = mapTypeName.replace("Map.Entry", "Map"); - for (int idx = mapTypeName.indexOf("<", 0); idx >= 0; idx = mapTypeName.indexOf("<", idx + 1)) { - int to = mapTypeName.indexOf(",", idx); - if (to > idx) { - mapTypeName = mapTypeName.substring(0, idx + 1) + "String" + mapTypeName.substring(to); // All elements except for the last one have the string type. - } - } - } - return mapTypeName; - } - - private static String getCodeForConversionFromMapToTuple(Type tupleType, String mapVar) { - String decoded = "$x"; - List elementsTypes = TypeInference.getTupleComponentTypes(tupleType); - String elementBase = mapVar; - for (Type elmType: elementsTypes.subList(0, elementsTypes.size() - 1)) { - elementBase += ".entrySet().iterator().next()"; - if (elmType == DataConstraintModel.typeBoolean - || elmType == DataConstraintModel.typeInt - || elmType == DataConstraintModel.typeLong - || elmType == DataConstraintModel.typeFloat - || elmType == DataConstraintModel.typeDouble) { - String elmVal = CodeUtil.getToValueExp(elmType.getImplementationTypeName(), elementBase + ".getKey()"); - decoded = decoded.replace("$x", "new AbstractMap.SimpleEntry<>(" + elmVal + ", $x)"); - } else if (elmType == DataConstraintModel.typeString) { - decoded = decoded.replace("$x", "new AbstractMap.SimpleEntry<>(" + elementBase + ".getKey(), $x)"); - } else { - // To do. - } - elementBase += ".getValue()"; - } - decoded = decoded.replace("$x", elementBase); - return decoded; - } - - private static String getCodeForConversionFromMapToPair(Type pairType, String mapVar) { - String decoded = "$x"; - decoded = decoded.replace("$x", "new Pair<>(" + mapVar + ".get(\"left\"), $x)"); - decoded = decoded.replace("$x", mapVar + ".get(\"right\")"); - return decoded; - } - - private static String getCodeForConversionFromMapToMap(Type mapType, String mapVal, String mapVar) { - List elementsTypes = TypeInference.getMapComponentTypes(mapType); - Type keyType = elementsTypes.get(0); - Type valType = elementsTypes.get(1); - String keyVal = null; - String decoded = ""; - if (keyType == DataConstraintModel.typeBoolean - || keyType == DataConstraintModel.typeInt - || keyType == DataConstraintModel.typeLong - || keyType == DataConstraintModel.typeFloat - || keyType == DataConstraintModel.typeDouble) { - decoded += "for (String k: " + mapVal + ".keySet()) {\n"; - decoded += "\t" + mapVar + ".put("; - keyVal = CodeUtil.getToValueExp(keyType.getImplementationTypeName(), "k"); - decoded += keyVal + ", " + mapVal + ".get(" + keyVal + ")" + ");\n"; - decoded += "}"; - } else if (keyType == DataConstraintModel.typeString) { - decoded += mapVar + " = " + mapVal + ";"; - } - return decoded; - } - - private static String getHttpMethodParamsStatement(String callerResourceName, List>> params, boolean isFirstCall) { - String statements = ""; - if (isFirstCall) { - statements += "Form "; - } - statements += "form = new Form();\n"; - for (Map.Entry> param: params) { - Type paramType = param.getKey(); - String paramName = param.getValue().getKey(); - String value = param.getValue().getValue(); - if (DataConstraintModel.typeList.isAncestorOf(paramType)) { - Type compType = TypeInference.getListComponentType(paramType); - String wrapperType = DataConstraintModel.getWrapperType(compType); - if (wrapperType == null) { - statements += "for (" + compType.getInterfaceTypeName() + " i: " + value + ") {\n"; - } else { - statements += "for (" + wrapperType + " i: " + value + ") {\n"; - } - if (DataConstraintModel.typeTuple.isAncestorOf(compType) || DataConstraintModel.typePair.isAncestorOf(paramType) || DataConstraintModel.typeList.isAncestorOf(compType) || DataConstraintModel.typeMap.isAncestorOf(paramType)) { - statements += "\tform.param(\"" + paramName + "\", new ObjectMapper().writeValueAsString(i));\n"; // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} - } else { - statements += "\tform.param(\"" + paramName + "\", i.toString());\n"; - } - statements += "}\n"; -// return "Entity entity = Entity.entity(" + paramName + ".toString(), MediaType.APPLICATION_JSON);"; - } else if (DataConstraintModel.typeTuple.isAncestorOf(paramType) || DataConstraintModel.typePair.isAncestorOf(paramType) || DataConstraintModel.typeMap.isAncestorOf(paramType)) { - // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} - statements += "form.param(\"" + paramName + "\", new ObjectMapper().writeValueAsString(" + value + "));\n"; - } else { - statements += "form.param(\"" + paramName + "\", " + CodeUtil.getToStringExp(paramType.getImplementationTypeName(), value) + ");\n"; - } - } - if (isFirstCall) { - statements += "Entity "; - } - statements += "entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED);"; - return statements; - } - - private static String getHttpMethodCallStatement(String baseURL, String resourceName, String srcResName, String httpMethod) { - if (srcResName == null) { - return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "\").request()." + httpMethod + "(entity, String.class);"; - } else { - // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. - return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "/" + srcResName + "\").request()." + httpMethod + "(entity, String.class);"; - } - } - - private static String getHttpMethodCallStatementWithResponse(String baseURL, String resourceName, String httpMethod, String respImplName) { - String responseShortTypeName = respImplName; - if (respImplName.contains("<")) { - responseShortTypeName = respImplName.substring(0, respImplName.indexOf("<")); - } - return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "\").request()." + httpMethod + "(" + responseShortTypeName + ".class);"; - } - - private static MethodDeclaration getUpdateMethod(TypeDeclaration type, TypeDeclaration from) { - for (MethodDeclaration m: type.getMethods()) { - if (m.getName().equals("update" + from.getTypeName())) return m; - } - return null; - } - - private static List getUpdateMethods(TypeDeclaration type) { - List updates = new ArrayList<>(); - for (MethodDeclaration m: type.getMethods()) { - if (m.getName().startsWith("update")) { - updates.add(m); - } - } - return updates; - } - - private static MethodDeclaration getGetterMethod(TypeDeclaration type) { - for (MethodDeclaration m: type.getMethods()) { - if (m.getName().startsWith("get")) return m; - } - return null; - } - - private static Map> getIOChannelsAndMembers(ResourceNode resource, DataTransferModel model) { - Map> ioChannelsAndMembers = new HashMap<>(); - for (Channel c: model.getIOChannels()) { - DataTransferChannel ch = (DataTransferChannel) c; - // I/O channel - for (ChannelMember out: ch.getOutputChannelMembers()) { - if (out.getResource().equals(resource.getResource())) { - if (out.getStateTransition().getMessageExpression() instanceof Term || out.getStateTransition().getMessageExpression() instanceof Variable) { - Set channelMembers = ioChannelsAndMembers.get(ch); - if (channelMembers == null) { - channelMembers = new HashSet<>(); - ioChannelsAndMembers.put(ch, channelMembers); - } - channelMembers.add(out); - } - } - } - } - return ioChannelsAndMembers; - } - - private static List getInputMethods(TypeDeclaration type, ResourceNode resource, DataTransferModel model) { - List inputs = new ArrayList<>(); - for (Channel c: model.getIOChannels()) { - DataTransferChannel channel = (DataTransferChannel) c; - // I/O channel - for (ChannelMember out: channel.getOutputChannelMembers()) { - if (out.getResource().equals(resource.getResource())) { - MethodDeclaration input = getInputMethod(type, out); - inputs.add(input); - } - } - } - return inputs; - } - - private static MethodDeclaration getInputMethod(TypeDeclaration type, ChannelMember out) { - MethodDeclaration input = null; - if (out.getStateTransition().getMessageExpression() instanceof Term) { - Term message = (Term) out.getStateTransition().getMessageExpression(); - input = getMethod(type, message.getSymbol().getImplName()); - } else if (out.getStateTransition().getMessageExpression() instanceof Variable) { - Variable message = (Variable) out.getStateTransition().getMessageExpression(); - input = getMethod(type, message.getName()); - } - return input; - } - - private static MethodDeclaration getMethod(TypeDeclaration type, String methodName) { - for (MethodDeclaration m: type.getMethods()) { - if (m.getName().equals(methodName)) return m; - } - return null; - } -} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java new file mode 100644 index 0000000..dd5e93b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java @@ -0,0 +1,176 @@ +package generators; + +import java.util.List; +import java.util.Map; + +import code.ast.Annotation; +import code.ast.Block; +import code.ast.CompilationUnit; +import code.ast.EnhancedForStatement; +import code.ast.FieldDeclaration; +import code.ast.ImportDeclaration; +import code.ast.MethodDeclaration; +import code.ast.TypeDeclaration; +import code.ast.VariableDeclaration; +import models.algebra.Type; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ListType; + +public class JerseySpecific extends RestApiSpecific { + public static final Type typeClient = new Type("Client", new code.ast.SimpleType("Client")); + + public JerseySpecific() { + langSpec = new JavaSpecific(); + } + + @Override + public void addComponentAnnotations(TypeDeclaration component, String resourcePath) { + component.addAnnotation(new Annotation("Component")); + component.addAnnotation(new Annotation("Path", "\"/" + resourcePath + "\"")); + } + + @Override + public void addGetAnnotations(MethodDeclaration getMethod) { + getMethod.addAnnotation(new Annotation("Produces", "MediaType.APPLICATION_JSON")); + getMethod.addAnnotation(new Annotation("GET")); + } + + @Override + public void addPutAnnotations(MethodDeclaration putMethod) { + putMethod.addAnnotation(new Annotation("PUT")); + } + + @Override + public void addPostAnnotations(MethodDeclaration postMethod) { + postMethod.addAnnotation(new Annotation("POST")); + } + + @Override + public void addDeleteAnnotations(MethodDeclaration deleteMethod) { + deleteMethod.addAnnotation(new Annotation("DELETE")); + } + + @Override + public void addPathAnnotation(MethodDeclaration method, String resourcePath) { + method.addAnnotation(new Annotation("Path", "\"" + resourcePath + "\"")); + } + + @Override + public void addPathParamAnnotation(VariableDeclaration var, String paramName) { + var.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); + } + + @Override + public void addFormParamAnnotation(VariableDeclaration var, String paramName) { + var.addAnnotation(new Annotation("FormParam", "\"" + paramName + "\"")); + } + + @Override + public void addPlatformSpecificImports(CompilationUnit cu) { + cu.addImport(new ImportDeclaration("jakarta.ws.rs.*")); + cu.addImport(new ImportDeclaration("jakarta.ws.rs.client.*")); + cu.addImport(new ImportDeclaration("jakarta.ws.rs.core.*")); +// cu.addImport(new ImportDeclaration("javax.ws.rs.*")); +// cu.addImport(new ImportDeclaration("javax.ws.rs.client.*")); +// cu.addImport(new ImportDeclaration("javax.ws.rs.core.*")); + cu.addImport(new ImportDeclaration("org.springframework.stereotype.Component")); + cu.addImport(new ImportDeclaration("com.fasterxml.jackson.databind.ObjectMapper")); + cu.addImport(new ImportDeclaration("com.fasterxml.jackson.core.JsonProcessingException")); + } + + @Override + public boolean hasHttpClientFieldDeclaration(TypeDeclaration component) { + for (FieldDeclaration field: component.getFields()) { + if (field.getType().equals(typeClient)) { + return true; + } + } + return false; + } + + @Override + public void addHttpClientFieldDeclaration(TypeDeclaration component) { + FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); + component.addField(clientField); + } + + @Override + public String getConversionFromJsonString(String fromStrVarName, String toVarName, String toVarType) { + return toVarType + toVarName + langSpec.getAssignment() + langSpec.getConstructorInvocation("ObjectMapper", null) + ".readValue(" + fromStrVarName + ", HashMap.class)"; + } + + @Override + public String getHttpMethodParamsConstructionStatement(String callerResourceName, List>> params, boolean isFirstCall) { + String statements = ""; + if (isFirstCall) { + statements += "Form "; + } + statements += "form" + langSpec.getAssignment() + langSpec.getConstructorInvocation("Form", null) + langSpec.getStatementDelimiter() + "\n"; + for (Map.Entry> param: params) { + Type paramType = param.getKey(); + String paramName = param.getValue().getKey(); + String value = param.getValue().getValue(); + if (DataConstraintModel.typeList.isAncestorOf(paramType)) { + if (paramType instanceof ListType) { + Type compType = ((ListType) paramType).getElementType(); + Type wrapperType = langSpec.getWrapperType(compType); + EnhancedForStatement forStatement = null; + if (!langSpec.isValueType(compType)) { + forStatement = langSpec.getForStatementForCollection(langSpec.newVariableDeclaration(compType, "i"), value); + } else { + forStatement = langSpec.getForStatementForCollection(langSpec.newVariableDeclaration(wrapperType, "i"), value); + } + Block forBlock = new Block(); + if (DataConstraintModel.typeTuple.isAncestorOf(compType) || DataConstraintModel.typePair.isAncestorOf(paramType) || DataConstraintModel.typeList.isAncestorOf(compType) || DataConstraintModel.typeMap.isAncestorOf(paramType)) { + forBlock.addStatement("form.param(\"" + paramName + "\", " + langSpec.getConstructorInvocation("ObjectMapper", null) + ".writeValueAsString(i))" + langSpec.getStatementDelimiter()); // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} + } else { + forBlock.addStatement("form.param(\"" + paramName + "\", i.toString())" + langSpec.getStatementDelimiter()); + } + forStatement.setBody(forBlock); + statements += forStatement; +// return "Entity entity = Entity.entity(" + paramName + ".toString(), MediaType.APPLICATION_JSON);"; + } + } else if (DataConstraintModel.typeTuple.isAncestorOf(paramType) || DataConstraintModel.typePair.isAncestorOf(paramType) || DataConstraintModel.typeMap.isAncestorOf(paramType)) { + // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} + statements += "form.param(\"" + paramName + "\", " + langSpec.getConstructorInvocation("ObjectMapper", null) + ".writeValueAsString(" + value + "))" + langSpec.getStatementDelimiter() + "\n"; + } else { + statements += "form.param(\"" + paramName + "\", " + new JavaSpecific().getValueToStringExp(paramType.getImplementationTypeName(), value) + ")" + langSpec.getStatementDelimiter() + "\n"; + } + } + if (isFirstCall) { + statements += "Entity "; + } + statements += "entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED)" + langSpec.getStatementDelimiter(); + return statements; + } + + @Override + public String getHttpMethodCallStatement(String baseURL, String resourceName, String senderResName, String httpMethod) { + if (senderResName == null) { + return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "\").request()." + httpMethod + "(entity, String.class)" + langSpec.getStatementDelimiter(); + } else { + // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. + return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "/" + senderResName + "\").request()." + httpMethod + "(entity, String.class)" + langSpec.getStatementDelimiter(); + } + } + + @Override + public String getHttpMethodCallWithResponseStatement(String baseURL, String resourceName, String httpMethod, String responseTypeName) { + String responseShortTypeName = responseTypeName; + if (responseTypeName.contains("<")) { + responseShortTypeName = responseTypeName.substring(0, responseTypeName.indexOf("<")); + } + return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "\").request()." + httpMethod + "(" + responseShortTypeName + ".class)" + langSpec.getStatementDelimiter(); + } + + @Override + public void addJsonException(MethodDeclaration method) { + method.addThrow("JsonProcessingException"); + } + + @Override + public boolean hasJsonException(MethodDeclaration method) { + if (method.getThrows() == null || method.getThrows().getExceptions() == null) return false; + return method.getThrows().getExceptions().contains("JsonProcessingException"); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java new file mode 100644 index 0000000..3ddf549 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java @@ -0,0 +1,72 @@ +package generators; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; + +import code.ast.Annotation; +import code.ast.CompilationUnit; +import code.ast.FieldDeclaration; +import code.ast.ImportDeclaration; +import code.ast.MethodDeclaration; +import code.ast.TypeDeclaration; +import code.ast.VariableDeclaration; +import models.algebra.Type; + +abstract public class RestApiSpecific implements IPlatformSpecific { + protected ILanguageSpecific langSpec = null; + + @Override + public boolean hasMain() { + return false; + } + + @Override + public boolean isMonolithic() { + return false; + } + + @Override + public boolean isDifferentTreesAsDifferentServices() { + return true; + } + + abstract public void addComponentAnnotations(TypeDeclaration component, String resourcePath); + + abstract public void addGetAnnotations(MethodDeclaration getMethod); + + abstract public void addPutAnnotations(MethodDeclaration putMethod); + + abstract public void addPostAnnotations(MethodDeclaration postMethod); + + abstract public void addDeleteAnnotations(MethodDeclaration deleteMethod); + + abstract public void addPathAnnotation(MethodDeclaration method, String resourcePath); + + abstract public void addPathParamAnnotation(VariableDeclaration var, String paramName); + + abstract public void addFormParamAnnotation(VariableDeclaration var, String paramName); + + abstract public void addPlatformSpecificImports(CompilationUnit cu); + + abstract public boolean hasHttpClientFieldDeclaration(TypeDeclaration component); + + abstract public void addHttpClientFieldDeclaration(TypeDeclaration component); + + abstract public String getConversionFromJsonString(String fromStrVarName, String toVarName, String toVarType); + + abstract public String getHttpMethodParamsConstructionStatement(String callerResourceName, List>> params, boolean isFirstCall); + + abstract public String getHttpMethodCallStatement(String baseURL, String resourceName, String senderResName, String httpMethod); + + abstract public String getHttpMethodCallWithResponseStatement(String baseURL, String resourceName, String httpMethod, String responseTypeName); + + abstract public void addJsonException(MethodDeclaration method); + + abstract public boolean hasJsonException(MethodDeclaration method); + + public String getBaseURL() { + return "http://localhost:8080"; + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/StandaloneSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/StandaloneSpecific.java new file mode 100644 index 0000000..ce4acd5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/StandaloneSpecific.java @@ -0,0 +1,28 @@ +package generators; + +import java.util.List; + +import code.ast.Annotation; +import code.ast.CompilationUnit; +import code.ast.ImportDeclaration; +import code.ast.MethodDeclaration; +import code.ast.TypeDeclaration; +import code.ast.VariableDeclaration; + +public class StandaloneSpecific implements IPlatformSpecific { + + @Override + public boolean hasMain() { + return true; + } + + @Override + public boolean isMonolithic() { + return true; + } + + @Override + public boolean isDifferentTreesAsDifferentServices() { + return false; // meaningless + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/generators/TypeInference.java new file mode 100644 index 0000000..1d9f4f9 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/TypeInference.java @@ -0,0 +1,2381 @@ +package generators; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import models.Node; +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Position; +import models.algebra.Symbol; +import models.algebra.Term; +import models.algebra.Type; +import models.algebra.Variable; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonType; +import models.dataConstraintModel.ListType; +import models.dataConstraintModel.MapType; +import models.dataConstraintModel.ResourceHierarchy; +import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; +import models.dataConstraintModel.StateTransition; +import models.dataConstraintModel.TupleType; +import models.dataFlowModel.DataTransferModel; +import models.dataFlowModel.ResourceNode; + +/** + * Type inference for data transfer model + * + * @author Nitta + * + */ +public class TypeInference { + private ILanguageSpecific langSpec; + private Map listTypes = new HashMap<>(); + private Map listComponentTypes = new HashMap<>(); + private Map, Type> tupleTypes = new HashMap<>(); + private Map> tupleComponentTypes = new HashMap<>(); + private Map pairTypes = new HashMap<>(); + private Map pairComponentTypes = new HashMap<>(); + private Map, Type> mapTypes = new HashMap<>(); + private Map> mapComponentTypes = new HashMap<>(); + private Map, Type> jsonTypes = new HashMap<>(); + private Map> jsonMemberTypes = new HashMap<>(); + + public TypeInference(ILanguageSpecific langSpec) { + this.langSpec = langSpec; + } + + public Type getListType(Type compType) { + return listTypes.get(compType); + } + + public Type getListComponentType(Type listType) { + return listComponentTypes.get(listType); + } + + public Collection getListTypes() { + return listTypes.values(); + } + + public Type getTupleType(List compTypes) { + return tupleTypes.get(compTypes); + } + + public List getTupleComponentTypes(Type tupleType) { + return tupleComponentTypes.get(tupleType); + } + + public Collection getTupleTypes() { + return tupleTypes.values(); + } + + public Type getPairType(Type compType) { + return pairTypes.get(compType); + } + + public Type getPairComponentType(Type pairType) { + return pairComponentTypes.get(pairType); + } + + public Type getMapType(List compTypes) { + return mapTypes.get(compTypes); + } + + public List getMapComponentTypes(Type mapType) { + return mapComponentTypes.get(mapType); + } + + public Type getJsonType(Map memberTypes) { + return jsonTypes.get(memberTypes); + } + + public Map getJsonMemberTypes(Type jsonType) { + return jsonMemberTypes.get(jsonType); + } + + public void infer(DataTransferModel model) { + Map> resources = new HashMap<>(); + Map> resourcePathParams = new HashMap<>(); + Map variables = new HashMap<>(); + Map, Type>>> messages = new HashMap<>(); + Map consOrSet = new HashMap<>(); + Map tuple = new HashMap<>(); + Map pair = new HashMap<>(); + Map map = new HashMap<>(); + Map json = new HashMap<>(); + + // Maps from the objectId of each expression to its belonging group that has the same type as the expression + Map> expToResource = new HashMap<>(); + Map> expToPathParams = new HashMap<>(); + Map> expToVariable = new HashMap<>(); + Map> expToMessage = new HashMap<>(); + Map>> expToConsOrSet = new HashMap<>(); + Map>> expToTuple = new HashMap<>(); + Map>> expToPair = new HashMap<>(); + Map>> expToMap = new HashMap<>(); + Map>> expToJson = new HashMap<>(); + + // Maps from the objectId of each group to the set of updated expressions. + Map> updateFromResource = new HashMap<>(); + Set updateFromResourceOwnership = new HashSet<>(); + Map> updateFromVariable = new HashMap<>(); + Map> updateFromMessage = new HashMap<>(); + Map> updateFromConsOrSet = new HashMap<>(); + Map> updateFromTuple = new HashMap<>(); + Map> updateFromPair = new HashMap<>(); + Map> updateFromMap = new HashMap<>(); + Map> updateFromJson = new HashMap<>(); + + listComponentTypes.put(DataConstraintModel.typeList, null); + listComponentTypes.put(DataConstraintModel.typeListInt, DataConstraintModel.typeInt); + listComponentTypes.put(DataConstraintModel.typeListStr, DataConstraintModel.typeString); + listTypes.put(DataConstraintModel.typeInt, DataConstraintModel.typeListInt); + listTypes.put(DataConstraintModel.typeString, DataConstraintModel.typeListStr); + pairComponentTypes.put(DataConstraintModel.typePair, null); + pairComponentTypes.put(DataConstraintModel.typePairInt, DataConstraintModel.typeInt); + pairComponentTypes.put(DataConstraintModel.typePairStr, DataConstraintModel.typeString); + pairComponentTypes.put(DataConstraintModel.typePairDouble, DataConstraintModel.typeDouble); + pairTypes.put(DataConstraintModel.typeInt, DataConstraintModel.typePairInt); + pairTypes.put(DataConstraintModel.typeString, DataConstraintModel.typePairStr); + pairTypes.put(DataConstraintModel.typeDouble, DataConstraintModel.typePairDouble); + tupleComponentTypes.put(DataConstraintModel.typeTuple, Arrays.asList(new Type[] { null, null })); + mapComponentTypes.put(DataConstraintModel.typeMap, Arrays.asList(new Type[] { null, null })); + + // 1. Collect type information from the architecture model. + Collection channels = new HashSet<>(model.getInputChannels()); + channels.addAll(model.getChannels()); + for (Channel ch : channels) { + // 1.1 Group expressions by resources. + IGroupExpressionsByResource groupExpressionsByResource = new IGroupExpressionsByResource() { + public void groupForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + StateTransition st = cm.getStateTransition(); + ResourceHierarchy res = cm.getResource().getResourceHierarchy(); + List identicalResources = resources.get(res); + if (identicalResources == null) { + identicalResources = new ArrayList<>(); + resources.put(res, identicalResources); + } + identicalResources.add(st.getCurStateExpression()); + expToResource.put(System.identityHashCode(st.getCurStateExpression()), identicalResources); + if (st.getNextStateExpression() != null) { + identicalResources.add(st.getNextStateExpression()); + expToResource.put(System.identityHashCode(st.getNextStateExpression()), identicalResources); + } + Map updatedExps = getUpdateSet(updateFromResource, identicalResources); + Type resType = res.getResourceStateType(); + Expression exp = st.getCurStateExpression(); + Type expType = getExpTypeIfUpdatable(resType, exp); + if (expType != null) { + res.setResourceStateType(expType); + for (Expression resExp : identicalResources) { + if (resExp != exp) { + if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { + ((Variable) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); + } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { + ((Term) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); + } + } + } + } else if (exp instanceof Variable) { + if (compareTypes(((Variable) exp).getType(), resType)) { + ((Variable) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } + } else if (exp instanceof Term) { + if (compareTypes(((Term) exp).getType(), resType)) { + ((Term) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } + } + resType = res.getResourceStateType(); + exp = st.getNextStateExpression(); + if (exp != null) { + expType = getExpTypeIfUpdatable(resType, exp); + if (expType != null) { + res.setResourceStateType(expType); + for (Expression resExp : identicalResources) { + if (resExp != exp) { + if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { + ((Variable) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); + } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { + ((Term) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); + } + } + } + } else if (exp instanceof Variable) { + if (compareTypes(((Variable) exp).getType(), resType)) { + ((Variable) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } + } else if (exp instanceof Term) { + if (compareTypes(((Term) exp).getType(), resType)) { + ((Term) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } + } + } + } + for (Channel childCh: ch.getChildren()) { + groupForChannel(childCh); + } + } + }; + groupExpressionsByResource.groupForChannel(ch); + + // 1.2 Group expressions by variable. + IGroupExpressionsByVariable groupExpressionsByVariable = new IGroupExpressionsByVariable() { + public void groupForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + StateTransition st = cm.getStateTransition(); + Map> locals = new HashMap<>(); + Map localTypes = new HashMap<>(); + List allVariables = new ArrayList<>(); + allVariables.addAll(st.getCurStateExpression().getVariables().values()); + allVariables.addAll(st.getMessageExpression().getVariables().values()); + if (st.getNextStateExpression() != null) { + allVariables.addAll(st.getNextStateExpression().getVariables().values()); + } + for (Selector s: ch.getAllSelectors()) { // add channel selectors + if (s.getExpression() instanceof Variable) { + allVariables.add((Variable) s.getExpression()); + } + } + ResourcePath resPath = cm.getResource(); + for (Expression param: resPath.getPathParams()) { // add path parameters + if (param instanceof Variable) { + allVariables.add((Variable) param); + } else if (param instanceof Term) { + allVariables.addAll(((Term) param).getVariables().values()); + } + } + for (Variable var : allVariables) { + List sameVariable = locals.get(var.getName()); + if (sameVariable == null) { + sameVariable = new ArrayList<>(); + sameVariable.add(var); + expToVariable.put(System.identityHashCode(var), sameVariable); + locals.put(var.getName(), sameVariable); + localTypes.put(var.getName(), var.getType()); + } else { + sameVariable.add(var); + expToVariable.put(System.identityHashCode(var), sameVariable); + Type varType = localTypes.get(var.getName()); + Map updatedVars = getUpdateSet(updateFromVariable, sameVariable); + if (compareTypes(varType, var.getType())) { + localTypes.put(var.getName(), var.getType()); + for (Expression v : sameVariable) { + if (v != var) { + if (compareTypes(((Variable) v).getType(), var.getType())) { + ((Variable) v).setType(var.getType()); + updatedVars.put(System.identityHashCode(v), v); + } + } + } + } else if (compareTypes(var.getType(), varType)) { + var.setType(varType); + updatedVars.put(System.identityHashCode(var), var); + } + } + } + for (String varName : locals.keySet()) { + variables.put(System.identityHashCode(locals.get(varName)), localTypes.get(varName)); + } + } + for (Channel childCh: ch.getChildren()) { + groupForChannel(childCh); + } + } + }; + groupExpressionsByVariable.groupForChannel(ch); + + // 1.3 Group expressions by message. + IGroupExpressionsByMessage groupExpressionsByMessage = new IGroupExpressionsByMessage() { + public void groupForChannel(Channel rootCh, Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + Expression message = cm.getStateTransition().getMessageExpression(); + if (message instanceof Variable) { + Type msgType = ((Variable) message).getType(); + Map, Type>> msgTypeMap = messages.get(rootCh); + if (msgTypeMap == null) { + msgTypeMap = new HashMap<>(); + messages.put(rootCh, msgTypeMap); + } + Map.Entry, Type> typeAndExps = msgTypeMap.get(0); + if (typeAndExps == null) { + List exps = new ArrayList<>(); + exps.add(message); + typeAndExps = new AbstractMap.SimpleEntry<>(exps, msgType); + msgTypeMap.put(0, typeAndExps); + expToMessage.put(System.identityHashCode(message), exps); + } else { + typeAndExps.getKey().add(message); + expToMessage.put(System.identityHashCode(message), typeAndExps.getKey()); + Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); + if (compareTypes(typeAndExps.getValue(), msgType)) { + typeAndExps.setValue(msgType); + for (Expression e : typeAndExps.getKey()) { + if (e != message) { + if (e instanceof Variable) { + ((Variable) e).setType(msgType); + updateExps.put(System.identityHashCode(e), e); + } + } + } + } else if (compareTypes(msgType, typeAndExps.getValue())) { + ((Variable) message).setType(typeAndExps.getValue()); + updateExps.put(System.identityHashCode(message), message); + } + } + } else if (message instanceof Term) { + Map, Type>> msgTypeMap = messages.get(rootCh); + if (msgTypeMap == null) { + msgTypeMap = new HashMap<>(); + messages.put(rootCh, msgTypeMap); + } + for (int i = 0; i < ((Term) message).getArity(); i++) { + Expression arg = ((Term) message).getChild(i); + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } else { + continue; + } + Map.Entry, Type> typeAndExps = msgTypeMap.get(i); + if (typeAndExps == null) { + List exps = new ArrayList<>(); + exps.add(arg); + typeAndExps = new AbstractMap.SimpleEntry<>(exps, argType); + msgTypeMap.put(i, typeAndExps); + expToMessage.put(System.identityHashCode(arg), exps); + } else { + typeAndExps.getKey().add(arg); + expToMessage.put(System.identityHashCode(arg), typeAndExps.getKey()); + Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); + if (compareTypes(typeAndExps.getValue(), argType)) { + typeAndExps.setValue(argType); + for (Expression e : typeAndExps.getKey()) { + if (e != arg) { + if (e instanceof Variable) { + ((Variable) e).setType(argType); + updateExps.put(System.identityHashCode(e), e); + } + } + } + } else if (compareTypes(argType, typeAndExps.getValue())) { + if (arg instanceof Variable) { + ((Variable) arg).setType(typeAndExps.getValue()); + updateExps.put(System.identityHashCode(arg), arg); + } else if (arg instanceof Term) { + ((Term) arg).setType(typeAndExps.getValue()); + updateExps.put(System.identityHashCode(arg), arg); + } + } + } + } + } + } + for (Channel childCh: ch.getChildren()) { + groupForChannel(rootCh, childCh); + } + } + }; + groupExpressionsByMessage.groupForChannel(ch, ch); + + // 1.4 Extract constraints on expressions in each term. + IExtractConstraintsOnExpressionsInTerm extractConstraintsOnExpressionsInTerm = new IExtractConstraintsOnExpressionsInTerm() { + public void extractForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + StateTransition st = cm.getStateTransition(); + List terms = new ArrayList<>(); + if (st.getCurStateExpression() instanceof Term) { + Map subTerms = ((Term) st.getCurStateExpression()).getSubTerms(Term.class); + terms.addAll(subTerms.values()); + } + if (st.getMessageExpression() instanceof Term) { + Map subTerms = ((Term) st.getMessageExpression()).getSubTerms(Term.class); + terms.addAll(subTerms.values()); + } + if (st.getNextStateExpression() != null && st.getNextStateExpression() instanceof Term) { + Map subTerms = ((Term) st.getNextStateExpression()).getSubTerms(Term.class); + terms.addAll(subTerms.values()); + } + for (Term t : terms) { + Symbol symbol = t.getSymbol(); + if (symbol.equals(DataConstraintModel.cons) || symbol.equals(DataConstraintModel.set) || symbol.equals(DataConstraintModel.append)) { + // If the root symbol of the term is cons or set. + List consExps = new ArrayList<>(); + consExps.add(t); // list term + updateExpressionBelonging(expToConsOrSet, t, consExps); + if (symbol.equals(DataConstraintModel.cons)) { + // If the root symbol of the term is cons. + for (Expression e : t.getChildren()) { + consExps.add(e); + updateExpressionBelonging(expToConsOrSet, e, consExps); + } + } else if (symbol.equals(DataConstraintModel.append)) { + // If the root symbol of the term is append. + Expression e = t.getChildren().get(1); + consExps.add(e); // list element + updateExpressionBelonging(expToConsOrSet, e, consExps); + e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + } else { + // If the root symbol of the term is set. + Expression e = t.getChildren().get(2); + consExps.add(e); // list element + updateExpressionBelonging(expToConsOrSet, e, consExps); + e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + } + Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); + if (newType != null) { + // If the type of the 2nd argument of cons (1st argument of set/append) is more concrete than the type of the term. + t.setType(newType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + } else { + Type arg2Type = null; + if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { + arg2Type = ((Variable) consExps.get(2)).getType(); + if (compareTypes(arg2Type, t.getType())) { + // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set/append). + ((Variable) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { + arg2Type = ((Term) consExps.get(2)).getType(); + if (compareTypes(arg2Type, t.getType())) { + // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set/append). + ((Term) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } + } + Type newCompType = getExpTypeIfUpdatable(listComponentTypes.get(t.getType()), consExps.get(1)); + if (newCompType != null) { + // If the type of the 1st argument of cons (3rd argument of set) is more concrete than the type of list component. + Type newListType = listTypes.get(newCompType); + if (newListType == null) { + // Create new list type. + newListType = createNewListType(newCompType, DataConstraintModel.typeList); + } + t.setType(newListType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { + ((Variable) consExps.get(2)).setType(newListType); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { + ((Term) consExps.get(2)).setType(newListType); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } + consOrSet.put(System.identityHashCode(consExps), t.getType()); + } else if (symbol.equals(DataConstraintModel.head) || symbol.equals(DataConstraintModel.get)) { + // If the root symbol of the term is head or get. + List consExps = new ArrayList<>(); + Expression e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + consExps.add(t); // list's component + updateExpressionBelonging(expToConsOrSet, t, consExps); + consExps.add(null); + Type listType = listTypes.get(t.getType()); + if (listType == null && t.getType() != null) { + // Create a new list type. + listType = createNewListType(t.getType(), DataConstraintModel.typeList); + } + Type newListType = getExpTypeIfUpdatable(listType, consExps.get(0)); + if (newListType != null) { + // If the type of the component of the 1st argument is more concrete than the type of the term. + Type newCompType = listComponentTypes.get(newListType); + if (newCompType != null) { + t.setType(newCompType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + } + consOrSet.put(System.identityHashCode(consExps), newListType); + } else { + // If the type of the term is more concrete than the type of the component of the 1st argument. + if (consExps.get(0) != null && consExps.get(0) instanceof Variable) { + ((Variable) consExps.get(0)).setType(listType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); + } else if (consExps.get(0) != null && consExps.get(0) instanceof Term) { + ((Term) consExps.get(0)).setType(listType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); + } + consOrSet.put(System.identityHashCode(consExps), listType); + } + } else if (symbol.equals(DataConstraintModel.tail)) { + // If the root symbol of the term is tail. + List consExps = new ArrayList<>(); + consExps.add(t); // list term + updateExpressionBelonging(expToConsOrSet, t, consExps); + consExps.add(null); // list's component + Expression e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); + if (newType != null) { + // If the type of the argument is more concrete than the type of the term. + t.setType(newType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + } else { + Type argType = null; + if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { + argType = ((Variable) consExps.get(2)).getType(); + if (compareTypes(argType, t.getType())) { + // If the type of the term is more concrete than the type of the argument. + ((Variable) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { + argType = ((Term) consExps.get(2)).getType(); + if (compareTypes(argType, t.getType())) { + // If the type of the term is more concrete than the type of the argument. + ((Term) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } + } + consOrSet.put(System.identityHashCode(consExps), t.getType()); + } else if (symbol.equals(DataConstraintModel.tuple)) { + // If the root symbol of the term is tuple. + List tupleExps = new ArrayList<>(); + List newArgTypesList = new ArrayList<>(); + tupleExps.add(t); // tuple term + updateExpressionBelonging(expToTuple, t, tupleExps); + for (Expression e : t.getChildren()) { + tupleExps.add(e); // tuple's component + updateExpressionBelonging(expToTuple, e, tupleExps); + if (e instanceof Variable) { + newArgTypesList.add(((Variable) e).getType()); + } else if (e instanceof Term) { + newArgTypesList.add(((Term) e).getType()); + } else { + newArgTypesList.add(null); + } + } + if (t.getType() == DataConstraintModel.typeTuple) { + Type newTupleType = tupleTypes.get(newArgTypesList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(newArgTypesList, DataConstraintModel.typeTuple); + } + // Update the type of the tuple term and record the updated expression. + t.setType(newTupleType); + Map updateExps = getUpdateSet(updateFromTuple, tupleExps); + updateExps.put(System.identityHashCode(t), t); + } + tuple.put(System.identityHashCode(tupleExps), t.getType()); + } else if (symbol.equals(DataConstraintModel.pair)) { + // If the root symbol of the term is pair. + List pairExps = new ArrayList<>(); + pairExps.add(t); // pair + updateExpressionBelonging(expToPair, t, pairExps); + if (t.getType() == DataConstraintModel.typePair) { + for (Expression e : t.getChildren()) { + pairExps.add(e); // left/right + updateExpressionBelonging(expToPair, e, pairExps); + Type newArgType = null; + if (e instanceof Variable) { + newArgType = (((Variable) e).getType()); + + } else if (e instanceof Term) { + newArgType = (((Term) e).getType()); + } + + if (newArgType != null) { + Type newPairType = pairTypes.get(newArgType); + if (newPairType != null) { + t.setType(newPairType); + Map updateExps = getUpdateSet(updateFromPair, pairExps); + updateExps.put(System.identityHashCode(t), t); + } + } + } + pair.put(System.identityHashCode(pairExps), t.getType()); + + } + } else if (symbol.equals(DataConstraintModel.fst)) { + // If the root symbol of the term is fst. + List tupleExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + tupleExps.add(arg); // tuple argument + updateExpressionBelonging(expToTuple, arg, tupleExps); + tupleExps.add(t); // first component + updateExpressionBelonging(expToTuple, t, tupleExps); + tupleExps.add(null); // second component + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newTupleType = DataConstraintModel.typeTuple; + if (argType == DataConstraintModel.typeTuple && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(t.getType()); + newCompTypeList.add(null); + newTupleType = tupleTypes.get(newCompTypeList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); + } + } + if (argType != newTupleType && newTupleType != null) { + // Update the type of the tuple argument and record the updated expression. + if (arg instanceof Variable) { + ((Variable) arg).setType(newTupleType); + argType = newTupleType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newTupleType); + argType = newTupleType; + } + Map updateExps = getUpdateSet(updateFromTuple, tupleExps); + updateExps.put(System.identityHashCode(arg), arg); + } + tuple.put(System.identityHashCode(tupleExps), argType); + } else if (symbol.equals(DataConstraintModel.snd)) { + // If the root symbol of the term is snd. + List tupleExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + tupleExps.add(arg); // tuple argument + updateExpressionBelonging(expToTuple, arg, tupleExps); + tupleExps.add(null); // first component + tupleExps.add(t); // second component + updateExpressionBelonging(expToTuple, t, tupleExps); + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newTupleType = DataConstraintModel.typeTuple; + if (argType == DataConstraintModel.typeTuple && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(null); + if (DataConstraintModel.typeTuple.isAncestorOf(t.getType())) { + List sndTypes = tupleComponentTypes.get(t.getType()); + if (sndTypes != null) { + for (Type t2: sndTypes) { + newCompTypeList.add(t2); + } + } else { + newCompTypeList.add(t.getType()); + } + } else { + newCompTypeList.add(t.getType()); + } + newTupleType = tupleTypes.get(newCompTypeList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); + } + } + if (argType != newTupleType && newTupleType != null) { + // Update the type of the tuple argument and record the updated expression. + if (arg instanceof Variable) { + ((Variable) arg).setType(newTupleType); + argType = newTupleType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newTupleType); + argType = newTupleType; + } + Map updateExps = getUpdateSet(updateFromTuple, tupleExps); + updateExps.put(System.identityHashCode(arg), arg); + } + tuple.put(System.identityHashCode(tupleExps), argType); + } else if (symbol.equals(DataConstraintModel.left)) { + // If the root symbol of the term is left. + List pairExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + pairExps.add(arg); // pair + updateExpressionBelonging(expToPair, arg, pairExps); + pairExps.add(t); // left + updateExpressionBelonging(expToPair, t, pairExps); + pairExps.add(null); // right + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newPairType = DataConstraintModel.typePair; + if (argType == DataConstraintModel.typePair && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(t.getType()); + newCompTypeList.add(null); + newPairType = pairTypes.get(newCompTypeList); + if (newPairType == null) { + // Create new tuple type; + newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); + } + } + if (argType != newPairType && newPairType != null) { + if (arg instanceof Variable) { + ((Variable) arg).setType(newPairType); + argType = newPairType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newPairType); + argType = newPairType; + } + Map updateExps = getUpdateSet(updateFromPair, pairExps); + updateExps.put(System.identityHashCode(arg), arg); + } + pair.put(System.identityHashCode(pairExps), argType); + } else if (symbol.equals(DataConstraintModel.right)) { + // If the root symbol of the term is right. + List pairExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + pairExps.add(arg); // pair + updateExpressionBelonging(expToPair, arg, pairExps); + pairExps.add(null); // left + pairExps.add(t); // right + updateExpressionBelonging(expToPair, t, pairExps); + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newPairType = DataConstraintModel.typePair; + if (argType == DataConstraintModel.typePair && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(null); + newCompTypeList.add(t.getType()); + newPairType = pairTypes.get(newCompTypeList); + if (newPairType == null) { + // Create new tuple type; + newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); + } + } + if (argType != newPairType && newPairType != null) { + if (arg instanceof Variable) { + ((Variable) arg).setType(newPairType); + argType = newPairType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newPairType); + argType = newPairType; + } + Map updateExps = getUpdateSet(updateFromPair, pairExps); + updateExps.put(System.identityHashCode(arg), arg); + } + pair.put(System.identityHashCode(pairExps), argType); + } else if (symbol.equals(DataConstraintModel.lookup)) { + // If the root symbol of the term is lookup. + List mapExps = new ArrayList<>(); + Expression arg1 = t.getChildren().get(0); // map + mapExps.add(arg1); + updateExpressionBelonging(expToMap, arg1, mapExps); + Expression arg2 = t.getChildren().get(1); // key + mapExps.add(arg2); + updateExpressionBelonging(expToMap, arg2, mapExps); + mapExps.add(t); // value + updateExpressionBelonging(expToMap, t, mapExps); + Type arg1Type = null; + if (arg1 instanceof Variable) { + arg1Type = ((Variable) arg1).getType(); + } else if (arg1 instanceof Term) { + arg1Type = ((Term) arg1).getType(); + } + List newCompTypeList = new ArrayList<>(); + if (arg2 instanceof Variable) { + newCompTypeList.add(((Variable) arg2).getType()); + } else if (arg2 instanceof Term) { + newCompTypeList.add(((Term) arg2).getType()); + } else { + newCompTypeList.add(null); + } + newCompTypeList.add(t.getType()); + if (arg1Type == DataConstraintModel.typeMap || arg1Type == null) { + Type newMapType = mapTypes.get(newCompTypeList); + if (newMapType == null) { + // Create new tuple type; + newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); + } + // Update the type of the map argument and record the updated expression. + if (arg1 instanceof Variable) { + ((Variable) arg1).setType(newMapType); + arg1Type = newMapType; + } else if (arg1 instanceof Term) { + ((Term) arg1).setType(newMapType); + arg1Type = newMapType; + } + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(arg1), arg1); + } + map.put(System.identityHashCode(mapExps), arg1Type); + } else if (symbol.equals(DataConstraintModel.insert)) { + // If the root symbol of the term is insert. + List mapExps = new ArrayList<>(); + mapExps.add(t); // map + updateExpressionBelonging(expToMap, t, mapExps); + Expression arg1 = t.getChildren().get(1); // key + mapExps.add(arg1); + updateExpressionBelonging(expToMap, arg1, mapExps); + Expression arg2 = t.getChildren().get(2); // value + mapExps.add(arg2); + updateExpressionBelonging(expToMap, arg2, mapExps); + Expression arg0 = t.getChildren().get(0); // map + mapExps.add(arg0); + updateExpressionBelonging(expToMap, arg0, mapExps); + Type termType = t.getType(); + List newCompTypeList = new ArrayList<>(); + if (arg1 instanceof Variable) { + newCompTypeList.add(((Variable) arg1).getType()); + } else if (arg1 instanceof Term) { + newCompTypeList.add(((Term) arg1).getType()); + } else { + newCompTypeList.add(null); + } + if (arg2 instanceof Variable) { + newCompTypeList.add(((Variable) arg2).getType()); + } else if (arg2 instanceof Term) { + newCompTypeList.add(((Term) arg2).getType()); + } else { + newCompTypeList.add(null); + } + Type newTermType = getExpTypeIfUpdatable(termType, mapExps.get(3)); + if (newTermType != null) { + // If the type of the 1st argument of insert is more concrete than the type of the term. + t.setType(newTermType); + termType = newTermType; + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(t), t); + } else { + Type arg3Type = null; + if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { + arg3Type = ((Variable) mapExps.get(3)).getType(); + if (compareTypes(arg3Type, t.getType())) { + // If the type of the term is more concrete than the type of the 1st argument of insert. + ((Variable) mapExps.get(3)).setType(t.getType()); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { + arg3Type = ((Term) mapExps.get(3)).getType(); + if (compareTypes(arg3Type, t.getType())) { + // If the type of the term is more concrete than the type of the 1st argument of insert. + ((Term) mapExps.get(3)).setType(t.getType()); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + } + } + if (termType == DataConstraintModel.typeMap || termType == null) { + Type newMapType = mapTypes.get(newCompTypeList); + if (newMapType == null) { + // Create new tuple type; + newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); + } + // Update the type of the map term and record the updated expression. + t.setType(newMapType); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(t), t); + if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { + ((Variable) mapExps.get(3)).setType(newMapType); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { + ((Term) mapExps.get(3)).setType(newMapType); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + termType = newMapType; + } + map.put(System.identityHashCode(mapExps), termType); + } else if (symbol.equals(DataConstraintModel.addMember)) { + // If the root symbol of the term is addMember (addMember(json, key, value)). + List dotExps = new ArrayList<>(); + Expression jsonArg = t.getChildren().get(0); + Expression keyArg = t.getChildren().get(1); + Expression valueArg = t.getChildren().get(2); + dotExps.add(t); // json + updateExpressionBelonging(expToJson, t, dotExps); + dotExps.add(keyArg); // key + updateExpressionBelonging(expToJson, keyArg, dotExps); + dotExps.add(valueArg); // value + updateExpressionBelonging(expToJson, valueArg, dotExps); + dotExps.add(jsonArg); // json + updateExpressionBelonging(expToJson, jsonArg, dotExps); + Type jsonType = t.getType(); + Type valueType = null; + if (valueArg instanceof Variable) { + valueType = ((Variable) valueArg).getType(); + } else if (valueArg instanceof Term) { + valueType = ((Term) valueArg).getType(); + } + String keyName = null; + if (keyArg instanceof Constant) { + keyName = ((Constant) keyArg).getSymbol().getName(); + } + Type jsonArgType = null; + if (jsonArg instanceof Variable) { + jsonArgType = ((Variable) jsonArg).getType(); + } else if (jsonArg instanceof Term) { + jsonArgType = ((Term) jsonArg).getType(); + } + Type newJsonType = DataConstraintModel.typeJson; + if (jsonType == DataConstraintModel.typeJson && jsonArgType != null && keyName != null) { + Map newMemberTypes = new HashMap<>(((JsonType) jsonArgType).getMemberTypes()); + newMemberTypes.put(keyName, valueType); + newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + // Create new json type; + newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); + } + } + if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { + // Update the type of the json term and record the updated expression. + t.setType(newJsonType); + jsonType = newJsonType; + Map updateExps = getUpdateSet(updateFromJson, dotExps); + updateExps.put(System.identityHashCode(t), t); + } + json.put(System.identityHashCode(dotExps), jsonType); + } else if (symbol.equals(DataConstraintModel.dot)) { + // If the root symbol of the term is dot (json.property). + List dotExps = new ArrayList<>(); + Expression jsonArg = t.getChildren().get(0); + Expression keyArg = t.getChildren().get(1); + dotExps.add(jsonArg); // json + updateExpressionBelonging(expToJson, jsonArg, dotExps); + dotExps.add(keyArg); // key + updateExpressionBelonging(expToJson, keyArg, dotExps); + dotExps.add(t); // value + updateExpressionBelonging(expToJson, t, dotExps); + dotExps.add(null); // json + Type jsonType = null; + if (jsonArg instanceof Variable) { + jsonType = ((Variable) jsonArg).getType(); + } else if (jsonArg instanceof Term) { + jsonType = ((Term) jsonArg).getType(); + } + String keyName = null; + if (keyArg instanceof Constant) { + keyName = ((Constant) keyArg).getSymbol().getName(); + } + Type newJsonType = DataConstraintModel.typeJson; + if (jsonType == DataConstraintModel.typeJson && t.getType() != null && keyName != null) { + Map newMemberTypes = new HashMap<>(); + newMemberTypes.put(keyName, t.getType()); + newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + // Create new json type; + newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); + } + } + if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { + // Update the type of the json argument and record the updated expression. + if (jsonArg instanceof Variable) { + ((Variable) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } else if (jsonArg instanceof Term) { + ((Term) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } + Map updateExps = getUpdateSet(updateFromJson, dotExps); + updateExps.put(System.identityHashCode(jsonArg), jsonArg); + } + json.put(System.identityHashCode(dotExps), jsonType); + } else if (symbol.equals(DataConstraintModel.dotParam)) { + // If the root symbol of the term is dot (json.{param}). + List dotExps = new ArrayList<>(); + Expression jsonArg = t.getChildren().get(0); + Expression keyArg = t.getChildren().get(1); + dotExps.add(jsonArg); // json (list/map) + updateExpressionBelonging(expToJson, jsonArg, dotExps); + dotExps.add(null); // key + dotExps.add(t); // value + updateExpressionBelonging(expToJson, t, dotExps); + dotExps.add(null); // json + Type jsonType = null; + if (jsonArg instanceof Variable) { + jsonType = ((Variable) jsonArg).getType(); + } else if (jsonArg instanceof Term) { + jsonType = ((Term) jsonArg).getType(); + } + Type keyType = null; + if (keyArg instanceof Variable) { + keyType = ((Variable) keyArg).getType(); + } else if (keyArg instanceof Term) { + keyType = ((Term) keyArg).getType(); + } + Type newJsonType = null; + if (keyType == DataConstraintModel.typeInt) { + newJsonType = DataConstraintModel.typeList; + } else if (keyType == DataConstraintModel.typeString) { + newJsonType = DataConstraintModel.typeMap; + } + if (t.getType() != null) { + if ((jsonType == DataConstraintModel.typeList)) { + newJsonType = listTypes.get(t.getType()); + if (newJsonType == null) { + // Create new list type; + newJsonType = createNewListType(t.getType(), DataConstraintModel.typeList); + } + } else if (jsonType == DataConstraintModel.typeMap) { + List keyValueTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, t.getType()}); + newJsonType = mapTypes.get(keyValueTypes); + if (newJsonType == null) { + // Create new map type; + newJsonType = createNewMapType(keyValueTypes, DataConstraintModel.typeMap); + } + } + } + if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { + // Update the type of the json argument and record the updated expression. + if (jsonArg instanceof Variable) { + ((Variable) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } else if (jsonArg instanceof Term) { + ((Term) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } + Map updateExps = getUpdateSet(updateFromJson, dotExps); + updateExps.put(System.identityHashCode(jsonArg), jsonArg); + } + json.put(System.identityHashCode(dotExps), jsonType); + } else if (symbol.equals(DataConstraintModel.cond)) { + // If the root symbol of the term is if function. + Expression c1 = t.getChild(1); + Expression c2 = t.getChild(2); + List condTerms = new ArrayList<>(); + condTerms.add(t); + condTerms.add(c1); + condTerms.add(c2); + expToVariable.put(System.identityHashCode(t), condTerms); + expToVariable.put(System.identityHashCode(c1), condTerms); + expToVariable.put(System.identityHashCode(c2), condTerms); + Type condType = t.getType(); + Map updatedVars = getUpdateSet(updateFromVariable, condTerms); + Type child1Type = getExpTypeIfUpdatable(condType, c1); + if (child1Type != null) { + condType = child1Type; + t.setType(child1Type); + updatedVars.put(System.identityHashCode(t), t); + } else { + if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), condType)) { + ((Variable) c1).setType(condType); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), condType)) { + ((Term) c1).setType(condType); + updatedVars.put(System.identityHashCode(c1), c1); + } + } + Type child2Type = getExpTypeIfUpdatable(condType, c2); + if (child2Type != null) { + condType = child2Type; + t.setType(child2Type); + updatedVars.put(System.identityHashCode(t), t); + if (c1 instanceof Variable) { + ((Variable) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term) { + ((Term) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } + } else { + if (c2 instanceof Variable && compareTypes(((Variable) c2).getType(), condType)) { + ((Variable) c2).setType(condType); + updatedVars.put(System.identityHashCode(c2), c2); + } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), condType)) { + ((Term) c2).setType(condType); + updatedVars.put(System.identityHashCode(c2), c2); + } + } + variables.put(System.identityHashCode(condTerms), condType); + } else if (symbol.equals(DataConstraintModel.add) || symbol.equals(DataConstraintModel.sub) + || symbol.equals(DataConstraintModel.mul) || symbol.equals(DataConstraintModel.div)) { + // If the root symbol of the term is arithmetic operators. + Expression c1 = t.getChild(0); + Expression c2 = t.getChild(1); + List operands = new ArrayList<>(); + operands.add(t); + operands.add(c1); + operands.add(c2); + expToVariable.put(System.identityHashCode(t), operands); + expToVariable.put(System.identityHashCode(c1), operands); + expToVariable.put(System.identityHashCode(c2), operands); + Type opType = t.getType(); + Map updatedVars = getUpdateSet(updateFromVariable, operands); + Type child1Type = getExpTypeIfUpdatable(opType, c1); + if (child1Type != null) { + opType = child1Type; + t.setType(child1Type); + updatedVars.put(System.identityHashCode(t), t); + } else { + if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), opType)) { + ((Variable) c1).setType(opType); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), opType)) { + ((Term) c1).setType(opType); + updatedVars.put(System.identityHashCode(c1), c1); + } + } + Type child2Type = getExpTypeIfUpdatable(opType, c2); + if (child2Type != null) { + opType = child2Type; + t.setType(child2Type); + updatedVars.put(System.identityHashCode(t), t); + if (c1 instanceof Variable) { + ((Variable) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term) { + ((Term) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } + } else { + if (c2 instanceof Variable && compareTypes(((Variable) c2).getType(), opType)) { + ((Variable) c2).setType(opType); + updatedVars.put(System.identityHashCode(c2), c2); + } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), opType)) { + ((Term) c2).setType(opType); + updatedVars.put(System.identityHashCode(c2), c2); + } + } + variables.put(System.identityHashCode(operands), opType); + } else if (symbol.getSignature() != null + && symbol.getSignature()[0] == DataConstraintModel.typeList) { + // If the root symbol of the term is the list type (except for the cons function). + List consExps = new ArrayList<>(); + consExps.add(t); + expToVariable.put(System.identityHashCode(t), consExps); + Type condType = t.getType(); + Map updatedVars = getUpdateSet(updateFromVariable, consExps); + for (int i = 1; i < symbol.getSignature().length; i++) { + Type tc = symbol.getSignature()[i]; + if (tc == DataConstraintModel.typeList) { + Expression e = t.getChildren().get(i - 1); + Type newType = getExpTypeIfUpdatable(condType, e); + if (newType != null) { + condType = newType; + for (Expression e2 : consExps) { + if (e2 instanceof Variable) { + ((Variable) e2).setType(newType); + updatedVars.put(System.identityHashCode(e2), e2); + } else if (e2 instanceof Term) { + ((Term) e2).setType(newType); + updatedVars.put(System.identityHashCode(e2), e2); + } + } + } else { + if (e instanceof Variable && compareTypes(((Variable) e).getType(), condType)) { + ((Variable) e).setType(condType); + updatedVars.put(System.identityHashCode(e), e); + } else if (e instanceof Term && compareTypes(((Term) e).getType(), condType)) { + ((Term) e).setType(condType); + updatedVars.put(System.identityHashCode(e), e); + } + } + consExps.add(e); + expToVariable.put(System.identityHashCode(e), consExps); + } + } + variables.put(System.identityHashCode(consExps), condType); + } + } + } + for (Channel childCh: ch.getChildren()) { + extractForChannel(childCh); + } + } + }; + extractConstraintsOnExpressionsInTerm.extractForChannel(ch); + + // 1.5 Extract constraints on path parameters and resources. + IExtractConstraintsOnPathParametersAndResources extractConstraintsOnPathParametersAndResources = new IExtractConstraintsOnPathParametersAndResources() { + public void extractForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + ResourcePath rPath = cm.getResource(); + while (rPath != null) { + Expression param = rPath.getLastParam(); + if (param != null) { + ResourceHierarchy parent = rPath.getResourceHierarchy().getParent(); + if (parent != null) { + List pathParams = resourcePathParams.get(parent); + if (pathParams == null) { + pathParams = new ArrayList<>(); + resourcePathParams.put(parent, pathParams); + } + pathParams.add(param); + expToPathParams.put(System.identityHashCode(param), pathParams); + Type parentType = parent.getResourceStateType(); + Type paramType = null; + if (param instanceof Variable) { + paramType = ((Variable) param).getType(); + } else if (param instanceof Term) { + paramType = ((Term) param).getType(); + } + if (paramType != null && parentType == null) { + if (paramType.equals(DataConstraintModel.typeString)) { + parentType = DataConstraintModel.typeMap; + } else if (paramType.equals(DataConstraintModel.typeInt)) { + parentType = DataConstraintModel.typeList; + } + if (parentType != null) { + parent.setResourceStateType(parentType); + updateFromResourceOwnership.add(parent); + } + } + } + } + rPath = rPath.getParent(); + } + } + for (Channel childCh: ch.getChildren()) { + extractForChannel(childCh); + } + } + }; + extractConstraintsOnPathParametersAndResources.extractForChannel(ch); + } + + // 1.6 Extract constraints on resource hierarchies. + for (ResourceHierarchy res: model.getResourceHierarchies()) { + if (res.getResourceStateType() != null) { + updateFromResourceOwnership.add(res); + } + } + + // 2. Propagate type information. + while (updateFromResource.size() > 0 || updateFromVariable.size() > 0 || updateFromMessage.size() > 0 + || updateFromConsOrSet.size() > 0 || updateFromTuple.size() > 0 || updateFromPair.size() > 0 + || updateFromMap.size() > 0 || updateFromJson.size() > 0 || updateFromResourceOwnership.size() > 0) { + if (updateFromResource.size() > 0) { + Set resourceKeys = updateFromResource.keySet(); + Integer resourceKey = resourceKeys.iterator().next(); + Map resourceValue = updateFromResource.get(resourceKey); + updateFromResource.remove(resourceKey); + for (int i : resourceValue.keySet()) { + Expression resExp = resourceValue.get(i); + updateVaribleTypes(resExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(resExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(resExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(resExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(resExp, pair, expToPair, updateFromPair); + updateMapTypes(resExp, map, expToMap, updateFromMap); + updateJsonTypes(resExp, json, expToJson, updateFromJson); + updateResourcePathParamsTypes(resExp, resourcePathParams, updateFromResourceOwnership); + } + } + if (updateFromVariable.size() > 0) { + Set variableKeys = updateFromVariable.keySet(); + Integer variableKey = variableKeys.iterator().next(); + Map variableValue = updateFromVariable.get(variableKey); + updateFromVariable.remove(variableKey); + for (int i : variableValue.keySet()) { + Expression var = variableValue.get(i); + updateResourceTypes(var, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(var, variables, expToVariable, updateFromVariable); + updateMessageTypes(var, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(var, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(var, tuple, expToTuple, updateFromTuple); + updatePairTypes(var, pair, expToPair, updateFromPair); + updateMapTypes(var, map, expToMap, updateFromMap); + updateJsonTypes(var, json, expToJson, updateFromJson); + updateResourcePathParamsTypes(var, resourcePathParams, updateFromResourceOwnership); + } + } + if (updateFromMessage.size() > 0) { + Set messageKeys = updateFromMessage.keySet(); + Integer messageKey = messageKeys.iterator().next(); + Map messageValue = updateFromMessage.get(messageKey); + updateFromMessage.remove(messageKey); + for (int i : messageValue.keySet()) { + Expression mesExp = messageValue.get(i); + updateResourceTypes(mesExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(mesExp, variables, expToVariable, updateFromVariable); + updateConsOrSetTypes(mesExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(mesExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(mesExp, pair, expToPair, updateFromPair); + updateMapTypes(mesExp, map, expToMap, updateFromMap); + updateJsonTypes(mesExp, json, expToJson, updateFromJson); + updateResourcePathParamsTypes(mesExp, resourcePathParams, updateFromResourceOwnership); + } + } + if (updateFromConsOrSet.size() > 0) { + Set consKeys = updateFromConsOrSet.keySet(); + Integer consKey = consKeys.iterator().next(); + Map consValue = updateFromConsOrSet.get(consKey); + updateFromConsOrSet.remove(consKey); + for (int i : consValue.keySet()) { + Expression consExp = consValue.get(i); + updateResourceTypes(consExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(consExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(consExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(consExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(consExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(consExp, pair, expToPair, updateFromPair); + updateMapTypes(consExp, map, expToMap, updateFromMap); + updateJsonTypes(consExp, json, expToJson, updateFromJson); + } + } + if (updateFromTuple.size() > 0) { + Set tupleKeys = updateFromTuple.keySet(); + Integer tupleKey = tupleKeys.iterator().next(); + Map tupleValue = updateFromTuple.get(tupleKey); + updateFromTuple.remove(tupleKey); + for (int i : tupleValue.keySet()) { + Expression tupleExp = tupleValue.get(i); + updateResourceTypes(tupleExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(tupleExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(tupleExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(tupleExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(tupleExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(tupleExp, pair, expToPair, updateFromPair); + updateMapTypes(tupleExp, map, expToMap, updateFromMap); + updateJsonTypes(tupleExp, json, expToJson, updateFromJson); + } + } + if (updateFromPair.size() > 0) { + Set pairKeys = updateFromPair.keySet(); + Integer pairKey = pairKeys.iterator().next(); + Map pairValue = updateFromPair.get(pairKey); + updateFromPair.remove(pairKey); + for (int i : pairValue.keySet()) { + Expression pairExp = pairValue.get(i); + updateResourceTypes(pairExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(pairExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(pairExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(pairExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(pairExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(pairExp, pair, expToPair, updateFromPair); + updateMapTypes(pairExp, map, expToMap, updateFromMap); + updateJsonTypes(pairExp, json, expToJson, updateFromJson); + } + } + if (updateFromMap.size() > 0) { + Set mapKeys = updateFromMap.keySet(); + Integer mapKey = mapKeys.iterator().next(); + Map mapValue = updateFromMap.get(mapKey); + updateFromMap.remove(mapKey); + for (int i : mapValue.keySet()) { + Expression mapExp = mapValue.get(i); + updateResourceTypes(mapExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(mapExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(mapExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(mapExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(mapExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(mapExp, pair, expToPair, updateFromPair); + updateMapTypes(mapExp, map, expToMap, updateFromMap); + updateJsonTypes(mapExp, json, expToJson, updateFromJson); + } + } + if (updateFromJson.size() > 0) { + Set jsonKeys = updateFromJson.keySet(); + Integer jsonKey = jsonKeys.iterator().next(); + Map jsonValue = updateFromJson.get(jsonKey); + updateFromJson.remove(jsonKey); + for (int i : jsonValue.keySet()) { + Expression jsonExp = jsonValue.get(i); + updateResourceTypes(jsonExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(jsonExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(jsonExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(jsonExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(jsonExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(jsonExp, pair, expToPair, updateFromPair); + updateMapTypes(jsonExp, map, expToMap, updateFromMap); + updateJsonTypes(jsonExp, json, expToJson, updateFromJson); + } + } + if (updateFromResourceOwnership.size() > 0) { + ResourceHierarchy res = updateFromResourceOwnership.iterator().next(); + updateFromResourceOwnership.remove(res); + updateResourceOwnershipTypes(res, resources, expToResource, updateFromResource, updateFromResourceOwnership); + } + } + } + + private void updateExpressionBelonging(Map>> belonging, Expression exp, List group) { + Set> groups = belonging.get(System.identityHashCode(exp)); + if (groups == null) { + groups = new HashSet<>(); + belonging.put(System.identityHashCode(exp), groups); + groups.add(group); + return; + } + if (!groups.contains(group)) { + groups.add(group); + } + } + + private void updateResourceTypes(Expression exp, Map> resources, Map> expToResource, + Map> updateFromResource, Set updateFromResourceOwnership) { + List identicalResources = expToResource.get(System.identityHashCode(exp)); + if (identicalResources == null) return; + for (ResourceHierarchy res: resources.keySet()) { + if (resources.get(res) == identicalResources) { + Type resType = res.getResourceStateType(); + Type newResType = getExpTypeIfUpdatable(resType, exp); + if (newResType != null) { + res.setResourceStateType(newResType); + updateFromResourceOwnership.add(res); // To update parent and children resources + // Update identical resources + Map updateExps = getUpdateSet(updateFromResource, identicalResources); + for (Expression resExp : identicalResources) { + if (resExp != exp) { + if (resExp instanceof Variable) { + ((Variable) resExp).setType(newResType); + updateExps.put(System.identityHashCode(resExp), resExp); + } else if (resExp instanceof Term) { + ((Term) resExp).setType(newResType); + updateExps.put(System.identityHashCode(resExp), resExp); + } + } + } + } + } + } + } + + private void updateResourcePathParamsTypes(Expression exp, Map> resourcePathParams, Set updateFromResourceOwnership) { + for (ResourceHierarchy parent: resourcePathParams.keySet()) { + List pathParams = resourcePathParams.get(parent); + if (pathParams.contains(exp)) { + Type parentType = parent.getResourceStateType(); + Type paramType = null; + if (exp instanceof Variable) { + paramType = ((Variable) exp).getType(); + } else if (exp instanceof Term) { + paramType = ((Term) exp).getType(); + } + if (paramType != null && parentType == null) { + if (paramType.equals(DataConstraintModel.typeString)) { + parentType = DataConstraintModel.typeMap; + } else if (paramType.equals(DataConstraintModel.typeInt)) { + parentType = DataConstraintModel.typeList; + } + if (parentType != null) { + parent.setResourceStateType(parentType); + updateFromResourceOwnership.add(parent); + } + } + } + } + } + + private void updateResourceOwnershipTypes(ResourceHierarchy res, Map> resources, + Map> expToResource, Map> updateFromResource, Set updateFromResourceOwnership) { + for (ResourceHierarchy parent: resources.keySet()) { + Type resType = res.getResourceStateType(); + Set children = parent.getChildren(); + if (res.equals(parent)) { + // Propagate an update of a parent resource type to its children' types. + if (DataConstraintModel.typeList.isAncestorOf(resType)) { + Type newElementType = listComponentTypes.get(resType); + if (newElementType != null && children != null && children.size() == 1) { + ResourceHierarchy element = children.iterator().next(); + Type elementType = element.getResourceStateType(); + if (compareTypes(elementType, newElementType)) { + element.setResourceStateType(newElementType); + updateFromResourceOwnership.add(element); + } + } + } else if (DataConstraintModel.typeMap.isAncestorOf(resType)) { + List newComponentTypes = mapComponentTypes.get(resType); + if (newComponentTypes != null && newComponentTypes.size() == 2 && children != null && children.size() == 1) { + ResourceHierarchy value = children.iterator().next(); + Type valueType = value.getResourceStateType(); + if (compareTypes(valueType, newComponentTypes.get(1))) { + value.setResourceStateType(newComponentTypes.get(1)); + updateFromResourceOwnership.add(value); + } + } + } else if (DataConstraintModel.typeJson.isAncestorOf(resType)) { + Map newMemberTypes = jsonMemberTypes.get(resType); + if (newMemberTypes != null && newMemberTypes.size() > 0 && children != null && children.size() > 0) { + for (ResourceHierarchy chlid: children) { + String key = chlid.getResourceName(); + Type memberType = chlid.getResourceStateType(); + if (compareTypes(memberType, newMemberTypes.get(key))) { + chlid.setResourceStateType(newMemberTypes.get(key)); + updateFromResourceOwnership.add(chlid); + } + } + } + } + } + if (children.contains(res)) { + // Propagate an update of a child resource type to its parent's type. + Type parentType = parent.getResourceStateType(); + if (parentType != null && DataConstraintModel.typeList.isAncestorOf(parentType)) { + Type oldElementType = listComponentTypes.get(parentType); + if (compareTypes(oldElementType, resType)) { + Type newListType = listTypes.get(resType); + if (newListType == null) { + newListType = createNewListType(resType, parentType); + } + if (newListType != null) { + parent.setResourceStateType(newListType); + updateFromResourceOwnership.add(parent); + } + } + } else if (parentType != null && DataConstraintModel.typeMap.isAncestorOf(parentType)) { + List oldComponentTypes = mapComponentTypes.get(parentType); + if (compareTypes(oldComponentTypes.get(1), resType)) { + List newComponentTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, resType}); + Type newMapType = mapTypes.get(newComponentTypes); + if (newMapType == null) { + newMapType = createNewMapType(newComponentTypes, parentType); + } + if (newMapType != null) { + parent.setResourceStateType(newMapType); + updateFromResourceOwnership.add(parent); + } + } + } else if (parentType != null && DataConstraintModel.typeJson.isAncestorOf(parentType)) { + Map oldMemberTypes = jsonMemberTypes.get(parentType); + String key= res.getResourceName(); + if (oldMemberTypes == null || compareTypes(oldMemberTypes.get(key), resType)) { + Map newMemberTypes = new HashMap<>(); + if (oldMemberTypes != null) newMemberTypes.putAll(oldMemberTypes); + newMemberTypes.put(key, resType); + Type newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + newJsonType = createNewJsonType(newMemberTypes, parentType); + } + if (newJsonType != null) { + parent.setResourceStateType(newJsonType); + updateFromResourceOwnership.add(parent); + } + } + } + } + } + // Propagate an update of the resource to its expressions. + List identicalResources = resources.get(res); + if (identicalResources != null) { + Type newResType = res.getResourceStateType(); + for (Expression resExp: identicalResources) { + Type resType = null; + if (resExp instanceof Variable) { + resType = ((Variable) resExp).getType(); + } else if (resExp instanceof Term) { + resType = ((Term) resExp).getType(); + } + if (resType == null || compareTypes(resType, newResType)) { + Map updateExps = getUpdateSet(updateFromResource, identicalResources); + if (resExp instanceof Variable) { + ((Variable) resExp).setType(newResType); + updateExps.put(System.identityHashCode(resExp), resExp); + } else if (resExp instanceof Term) { + ((Term) resExp).setType(newResType); + updateExps.put(System.identityHashCode(resExp), resExp); + } + } + } + } + } + + private void updateVaribleTypes(Expression exp, Map variables, + Map> expToVariable, Map> updateFromVariable) { + List sameVariable = expToVariable.get(System.identityHashCode(exp)); + if (sameVariable == null) return; + Type varType = variables.get(System.identityHashCode(sameVariable)); + Type newVarType = getExpTypeIfUpdatable(varType, exp); + if (newVarType != null) { + variables.put(System.identityHashCode(sameVariable), newVarType); + Map updateVars = getUpdateSet(updateFromVariable, sameVariable); + for (Expression v : sameVariable) { + if (v != exp) { + if (v instanceof Variable) { + ((Variable) v).setType(newVarType); + updateVars.put(System.identityHashCode(v), v); + } else if (v instanceof Term) { + ((Term) v).setType(newVarType); + updateVars.put(System.identityHashCode(v), v); + } + } + } + } else { + Map updateVars = getUpdateSet(updateFromVariable, sameVariable); + for (Expression v : sameVariable) { + if (v instanceof Variable) { + Type orgVarType = ((Variable) v).getType(); + if (orgVarType != varType && compareTypes(orgVarType, varType)) { + ((Variable) v).setType(varType); + updateVars.put(System.identityHashCode(v), v); + } + } else if (v instanceof Term) { + Type orgVarType = ((Term) v).getType(); + if (orgVarType != varType && compareTypes(orgVarType, varType)) { + ((Term) v).setType(varType); + updateVars.put(System.identityHashCode(v), v); + } + } + } + } + } + + private void updateMessageTypes(Expression exp, + Map, Type>>> messages, + Map> expToMessage, Map> updateFromMessage) { + List messageExps = expToMessage.get(System.identityHashCode(exp)); + if (messageExps == null) return; + Type msgType = null; + Map.Entry, Type> expsAndType = null; + for (Channel c : messages.keySet()) { + for (int i : messages.get(c).keySet()) { + expsAndType = messages.get(c).get(i); + if (expsAndType.getKey() == messageExps) { + msgType = expsAndType.getValue(); + break; + } + } + if (msgType != null) break; + } + if (msgType == null) return; + Type newMsgType = getExpTypeIfUpdatable(msgType, exp); + if (newMsgType != null) { + expsAndType.setValue(newMsgType); + Map updateExps = getUpdateSet(updateFromMessage, messageExps); + for (Expression e : messageExps) { + if (e != exp) { + if (e instanceof Variable) { + ((Variable) e).setType(newMsgType); + updateExps.put(System.identityHashCode(e), e); + } else if (e instanceof Term) { + ((Term) e).setType(newMsgType); + updateExps.put(System.identityHashCode(e), e); + } + } + } + } + } + + private void updateConsOrSetTypes(Expression exp, Map consOrSet, + Map>> expToConsOrSet, Map> updateFromConsOrSet) { + Set> consComponentGroups = expToConsOrSet.get(System.identityHashCode(exp)); + if (consComponentGroups == null) return; + for (List consOrSetComponentGroup: consComponentGroups) { + int idx = consOrSetComponentGroup.indexOf(exp); + switch (idx) { + case 0: + // exp is a list itself. + if (!(exp instanceof Term)) break; + Type listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); + Type expType = getExpTypeIfUpdatable(listType, exp); + if (expType != null) { + consOrSet.put(System.identityHashCode(consOrSetComponentGroup), expType); + Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); + if (consOrSetComponentGroup.get(2) instanceof Variable) { + ((Variable) consOrSetComponentGroup.get(2)).setType(expType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); + } else if (consOrSetComponentGroup.get(2) instanceof Term) { + ((Term) consOrSetComponentGroup.get(2)).setType(expType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); + } + Type compType = listComponentTypes.get(expType); + if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Variable) { + ((Variable) consOrSetComponentGroup.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); + } else if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Term) { + ((Term) consOrSetComponentGroup.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); + } + } + break; + case 1: + // exp is a list's component. + listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); + Type compType = listComponentTypes.get(listType); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + Type newListType = listTypes.get(newCompType); + if (newListType == null) { + // Create new list type. + newListType = createNewListType(newCompType, listType); + } + consOrSet.put(System.identityHashCode(consOrSetComponentGroup), newListType); + Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); + if (consOrSetComponentGroup.get(0) instanceof Term) { + ((Term) consOrSetComponentGroup.get(0)).setType(newListType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(0)), consOrSetComponentGroup.get(0)); + } + if (consOrSetComponentGroup.get(2) instanceof Variable) { + ((Variable) consOrSetComponentGroup.get(2)).setType(newListType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); + } else if (consOrSetComponentGroup.get(2) instanceof Term) { + ((Term) consOrSetComponentGroup.get(2)).setType(newListType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); + } + } + break; + case 2: + // exp is a list itself. + listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); + expType = getExpTypeIfUpdatable(listType, exp); + if (expType != null) { + consOrSet.put(System.identityHashCode(consOrSetComponentGroup), expType); + Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); + if (consOrSetComponentGroup.get(0) instanceof Term) { + ((Term) consOrSetComponentGroup.get(0)).setType(expType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(0)), consOrSetComponentGroup.get(0)); + } + compType = listComponentTypes.get(expType); + if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Variable) { + ((Variable) consOrSetComponentGroup.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); + } else if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Term) { + ((Term) consOrSetComponentGroup.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); + } + } + } + } + } + + private void updateTupleTypes(Expression exp, Map tuple, + Map>> expToTuple, Map> updateFromTuple) { + Set> tupleComponentGroups = expToTuple.get(System.identityHashCode(exp)); + if (tupleComponentGroups == null) return; + for (List tupleComponentGroup: tupleComponentGroups) { + int idx = tupleComponentGroup.indexOf(exp); + if (idx == 0) { + // exp is a tuple itself. + Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); + Type newTupleType = getExpTypeIfUpdatable(tupleType, exp); + if (newTupleType != null) { + // Propagate an update of a tuple's type to its components' types. + tuple.put(System.identityHashCode(tupleComponentGroup), newTupleType); + List componentTypes = tupleComponentTypes.get(newTupleType); + Map updateExps = getUpdateSet(updateFromTuple, tupleComponentGroup); + for (int i = 1; i < tupleComponentGroup.size(); i++) { + Expression compExp = tupleComponentGroup.get(i); + if (compExp instanceof Variable) { + Type compType = ((Variable) compExp).getType(); + if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { + // If the type of one component (compExp) is also tuple. + Type newExpType = tupleTypes.get(componentTypes.subList(i - 1, componentTypes.size())); + if (newExpType == null) { + // Create new tuple type; + newExpType = createNewTupleType(componentTypes.subList(i - 1, componentTypes.size()), compType); + } + if (compareTypes(compType, newExpType)) { + ((Variable) compExp).setType(newExpType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else { + if (i - 1 < componentTypes.size()) { + if (compareTypes(compType, componentTypes.get(i - 1))) { + ((Variable) compExp).setType(componentTypes.get(i - 1)); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else { + // for insert + if (compareTypes(compType, newTupleType)) { + ((Variable) compExp).setType(newTupleType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } + } + } else if (compExp instanceof Term) { + Type compType = ((Term) compExp).getType(); + if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { + // If the type of one component (compExp) is also tuple. + Type newExpType = tupleTypes.get(componentTypes.subList(i - 1, componentTypes.size())); + if (newExpType == null) { + // Create new tuple type; + newExpType = createNewTupleType(componentTypes.subList(i - 1, componentTypes.size()), compType); + } + if (compareTypes(compType, newExpType)) { + ((Term) compExp).setType(newExpType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else { + if (i - 1 < componentTypes.size()) { + if (compareTypes(compType, componentTypes.get(i - 1))) { + ((Term) compExp).setType(componentTypes.get(i - 1)); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else { + // for insert + if (compareTypes(compType, newTupleType)) { + ((Term) compExp).setType(newTupleType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } + } + } + } + } + } else { + // exp is a tuple's component. + Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); + List componentTypes = tupleComponentTypes.get(tupleType); + boolean updated = false; + if (idx == 1) { + Type compType = componentTypes.get(idx - 1); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + componentTypes = new ArrayList<>(componentTypes); + componentTypes.set(idx - 1, newCompType); + updated = true; + } + } else { + Type expType = null; + if (exp instanceof Term) { + expType = ((Term) exp).getType(); + } else if (exp instanceof Variable) { + expType = ((Variable) exp).getType(); + } + if (expType != null && DataConstraintModel.typeTuple.isAncestorOf(expType)) { + // If the type of the updated component (exp) is also tuple. + List subCompTypes = tupleComponentTypes.get(expType); + componentTypes = new ArrayList<>(componentTypes); + for (int i = 0; i < subCompTypes.size(); i++) { + if (componentTypes.size() < i + 2) { + componentTypes.add(subCompTypes.get(i)); + updated = true; + } else if (compareTypes(componentTypes.get(i + 1), subCompTypes.get(i))) { + componentTypes.set(i + 1, subCompTypes.get(i)); + updated = true; + } + } + } else { + Type compType = componentTypes.get(idx - 1); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + componentTypes = new ArrayList<>(componentTypes); + componentTypes.set(idx - 1, newCompType); + updated = true; + } + } + } + if (updated) { + // Propagate an update of a component's type to its container's (tuple's) type. + Type newTupleType = tupleTypes.get(componentTypes); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(componentTypes, tupleType); + } + Map updateExps = getUpdateSet(updateFromTuple, tupleComponentGroup); + Expression tupleExp = tupleComponentGroup.get(0); + if (tupleExp instanceof Variable) { + ((Variable) tupleExp).setType(newTupleType); + updateExps.put(System.identityHashCode(tupleExp), tupleExp); + } else if (tupleExp instanceof Term) { + ((Term) tupleExp).setType(newTupleType); + updateExps.put(System.identityHashCode(tupleExp), tupleExp); + } + tuple.put(System.identityHashCode(tupleComponentGroup), newTupleType); + } + } + } + } + + private void updatePairTypes(Expression exp, Map pair, + Map>> expToPair, Map> updateFromPair) { + Set> pairComponentGroups = expToPair.get(System.identityHashCode(exp)); + if (pairComponentGroups == null) return; + for (List pairComponentGroup: pairComponentGroups) { + int idx = pairComponentGroup.indexOf(exp); + if (idx == 0) { + // exp is a pair itself. + Type pairType = pair.get(System.identityHashCode(pairComponentGroup)); + Type newPairType = getExpTypeIfUpdatable(pairType, exp); + if (newPairType != null) { + // Propagate an update of a pair's type to its components' types. + pair.put(System.identityHashCode(pairComponentGroup), newPairType); + Type componentType = pairComponentTypes.get(newPairType); + Map updateExps = getUpdateSet(updateFromPair, pairComponentGroup); + for (int i = 1; i < pairComponentGroup.size(); i++) { + Expression compExp = pairComponentGroup.get(i); + if (compExp instanceof Variable) { + if (compareTypes(((Variable) compExp).getType(), componentType)) { + ((Variable) compExp).setType(componentType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else if (compExp instanceof Term) { + if (compareTypes(((Term) compExp).getType(), componentType)) { + ((Term) compExp).setType(componentType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } + } + } + } else { + // exp is a pair's component. + Type pairType = pair.get(System.identityHashCode(pairComponentGroup)); + Type compType = pairComponentTypes.get(pairType); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + // Propagate an update of a component's type to its container's (pair's) type. + Type newPairType = pairTypes.get(compType); + if (newPairType != null) { + Map updateExps = getUpdateSet(updateFromPair, pairComponentGroup); + Expression pairExp = pairComponentGroup.get(0); + if (pairExp instanceof Variable) { + ((Variable) pairExp).setType(newPairType); + updateExps.put(System.identityHashCode(pairExp), pairExp); + } else if (pairExp instanceof Term) { + ((Term) pairExp).setType(newPairType); + updateExps.put(System.identityHashCode(pairExp), pairExp); + } + pair.put(System.identityHashCode(pairComponentGroup), newPairType); + } + } + } + } + } + + private void updateMapTypes(Expression exp, Map map, + Map>> expToMap, Map> updateFromMap) { + Set> mapComponentGroups = expToMap.get(System.identityHashCode(exp)); + if (mapComponentGroups == null) return; + for (List mapComponentGroup: mapComponentGroups) { + int idx = mapComponentGroup.indexOf(exp); + if (idx == 0 || idx == 3) { + // exp is a map itself. + Type mapType = map.get(System.identityHashCode(mapComponentGroup)); + Type newMapType = getExpTypeIfUpdatable(mapType, exp); + if (newMapType != null) { + // Propagate an update of a map's type to its components' types. + map.put(System.identityHashCode(mapComponentGroup), newMapType); + List componentTypes = mapComponentTypes.get(newMapType); + Map updateExps = getUpdateSet(updateFromMap, mapComponentGroup); + for (int i = 1; i < mapComponentGroup.size() && i < 3; i++) { + Expression compExp = mapComponentGroup.get(i); + if (compExp instanceof Variable) { + if (compareTypes(((Variable) compExp).getType(), componentTypes.get(i - 1))) { + ((Variable) compExp).setType(componentTypes.get(i - 1)); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else if (compExp instanceof Term) { + if (compareTypes(((Term) compExp).getType(), componentTypes.get(i - 1))) { + ((Term) compExp).setType(componentTypes.get(i - 1)); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } + } + // Propagate an update of a map's type to another map's type. + Expression compExp = null; + if (idx == 0 && mapComponentGroup.size() == 4) { // for insert + compExp = mapComponentGroup.get(3); + } else if (idx == 3) { + compExp = mapComponentGroup.get(0); + } + if (compExp != null) { + if (compExp instanceof Variable) { + if (compareTypes(((Variable) compExp).getType(), newMapType)) { + ((Variable) compExp).setType(newMapType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else if (compExp instanceof Term) { + if (compareTypes(((Term) compExp).getType(), newMapType)) { + ((Term) compExp).setType(newMapType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } + } + } + } else { + // exp is a map's key or value. + Type mapType = map.get(System.identityHashCode(mapComponentGroup)); + List componentTypes = mapComponentTypes.get(mapType); + Type compType = componentTypes.get(idx - 1); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + // Propagate an update of a component's type to its container's (map's) type. + componentTypes = new ArrayList<>(componentTypes); + componentTypes.set(idx - 1, newCompType); + Type newMapType = mapTypes.get(componentTypes); + if (newMapType == null) { + // Create new map type; + newMapType = createNewMapType(componentTypes, mapType); + } + Map updateExps = getUpdateSet(updateFromMap, mapComponentGroup); + Expression mapExp = mapComponentGroup.get(0); + if (mapExp instanceof Variable) { + ((Variable) mapExp).setType(newMapType); + updateExps.put(System.identityHashCode(mapExp), mapExp); + } else if (mapExp instanceof Term) { + ((Term) mapExp).setType(newMapType); + updateExps.put(System.identityHashCode(mapExp), mapExp); + } + if (mapComponentGroup.size() == 4) { // for insert + mapExp = mapComponentGroup.get(3); + if (mapExp instanceof Variable) { + ((Variable) mapExp).setType(newMapType); + updateExps.put(System.identityHashCode(mapExp), mapExp); + } else if (mapExp instanceof Term) { + ((Term) mapExp).setType(newMapType); + updateExps.put(System.identityHashCode(mapExp), mapExp); + } + } + map.put(System.identityHashCode(mapComponentGroup), newMapType); + } + } + } + } + + + private void updateJsonTypes(Expression exp, Map json, + Map>> expToJson, Map> updateFromJson) { + Set> jsonMemberGroups = expToJson.get(System.identityHashCode(exp)); + if (jsonMemberGroups == null) return; + for (List jsonMemberGroup: jsonMemberGroups) { + int idx = jsonMemberGroup.indexOf(exp); + if (idx == 3) { + // exp is a json argument (0:t = addMember(3:json, 1:key, 2:value)). + Type jsonType = json.get(System.identityHashCode(jsonMemberGroup)); + if (jsonType != null && jsonMemberTypes.get(jsonType) != null) { + Map memberTypes = new HashMap<>(jsonMemberTypes.get(jsonType)); + Map argMemberTypes = new HashMap<>(memberTypes); + String keyName = null; + Type valueType = null; + if (jsonMemberGroup.get(1) instanceof Constant) { + keyName = ((Constant) jsonMemberGroup.get(1)).getSymbol().getName(); + valueType = ((Constant) jsonMemberGroup.get(1)).getType(); + argMemberTypes.remove(keyName); + } + Type jsonArgType = jsonTypes.get(argMemberTypes); + Type newJsonArgType = getExpTypeIfUpdatable(jsonArgType, exp); + if (newJsonArgType != null && keyName != null) { + // Propagate an update of a json arg's type to its container's (json's) type. + argMemberTypes = ((JsonType) newJsonArgType).getMemberTypes(); + argMemberTypes.put(keyName, valueType); + memberTypes.putAll(argMemberTypes); + Type newJsonType = jsonTypes.get(memberTypes); + if (newJsonType == null) { + // Create new json type. + newJsonType = createNewJsonType(memberTypes, jsonType); + } + // Update the type of the json term and record the updated expression. + Map updateExps = getUpdateSet(updateFromJson, jsonMemberGroup); + Expression jsonExp = jsonMemberGroup.get(0); + if (jsonExp instanceof Variable) { + ((Variable) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } else if (jsonExp instanceof Term) { + ((Term) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } + json.put(System.identityHashCode(jsonMemberGroup), newJsonType); + } + } + } else if (idx == 2) { + // exp is a value (0:t = addMember(3:json, 1:key, 2:value) or 2:value = dot(0:list/map, 1:key)). + Type jsonType = json.get(System.identityHashCode(jsonMemberGroup)); + Type newJsonType = null; + if (exp instanceof Term && ((Term) exp).getSymbol().equals(DataConstraintModel.dotParam)) { + if (DataConstraintModel.typeList.isAncestorOf(jsonType)) { + Type elementType = listComponentTypes.get(jsonType); + Type newElementType = getExpTypeIfUpdatable(elementType, exp); + if (newElementType != null) { + // Propagate an update of a member's type to its container's (json's) type. + newJsonType = listTypes.get(newElementType); + if (newJsonType == null) { + // Create new json type. + newJsonType = createNewListType(newElementType, jsonType); + } + } + } else if (DataConstraintModel.typeMap.isAncestorOf(jsonType)) { + List keyValueTypes = mapComponentTypes.get(jsonType); + Type newValueType = getExpTypeIfUpdatable(keyValueTypes.get(1), exp); + if (newValueType != null) { + // Propagate an update of a member's type to its container's (json's) type. + List newKeyValueTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, newValueType}); + newJsonType = mapTypes.get(newKeyValueTypes); + if (newJsonType == null) { + // Create new json type. + newJsonType = createNewMapType(newKeyValueTypes, jsonType); + } + } + } + } else { + Map memberTypes = jsonMemberTypes.get(jsonType); + String keyName = null; + if (jsonMemberGroup.get(1) instanceof Constant) { + keyName = ((Constant) jsonMemberGroup.get(1)).getSymbol().getName(); + } + if (memberTypes != null) { + Type memberType = memberTypes.get(keyName); + Type newMemberType = getExpTypeIfUpdatable(memberType, exp); + if (newMemberType != null && keyName != null) { + // Propagate an update of a member's type to its container's (json's) type. + Map newMemberTypes = new HashMap<>(memberTypes); + newMemberTypes.put(keyName, newMemberType); + newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + // Create new json type. + newJsonType = createNewJsonType(newMemberTypes, jsonType); + } + } + } + } + if (newJsonType != null) { + // Update the type of the json term and record the updated expression. + Map updateExps = getUpdateSet(updateFromJson, jsonMemberGroup); + Expression jsonExp = jsonMemberGroup.get(0); + if (jsonExp instanceof Variable) { + ((Variable) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } else if (jsonExp instanceof Term) { + ((Term) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } + json.put(System.identityHashCode(jsonMemberGroup), newJsonType); + } + } + } + } + + private ListType createNewListType(Type compType, Type parentType) { + List childrenTypes = getChildrenTypes(parentType, listComponentTypes.keySet()); + ListType newListType = langSpec.newListType(compType, parentType); + listTypes.put(compType, newListType); + listComponentTypes.put(newListType, compType); + for (Type childType : childrenTypes) { + if (compareTypes(childType, newListType)) { + if (newListType.getParentTypes().contains(parentType)) { + newListType.replaceParentType(parentType, childType); + } else { + newListType.addParentType(childType); + } + } else if (compareTypes(newListType, childType)) { + childType.replaceParentType(parentType, newListType); + } + } + return newListType; + } + + private MapType createNewMapType(List componentTypes, Type parentMapType) { + List childrenTypes = getChildrenTypes(parentMapType, mapComponentTypes.keySet()); + MapType newMapType = langSpec.newMapType(componentTypes.get(0), componentTypes.get(1), parentMapType); + mapTypes.put(componentTypes, newMapType); + mapComponentTypes.put(newMapType, componentTypes); + for (Type childType : childrenTypes) { + if (compareTypes(childType, newMapType)) { + if (newMapType.getParentTypes().contains(parentMapType)) { + newMapType.replaceParentType(parentMapType, childType); + } else { + newMapType.addParentType(childType); + } + } else if (compareTypes(newMapType, childType)) { + childType.replaceParentType(parentMapType, newMapType); + } + } + return newMapType; + } + + private TupleType createNewTupleType(List componentTypes, Type parentTupleType) { + List childrenTypes = getChildrenTypes(parentTupleType, tupleComponentTypes.keySet()); + TupleType newTupleType = langSpec.newTupleType(componentTypes, parentTupleType); + tupleTypes.put(componentTypes, newTupleType); + tupleComponentTypes.put(newTupleType, componentTypes); + for (Type childType : childrenTypes) { + if (compareTypes(childType, newTupleType)) { + if (newTupleType.getParentTypes().contains(parentTupleType)) { + newTupleType.replaceParentType(parentTupleType, childType); + } else { + newTupleType.addParentType(childType); + } + } else if (compareTypes(newTupleType, childType)) { + childType.replaceParentType(parentTupleType, newTupleType); + } + } + return newTupleType; + } + + private JsonType createNewJsonType(Map memberTypes, Type parentJsonType) { + List childrenTypes = getChildrenTypes(parentJsonType, jsonMemberTypes.keySet()); + JsonType newJsonType = langSpec.newJsonType(parentJsonType); + for (String key: memberTypes.keySet()) { + newJsonType.addMemberType(key, memberTypes.get(key)); + } + jsonTypes.put(memberTypes, newJsonType); + jsonMemberTypes.put(newJsonType, memberTypes); + for (Type childType : childrenTypes) { + if (compareTypes(childType, newJsonType)) { + if (newJsonType.getParentTypes().contains(parentJsonType)) { + newJsonType.replaceParentType(parentJsonType, childType); + } else { + newJsonType.addParentType(childType); + } + } else if (compareTypes(newJsonType, childType)) { + childType.replaceParentType(parentJsonType, newJsonType); + } + } + return newJsonType; + } + + /** + * Get children types of a given type from given set of types. + * @param parentType a type + * @param allTypes set of types + * @return list of the children types + */ + private List getChildrenTypes(Type parentType, Set allTypes) { + List childrenTypes = new ArrayList<>(); + for (Type childType : allTypes) { + if (childType.getParentTypes().contains(parentType)) { + childrenTypes.add(childType); + } + } + return childrenTypes; + } + + private String getImplementationTypeName(Type type) { + if (type == null) + return "Object"; + String wrapperType = DataConstraintModel.getWrapperType(type); + if (wrapperType != null) + return wrapperType; + return type.getImplementationTypeName(); + } + + private String getInterfaceTypeName(Type type) { + if (type == null) + return "Object"; + String wrapperType = DataConstraintModel.getWrapperType(type); + if (wrapperType != null) + return wrapperType; + return type.getInterfaceTypeName(); + } + + private > Map getUpdateSet(Map> updateSets, U keySet) { + Map updatedExps = updateSets.get(System.identityHashCode(keySet)); + if (updatedExps == null) { + updatedExps = new HashMap<>(); + updateSets.put(System.identityHashCode(keySet), updatedExps); + } + return updatedExps; + } + + private Type getExpTypeIfUpdatable(Type originalType, Expression newExp) { + Type expType = null; + if (newExp instanceof Term) { + expType = ((Term) newExp).getType(); + } else if (newExp instanceof Variable) { + expType = ((Variable) newExp).getType(); + } + if (compareTypes(originalType, expType)) { + return expType; + } + return null; + } + + /** + * Is an given original type an ancestor of a given new type? + * + * @param originalType original type + * @param newType new type (may not have been registered) + * @return true: if the original type equals to the new type or is an ancestor + * of the new type, false: otherwise + */ + private boolean compareTypes(Type originalType, Type newType) { + if (originalType == null) return true; + if (originalType != newType && newType != null) { + if (originalType.isAncestorOf(newType)) return true; + if (newType.isAncestorOf(originalType)) return false; + if (DataConstraintModel.typeMap.isAncestorOf(originalType) + && DataConstraintModel.typeMap.isAncestorOf(newType)) { + List originalCompTypes = mapComponentTypes.get(originalType); + List newCompTypes = mapComponentTypes.get(newType); + if (originalCompTypes == null) return true; + for (int i = 0; i < originalCompTypes.size(); i++) { + if (originalCompTypes.get(i) != null && + (newCompTypes.get(i) == null || !originalCompTypes.get(i).isAncestorOf(newCompTypes.get(i)))) return false; + } + return true; + } + if (DataConstraintModel.typeTuple.isAncestorOf(originalType) + && DataConstraintModel.typeTuple.isAncestorOf(newType)) { + List originalCompTypes = tupleComponentTypes.get(originalType); + List newCompTypes = tupleComponentTypes.get(newType); + if (originalCompTypes == null) return true; + originalCompTypes = new ArrayList<>(originalCompTypes); + newCompTypes = new ArrayList<>(newCompTypes); + for (int i = 0; i < originalCompTypes.size(); i++) { + if (originalCompTypes.get(i) != null) { + if (DataConstraintModel.typeTuple.isAncestorOf(originalCompTypes.get(i))) { + // Unfold the nested tuple's types. + Type tupleType = originalCompTypes.remove(i); + for (Type t: tupleComponentTypes.get(tupleType)) { + originalCompTypes.add(t); + } + } + if (newCompTypes.size() - 1 < i) return false; + if (newCompTypes.get(i) != null && DataConstraintModel.typeTuple.isAncestorOf(newCompTypes.get(i))) { + // Unfold the nested tuple's types. + Type tupleType = newCompTypes.remove(i); + for (Type t: tupleComponentTypes.get(tupleType)) { + newCompTypes.add(t); + } + } + if (newCompTypes.get(i) == null || !originalCompTypes.get(i).isAncestorOf(newCompTypes.get(i))) return false; + } + } + return true; + } + if (DataConstraintModel.typeList.isAncestorOf(originalType) + && DataConstraintModel.typeList.isAncestorOf(newType)) { + Type originalCompType = listComponentTypes.get(originalType); + Type newCompType = listComponentTypes.get(newType); + if (originalCompType != null && (newCompType == null || !originalCompType.isAncestorOf(newCompType))) return false; + return true; + } + if (DataConstraintModel.typeJson.isAncestorOf(originalType) && DataConstraintModel.typeJson.isAncestorOf(newType)) { + Map originalMemberTypes = jsonMemberTypes.get(originalType); + Map newMemberTypes = jsonMemberTypes.get(newType); + if (originalMemberTypes == null) return true; + if (originalMemberTypes.keySet().size() < newMemberTypes.keySet().size() + && newMemberTypes.keySet().containsAll(originalMemberTypes.keySet())) return true; + if (originalMemberTypes.keySet().size() > newMemberTypes.keySet().size()) return false; + if (!newMemberTypes.keySet().containsAll(originalMemberTypes.keySet())) return false; + for (String key: originalMemberTypes.keySet()) { + if (!originalMemberTypes.get(key).isAncestorOf(newMemberTypes.get(key))) return false; + } + return true; + } + } + return false; + } + + private interface IGroupExpressionsByResource { + public void groupForChannel(Channel ch); + } + + private interface IGroupExpressionsByVariable { + public void groupForChannel(Channel ch); + } + + private interface IGroupExpressionsByMessage { + public void groupForChannel(Channel rootCh, Channel ch); + } + + private static interface IExtractConstraintsOnExpressionsInTerm { + public void extractForChannel(Channel ch); + } + + private static interface IExtractConstraintsOnPathParametersAndResources { + public void extractForChannel(Channel ch); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Constant.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Constant.java index 440145e..2b0e579 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Constant.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Constant.java @@ -1,16 +1,18 @@ package models.algebra; +import generators.JavaImplementationVisitor; + import java.util.ArrayList; public class Constant extends Term { - + public Constant(String value) { super(new Symbol(value, 0), new ArrayList()); } public Constant(String value, Type type) { - super(new Symbol(value, 0), new ArrayList()); - symbol.setSignature(new Type[] {type}); + super(new Symbol((type == null ? value : type.valueToRepresentation(value)), 0), new ArrayList()); + symbol.setSignature(new Type[]{type}); } public Constant(Symbol symbol) { @@ -25,7 +27,7 @@ @Override public Object clone() { - Constant c = new Constant(symbol); + Constant c = new Constant(symbol); c.setType(type); return c; } @@ -34,11 +36,19 @@ return symbol.getName(); } - public String toImplementation(String[] sideEffects) { - if (symbol.isImplGenerative()) { - String exp = symbol.generate(getType(), new String[] {}, new String[] {}, sideEffects); - return exp; + public Object getValue() { + if (getType() != null) { + return getType().representationToValue(symbol.getName()); } - return symbol.getImplName(); + return symbol.getName(); + } + + public String toImplementation(String[] sideEffects) { + return accept(new JavaImplementationVisitor(), sideEffects); + } + + @Override + public String accept(IExpressionVisitor visitor, String[] sideEffects) { + return visitor.visit(this, sideEffects); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Expression.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Expression.java index f0aeadb..65345a1 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Expression.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Expression.java @@ -4,18 +4,39 @@ public abstract class Expression implements Cloneable { public abstract Expression getSubTerm(Position pos); + + /** + * Get the unification between this expression and another expression. + * + * @param another another expression + * @return unified expression + */ public abstract Expression unify(Expression another); + + /** + * Get the inverse map to obtain a sub-term of a given output value back from the output value itself. + * + * @param outputValue an output value (usually a term) + * @param targetPos a position in outputValue + * @return inverse map + */ public abstract Expression getInverseMap(Expression outputValue, Position targetPos); + public abstract boolean contains(Expression exp); + public abstract Object clone(); + public abstract HashMap getSubTerms(Class clazz); public HashMap getVariables() { return getSubTerms(Variable.class); } + public abstract String accept(IExpressionVisitor visitor, String[] sideEffects); + /** * Get the implementation of this expression. + * * @param sideEffects an array with an optional implementation that should be written before the evaluation of this expression * @return the implementation to represent the value of this expression */ diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java index f51b3c4..93076df 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java @@ -1,20 +1,22 @@ package models.algebra; -import java.util.ArrayList; +import generators.JavaImplementationVisitor; /** * A field in the implementation (regarded as a constant in the algebraic system) + * * @author Nitta * */ public class Field extends Constant { - + public Field(String name) { super(name); } public Field(String name, Type type) { - super(name, type); + super(name); + symbol.setSignature(new Type[]{type}); } public Field(Symbol symbol) { @@ -22,12 +24,12 @@ } public Type getType() { - if (symbol.getSignature().length >= 1) { + if (symbol.getSignature() != null && symbol.getSignature().length >= 1) { return symbol.getSignature()[0]; } return null; } - + @Override public boolean equals(Object another) { if (!(another instanceof Field)) return false; @@ -40,6 +42,11 @@ } public String toImplementation(String[] sideEffects) { - return "this." + super.toImplementation(sideEffects); + return accept(new JavaImplementationVisitor(), sideEffects); + } + + @Override + public String accept(IExpressionVisitor visitor, String[] sideEffects) { + return visitor.visit(this, sideEffects); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/IExpressionVisitor.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/IExpressionVisitor.java new file mode 100644 index 0000000..a8a88f5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/IExpressionVisitor.java @@ -0,0 +1,18 @@ +package models.algebra; + +import models.dataConstraintModel.JsonAccessor; +import models.dataConstraintModel.JsonTerm; + +public interface IExpressionVisitor { + String visit(Term term, String[] sideEffects); + + String visit(Field field, String[] sideEffects); + + String visit(Constant constant, String[] sideEffects); + + String visit(Variable variable, String[] sideEffects); + + String visit(JsonTerm jsonTerm, String[] sideEffects); + + String visit(JsonAccessor jsonAccessor, String[] sideEffects); +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/LambdaAbstraction.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/LambdaAbstraction.java new file mode 100644 index 0000000..9898224 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/LambdaAbstraction.java @@ -0,0 +1,30 @@ +package models.algebra; + +import java.util.ArrayList; +import java.util.List; + +public class LambdaAbstraction extends Symbol { + private List variables = null; + private Term term = null; + + public LambdaAbstraction(Variable variable, Term term) { + super("($" + variable.getName() + ")->" + term.toString(), 1, Type.LAMBDA); + this.variables = new ArrayList<>(); + this.variables.add(variable); + this.term = term; + } + + public LambdaAbstraction(List variables, Term term) { + super("($" + variables + ")->" + term.toString(), variables.size(), Type.LAMBDA); + this.variables = variables; + this.term = term; + } + + public List getVariables() { + return variables; + } + + public Term getTerm() { + return term; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Parameter.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Parameter.java index 739ab80..ab84998 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Parameter.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Parameter.java @@ -12,7 +12,8 @@ } public Parameter(String name, Type type) { - super(name, type); + super(name); + symbol.setSignature(new Type[] {type}); } public Parameter(Symbol symbol) { @@ -20,7 +21,7 @@ } public Type getType() { - if (symbol.getSignature().length >= 1) { + if (symbol.getSignature() != null && symbol.getSignature().length >= 1) { return symbol.getSignature()[0]; } return null; diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Position.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Position.java index 0a7c10b..de90a73 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Position.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Position.java @@ -28,6 +28,14 @@ public boolean isEmpty() { return (orders == null || orders.size() == 0); } + + public boolean isAncestorOf(Position another) { + if (another.orders.size() < this.orders.size()) return false; + for (int i = 0; i < orders.size(); i++) { + if (this.orders.get(i) != another.orders.get(i)) return false; + } + return true; + } public Object clone() { return new Position((ArrayList) orders.clone()); diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java index 5a06873..7bae391 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java @@ -1,71 +1,84 @@ package models.algebra; +import java.util.List; + +import models.algebra.Symbol.IImplGenerator; +import models.algebra.Symbol.Type; + public class Symbol { - private String name; - private String implName; - private int arity = 0; // -1: variable number - private Type operatorType = Type.PREFIX; - private Type implOperatorType = Type.PREFIX; - private Symbol[] inverses = null; - private models.algebra.Type[] signature = null; - private int[] implParamOrder = null; - private IImplGenerator generator = null; + protected String name; + protected int arity = 0; // -1: variable number + protected Type operatorType = Type.PREFIX; + protected Symbol[] inverses = null; + protected models.algebra.Type[] signature = null; + protected ICalculator calculator = null; + protected SymbolImpl symbolImpl = null; public Symbol(String name) { this.name = name; - this.implName = name; this.arity = 0; + this.symbolImpl = new SymbolImpl(name); } public Symbol(String name, int arity) { this.name = name; - this.implName = name; this.arity = arity; + this.symbolImpl = new SymbolImpl(name, arity); } public Symbol(String name, int arity, Type operatorType) { - this(name, arity); + this.name = name; + this.arity = arity; this.operatorType = operatorType; - this.implOperatorType = operatorType; + this.symbolImpl = new SymbolImpl(name, arity, operatorType); } public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType) { this.name = name; - this.implName = implName; this.arity = arity; this.operatorType = operatorType; - this.implOperatorType = implOperatorType; + this.symbolImpl = new SymbolImpl(implName, arity, implOperatorType); } public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType, int[] implParamOrder) { - this.name = name; - this.implName = implName; - this.arity = arity; - this.operatorType = operatorType; - this.implOperatorType = implOperatorType; - this.implParamOrder = implParamOrder; + this(name, arity, operatorType, implName, implOperatorType); + this.symbolImpl.setImplParamOrder(implParamOrder); } public Symbol(String name, int arity, Type operatorType, IImplGenerator generator) { - this.name = name; - this.arity = arity; - this.operatorType = operatorType; - this.generator = generator; - this.implOperatorType = Type.GENERATIVE; + this(name, arity, operatorType, name, Type.GENERATIVE); + this.symbolImpl.setGenerator(generator); } public Symbol(String name, int arity, Type operatorType, IImplGenerator generator, boolean bSideEffect) { - this.name = name; - this.arity = arity; - this.operatorType = operatorType; - this.generator = generator; - if (!bSideEffect) { - this.implOperatorType = Type.GENERATIVE; - } else { - this.implOperatorType = Type.GENERATIVE_WITH_SIDE_EFFECT; + this(name, arity, operatorType, name, Type.GENERATIVE); + this.symbolImpl.setGenerator(generator); + if (bSideEffect) { + this.symbolImpl.setImplOperatorType(Type.GENERATIVE_WITH_SIDE_EFFECT); } } + public Symbol(String name, int arity, ICalculator calculator) { + this(name, arity); + this.calculator = calculator; + } + + public Symbol(String name, int arity, Type operatorType, ICalculator calculator) { + this(name, arity, operatorType, name, operatorType); + this.calculator = calculator; + } + + public Symbol(String name, int arity, Type operatorType, IImplGenerator generator, ICalculator calculator) { + this(name, arity, operatorType, name, Type.GENERATIVE); + this.calculator = calculator; + this.symbolImpl.setGenerator(generator); + } + + public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType, ICalculator calculator) { + this(name, arity, operatorType, implName, implOperatorType); + this.calculator = calculator; + } + public void setArity(int arity) { this.arity = arity; } @@ -77,6 +90,11 @@ public String getName() { return name; } + + public void changeName(String name) { + this.name = name; + this.symbolImpl.setImplName(name); + } public Type getOperatorType() { return operatorType; @@ -89,6 +107,10 @@ public boolean isMethod() { return (operatorType == Type.METHOD || operatorType == Type.METHOD_WITH_SIDE_EFFECT); } + + public boolean isLambda() { + return (operatorType == Type.LAMBDA); + } public Symbol[] getInverses() { return inverses; @@ -107,62 +129,74 @@ } public String getImplName() { - return implName; + return symbolImpl.getImplName(); } public void setImplName(String implName) { - this.implName = implName; + this.symbolImpl.setImplName(implName); } public Type getImplOperatorType() { - return implOperatorType; + return symbolImpl.getImplOperatorType(); } public boolean isImplInfix() { - return (implOperatorType == Type.INFIX); + return (symbolImpl.getImplOperatorType() == Type.INFIX); } public boolean isImplMethod() { - return (implOperatorType == Type.METHOD || implOperatorType == Type.METHOD_WITH_SIDE_EFFECT); + return (symbolImpl.getImplOperatorType() == Type.METHOD || symbolImpl.getImplOperatorType() == Type.METHOD_WITH_SIDE_EFFECT); } public boolean isImplLambda() { - return (implOperatorType == Type.LAMBDA || implOperatorType == Type.LAMBDA_WITH_SIDE_EFFECT); + return (symbolImpl.getImplOperatorType() == Type.LAMBDA || symbolImpl.getImplOperatorType() == Type.LAMBDA_WITH_SIDE_EFFECT); } public boolean isImplGenerative() { - return (implOperatorType == Type.GENERATIVE || implOperatorType == Type.GENERATIVE_WITH_SIDE_EFFECT); + return (symbolImpl.getImplOperatorType() == Type.GENERATIVE || symbolImpl.getImplOperatorType() == Type.GENERATIVE_WITH_SIDE_EFFECT); } public boolean isImplWithSideEffect() { - return (implOperatorType == Type.METHOD_WITH_SIDE_EFFECT - || implOperatorType == Type.LAMBDA_WITH_SIDE_EFFECT - || implOperatorType == Type.GENERATIVE_WITH_SIDE_EFFECT); + return (symbolImpl.getImplOperatorType() == Type.METHOD_WITH_SIDE_EFFECT + || symbolImpl.getImplOperatorType() == Type.LAMBDA_WITH_SIDE_EFFECT + || symbolImpl.getImplOperatorType() == Type.GENERATIVE_WITH_SIDE_EFFECT); } public void setImplOperatorType(Type implOperatorType) { - this.implOperatorType = implOperatorType; + this.symbolImpl.setImplOperatorType(implOperatorType); } public int[] getImplParamOrder() { - return implParamOrder; + return symbolImpl.getImplParamOrder(); } public void setGenerator(IImplGenerator generator) { - this.generator = generator; + this.symbolImpl.setGenerator(generator); } /** * Generate the implementation of this symbol * @param type the type of this symbol + * @param childrenTypes * @param childrenImpl the implementations of the children * @param childrenSideEffects (input) an array of the side effects of the children * @param sideEffect (output) an array of the side effect of this symbol * @return the implementation */ - public String generate(models.algebra.Type type, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { - if (generator != null) { - return generator.generate(type, childrenImpl, childrenSideEffects, sideEffect); + public String generate(models.algebra.Type type, models.algebra.Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { + if (symbolImpl.getGenerator() != null) { + return symbolImpl.getGenerator().generate(type, childrenTypes, childrenImpl, childrenSideEffects, sideEffect); + } + return null; + } + + public boolean isCalculatable() { + return (calculator != null); + } + + public Expression calculate(List args) { + if (calculator != null) { + return calculator.calculate(args); } return null; } @@ -182,7 +216,7 @@ } public String toImplementation() { - return implName; + return symbolImpl.getImplName(); } public enum Type { @@ -196,13 +230,78 @@ GENERATIVE_WITH_SIDE_EFFECT } + public static class SymbolImpl { + private String implName; + protected int implArity = 0; // -1: variable number + private Type implOperatorType; + private int[] implParamOrder; + private IImplGenerator generator; + + public SymbolImpl(String implName) { + this.implName = implName; + this.implArity = 0; + } + + public SymbolImpl(String implName, int implArity) { + this.implName = implName; + this.implArity = implArity; + } + + public SymbolImpl(String implName, int implArity, Type implOperatorType) { + this(implName, implArity); + this.implOperatorType = implOperatorType; + } + + public SymbolImpl(String implName, int implArity, Type implOperatorType, int[] implParamOrder) { + this(implName, implArity, implOperatorType); + this.implParamOrder = implParamOrder; + } + + public SymbolImpl(String implName, int implArity, Type implOperatorType, int[] implParamOrder, IImplGenerator generator) { + this(implName, implArity, implOperatorType, implParamOrder); + this.generator = generator; + } + + public String getImplName() { + return implName; + } + + public void setImplName(String implName) { + this.implName = implName; + } + + public Type getImplOperatorType() { + return implOperatorType; + } + + public void setImplOperatorType(Type implOperatorType) { + this.implOperatorType = implOperatorType; + } + + public int[] getImplParamOrder() { + return implParamOrder; + } + + public void setImplParamOrder(int[] implParamOrder) { + this.implParamOrder = implParamOrder; + } + + public IImplGenerator getGenerator() { + return generator; + } + + public void setGenerator(IImplGenerator generator) { + this.generator = generator; + } + } + public Memento createMemento() { - return new Memento(implName, implOperatorType); + return new Memento(symbolImpl.getImplName(), symbolImpl.getImplOperatorType()); } public void setMemento(Memento memento) { - this.implName = memento.implName; - this.implOperatorType = memento.implOperatorType; + this.symbolImpl.setImplName(memento.implName); + this.symbolImpl.setImplOperatorType(memento.implOperatorType); } public static class Memento { @@ -219,11 +318,16 @@ /** * Generate the implementation * @param type the type of this expression + * @param childrenTypes * @param children the implementations of the children * @param childrenSideEffects (input) an array of the side effects of the children * @param sideEffect (output) an array of the side effect of this generator * @return the generated implementation */ - public String generate(models.algebra.Type type, String children[], String[] childrenSideEffects, String[] sideEffect); + public String generate(models.algebra.Type type, models.algebra.Type[] childrenTypes, String children[], String[] childrenSideEffects, String[] sideEffect); + } + + public interface ICalculator { + public Expression calculate(List args); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java index b7cad09..72f71a8 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java @@ -1,25 +1,35 @@ package models.algebra; +import generators.JavaImplementationVisitor; + import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map.Entry; public class Term extends Expression { protected Symbol symbol = null; - protected ArrayList children = new ArrayList<>(); + protected List children = new ArrayList<>(); protected Type type = null; public Term(Symbol symbol) { super(); this.symbol = symbol; } - - public Term(Symbol symbol, ArrayList children) { + + public Term(Symbol symbol, List children) { super(); this.symbol = symbol; this.children = children; } - + + public Term(Symbol symbol, Expression[] children) { + super(); + this.symbol = symbol; + this.children = new ArrayList<>(Arrays.asList(children)); + } + public Symbol getSymbol() { return symbol; } @@ -32,44 +42,62 @@ this.type = type; } - public Type getType() { + public Type getType() { if (type == null) { if (symbol.getSignature() == null) return null; return symbol.getSignature()[0]; } return type; } - + public boolean addChild(Expression child) { if (getArity() != -1 && children.size() >= getArity()) return false; children.add(child); return true; } - + + public boolean setChild(int n, Expression child) { + if (getArity() != -1 && n >= getArity()) return false; + children.set(n, child); + return true; + } + public void addChild(Expression child, boolean bForced) { if (!bForced && getArity() != -1 && children.size() >= getArity()) return; children.add(child); } + public void addChild(int n, Expression child, boolean bForced) { + if (!bForced && getArity() != -1 && children.size() >= getArity()) return; + children.add(n, child); + } + public Expression getChild(int n) { return children.get(n); } - public ArrayList getChildren() { + public List getChildren() { return children; } public HashMap getSubTerms(Class clazz) { HashMap subTerms = new HashMap<>(); - if (clazz == this.getClass()) { - subTerms.put(new Position(), (T) this); + Class thisClass = this.getClass(); + while (thisClass != null) { + if (clazz == thisClass) { + subTerms.put(new Position(), (T) this); + break; + } + thisClass = thisClass.getSuperclass(); } for (int i = 0; i < children.size(); i++) { - HashMap terms = children.get(i).getSubTerms(clazz); - for (Entry term: terms.entrySet()) { - Position pos = term.getKey(); - pos.addHeadOrder(i); - subTerms.put(pos, term.getValue()); + if (children.get(i) != null) { + HashMap terms = children.get(i).getSubTerms(clazz); + for (Entry term : terms.entrySet()) { + Position pos = term.getKey(); + pos.addHeadOrder(i); + subTerms.put(pos, term.getValue()); + } } } return subTerms; @@ -80,13 +108,14 @@ pos = (Position) pos.clone(); int i = pos.removeHeadOrder(); if (i >= children.size()) return null; + if (children.get(i) == null) return null; return children.get(i).getSubTerm(pos); } public Term substitute(Variable variable, Expression value) { Term newTerm = (Term) this.clone(); HashMap variables = getVariables(); - for (Entry varEnt: variables.entrySet()) { + for (Entry varEnt : variables.entrySet()) { if (varEnt.getValue().equals(variable)) { newTerm.replaceSubTerm(varEnt.getKey(), value); } @@ -109,18 +138,87 @@ @Override public Expression unify(Expression another) { if (another instanceof Variable) return (Expression) this.clone(); + if (this instanceof Constant) return (Expression) this.clone(); + if (another instanceof Constant) return (Expression) another.clone(); if (another instanceof Term) { Term anotherTerm = (Term) another; if (!symbol.equals(anotherTerm.symbol)) return null; if (children.size() != anotherTerm.children.size()) return null; Term unifiedTerm = new Term(symbol); for (int i = 0; i < children.size(); i++) { - unifiedTerm.addChild(children.get(i).unify(anotherTerm.children.get(i))); + if (children.get(i) != null) { + unifiedTerm.addChild(children.get(i).unify(anotherTerm.children.get(i))); + } else { + unifiedTerm.addChild(anotherTerm.children.get(i)); + } } return unifiedTerm; } else { return null; - } + } + } + + public Expression reduce() { + if (symbol.isLambda()) { + // Lambda beta-reduction + LambdaAbstraction newSymbol = ((LambdaAbstraction) symbol); + Term newTerm = newSymbol.getTerm(); + List newVariables = newSymbol.getVariables(); + List newChildren = children; + while (newVariables.size() > 0 && newChildren.size() > 0) { + newTerm = newTerm.substitute(newVariables.get(0), newChildren.get(0)); + newVariables = newVariables.subList(1, newVariables.size()); + newChildren = newChildren.subList(1, newChildren.size()); + newSymbol = new LambdaAbstraction(newVariables, newTerm); + } + if (newSymbol.arity == 0 && newChildren.size() == 0) { + return newTerm; + } else { + return new Term(newSymbol, newChildren); + } + } else if (symbol.isCalculatable()) { + List newChildren = new ArrayList<>(); + for (Expression child : children) { + if (child instanceof Term) { + child = ((Term) child).reduce(); + } + newChildren.add(child); + } + Expression newTerm = symbol.calculate(newChildren); + if (newTerm == null) return this; + return newTerm; + } else { + // Calculate inverse map + List newChildren = new ArrayList<>(); + boolean bReduced = false; + for (Expression child : children) { + if (child instanceof Term && !(child instanceof Constant)) { + Expression newChild = ((Term) (child)).reduce(); + if (newChild != child) { + bReduced = true; + child = newChild; + } + } + newChildren.add(child); + } + if (symbol.arity == 1 && newChildren.size() == 1) { + Expression child = newChildren.get(0); + if (child instanceof Term && !(child instanceof Constant)) { + Symbol childSymbol = ((Term) child).getSymbol(); + if (childSymbol.getInverses() != null) { + for (int i = 0; i < childSymbol.getInverses().length; i++) { + if (symbol.equals(childSymbol.getInverses()[i])) { + return ((Term) child).getChild(i); + } + } + } + } + } + if (!bReduced) return this; + Term newTerm = (Term) this.clone(); + newTerm.children = newChildren; + return newTerm; + } } @Override @@ -143,7 +241,7 @@ @Override public boolean contains(Expression exp) { if (equals(exp)) return true; - for (Expression e: children) { + for (Expression e : children) { if (e.contains(exp)) return true; } return false; @@ -174,8 +272,12 @@ @Override public Object clone() { Term newTerm = new Term(symbol); - for (Expression e: children) { - newTerm.addChild((Expression) e.clone()); + for (Expression e : children) { + if (e != null) { + newTerm.addChild((Expression) e.clone()); + } else { + newTerm.addChild(null); + } } newTerm.type = type; return newTerm; @@ -185,7 +287,7 @@ if (getArity() == 2 && symbol.isInfix()) { return "(" + children.get(0) + symbol.toString() + children.get(1) + ")"; } - if (getArity() >= 1 && symbol.isMethod()) { + if ((getArity() >= 1 || getArity() == -1) && symbol.isMethod()) { String exp = children.get(0).toString() + "." + symbol.toString() + "("; String delimiter = ""; for (int i = 1; i < children.size(); i++) { @@ -197,126 +299,24 @@ } else { String exp = symbol.toString() + "("; String delimiter = ""; - for (Expression e: children) { - exp += (delimiter + e.toString()); + for (Expression e : children) { + if (e != null) { + exp += (delimiter + e.toString()); + } else { + exp += (delimiter + "null"); + } delimiter = ","; } return exp + ")"; } } - public String toImplementation(String[] sideEffects) { - int[] implParamOrder = symbol.getImplParamOrder(); - if (symbol.isImplLambda()) { - String[] components = symbol.getImplName().split("->"); - String component0 = components[0].replace("(", "").replace(")", ""); - String[] params = component0.split(","); - String exp = components[1]; - if (implParamOrder == null) { - for (int i = 0; i < params.length; i++) { - exp = exp.replace(params[i], children.get(i).toImplementation(sideEffects)); - } - } else { - for (int i = 0; i < params.length; i++) { - exp = exp.replace(params[i], children.get(implParamOrder[i]).toImplementation(sideEffects)); - } - } - if (symbol.isImplWithSideEffect()) { - sideEffects[0] = sideEffects[0] + exp + ";\n"; - if (implParamOrder == null) { - exp = children.get(0).toImplementation(new String[] {""}); - } else { - exp = children.get(implParamOrder[0]).toImplementation(new String[] {""}); - } - } - return exp; - } - if (symbol.isImplGenerative()) { - String childrenImpl[] = new String[children.size()]; - String childrenSideEffects[] = new String[children.size()]; - if (implParamOrder == null) { - for (int i = 0; i < children.size(); i++) { - String childSideEffect[] = new String[] {""}; - childrenImpl[i] = children.get(i).toImplementation(childSideEffect); - childrenSideEffects[i] = childSideEffect[0]; - } - String exp = symbol.generate(getType(), childrenImpl, childrenSideEffects, sideEffects); - if (symbol.isImplWithSideEffect()) { - sideEffects[0] = sideEffects[0] + exp; - exp = children.get(0).toImplementation(new String[] {""}); // the value of this term - } - return exp; - } else { - for (int i = 0; i < children.size(); i++) { - String childSideEffect[] = new String[] {""}; - childrenImpl[i] = children.get(implParamOrder[i]).toImplementation(childSideEffect); - childrenSideEffects[i] = childSideEffect[0]; - } - String exp = symbol.generate(getType(), childrenImpl, childrenSideEffects, sideEffects); - if (symbol.isImplWithSideEffect()) { - sideEffects[0] = sideEffects[0] + exp; - exp = children.get(implParamOrder[0]).toImplementation(new String[] {""}); // the value of this term - } - return exp; - } - } - if (getArity() == 2 && symbol.isImplInfix()) { - if (implParamOrder == null) { - return "(" + children.get(0).toImplementation(sideEffects) + symbol.toImplementation() + children.get(1).toImplementation(sideEffects) + ")"; - } else { - return "(" + children.get(implParamOrder[0]).toImplementation(sideEffects) + symbol.toImplementation() + children.get(implParamOrder[1]).toImplementation(sideEffects) + ")"; - } - } - if (getArity() >= 1 && symbol.isImplMethod()) { - if (implParamOrder == null) { - String exp = children.get(0).toImplementation(sideEffects) + "." + symbol.toImplementation() + "("; - String delimiter = ""; - for (int i = 1; i < children.size(); i++) { - Expression e = children.get(i); - exp += (delimiter + e.toImplementation(sideEffects)); - delimiter = ","; - } - exp += ")"; - if (symbol.isImplWithSideEffect()) { - sideEffects[0] = sideEffects[0] + exp + ";\n"; - exp = children.get(0).toImplementation(new String[] {""}); - } - return exp; - } else { - String exp = children.get(implParamOrder[0]).toImplementation(sideEffects) + "." + symbol.toImplementation() + "("; - String delimiter = ""; - for (int i = 1; i < children.size(); i++) { - Expression e = children.get(implParamOrder[i]); - exp += (delimiter + e.toImplementation(sideEffects)); - delimiter = ","; - } - exp += ")"; - if (symbol.isImplWithSideEffect()) { - sideEffects[0] = sideEffects[0] + exp + ";\n"; - exp = children.get(implParamOrder[0]).toImplementation(new String[] {""}); - } - return exp; - } - } else { - if (implParamOrder == null) { - String exp = symbol.toImplementation() + "("; - String delimiter = ""; - for (Expression e: children) { - exp += (delimiter + e.toImplementation(sideEffects)); - delimiter = ","; - } - return exp + ")"; - } else { - String exp = symbol.toImplementation() + "("; - String delimiter = ""; - for (int i = 0; i < children.size(); i++) { - Expression e = children.get(implParamOrder[i]); - exp += (delimiter + e.toImplementation(sideEffects)); - delimiter = ","; - } - return exp + ")"; - } - } + return accept(new JavaImplementationVisitor(), sideEffects); + } + + @Override + public String accept(IExpressionVisitor visitor, String[] sideEffects) { + return visitor.visit(this, sideEffects); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java index 50b0285..d2c1780 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java @@ -5,33 +5,35 @@ public class Type { private String typeName; - private String implementationTypeName; - private String interfaceTypeName; +// private String implementationTypeName; +// private String interfaceTypeName; private List parentTypes = new ArrayList<>(); + private ITypeImpl implementationType; + private ITypeImpl interfaceType; - public Type(String typeName, String implementastionTypeName) { + public Type(String typeName, ITypeImpl implementationType) { this.typeName = typeName; - this.implementationTypeName = implementastionTypeName; - this.interfaceTypeName = implementastionTypeName; + this.implementationType = implementationType; + this.interfaceType = implementationType; } - public Type(String typeName, String implementastionTypeName, String interfaceTypeName) { + public Type(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType) { this.typeName = typeName; - this.implementationTypeName = implementastionTypeName; - this.interfaceTypeName = interfaceTypeName; + this.implementationType = implementationType; + this.interfaceType = interfaceType; } - public Type(String typeName, String implementastionTypeName, Type parentType) { + public Type(String typeName, ITypeImpl implementationType, Type parentType) { this.typeName = typeName; - this.implementationTypeName = implementastionTypeName; - this.interfaceTypeName = implementastionTypeName; + this.implementationType = implementationType; + this.interfaceType = implementationType; this.parentTypes.add(parentType); } - public Type(String typeName, String implementastionTypeName, String interfaceTypeName, Type parentType) { + public Type(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentType) { this.typeName = typeName; - this.implementationTypeName = implementastionTypeName; - this.interfaceTypeName = interfaceTypeName; + this.implementationType = implementationType; + this.interfaceType = interfaceType; this.parentTypes.add(parentType); } @@ -43,20 +45,20 @@ this.typeName = typeName; } - public String getImplementationTypeName() { - return implementationTypeName; + public ITypeImpl getImplementationType() { + return implementationType; } - public void setImplementationTypeName(String implementastionTypeName) { - this.implementationTypeName = implementastionTypeName; + public String getImplementationTypeName() { + return implementationType.toString(); + } + + public ITypeImpl getInterfaceType() { + return interfaceType; } public String getInterfaceTypeName() { - return interfaceTypeName; - } - - public void setInterfaceTypeName(String interfaceTypeName) { - this.interfaceTypeName = interfaceTypeName; + return interfaceType.toString(); } public List getParentTypes() { @@ -73,31 +75,54 @@ public boolean isAncestorOf(Type another) { if (this.equals(another)) return true; - if (another.getParentTypes() == null) return false; + if (another == null || another.getParentTypes() == null) return false; for (Type anothersParentType: another.getParentTypes()) { if (isAncestorOf(anothersParentType)) return true; } return false; } + + public String valueToRepresentation(Object value) { + if (value instanceof String) return (String) value; + return value.toString(); + } + + public Object representationToValue(String representation) { + return representation; + } + + @Override + public boolean equals(Object another) { + if (this == another) return true; + if (another == null) return false; + if (!(another instanceof Type)) return false; + if (!typeName.equals(((Type) another).typeName)) return false; + if (!implementationType.equals(((Type) another).implementationType)) return false; + if (!interfaceType.equals(((Type) another).interfaceType)) return false; + return true; + } + + public interface ITypeImpl { + } public Memento createMemento() { - return new Memento(implementationTypeName, interfaceTypeName, parentTypes); + return new Memento(implementationType, interfaceType, parentTypes); } public void setMemento(Memento memento) { - this.implementationTypeName = memento.implementationTypeName; - this.interfaceTypeName = memento.interfaceTypeName; + this.implementationType = memento.implementationType; + this.interfaceType = memento.interfaceType; this.parentTypes = memento.parentTypes; } public static class Memento { - private String implementationTypeName; - private String interfaceTypeName; + private ITypeImpl implementationType; + private ITypeImpl interfaceType; private List parentTypes; - public Memento(String implementationTypeName, String interfaceTypeName, List parentTypes) { - this.implementationTypeName = implementationTypeName; - this.interfaceTypeName = interfaceTypeName; + public Memento(ITypeImpl implementationType, ITypeImpl interfaceType, List parentTypes) { + this.implementationType = implementationType; + this.interfaceType = interfaceType; this.parentTypes = parentTypes; } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Variable.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Variable.java index fa0095b..336a87f 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Variable.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Variable.java @@ -1,5 +1,7 @@ package models.algebra; +import generators.JavaImplementationVisitor; + import java.util.HashMap; public class Variable extends Expression { @@ -10,13 +12,13 @@ super(); this.name = name; } - + public Variable(String name, Type type) { super(); this.name = name; this.type = type; } - + public String getName() { return name; } @@ -24,11 +26,11 @@ public Type getType() { return type; } - + public void setType(Type type) { this.type = type; } - + @Override public HashMap getSubTerms(Class clazz) { HashMap subTerms = new HashMap<>(); @@ -48,18 +50,18 @@ public Expression unify(Expression another) { return (Expression) another.clone(); } - + @Override public Expression getInverseMap(Expression outputValue, Position targetPos) { if (targetPos.isEmpty()) return outputValue; return null; } - + @Override public boolean contains(Expression exp) { return equals(exp); } - + @Override public boolean equals(Object another) { if (!(another instanceof Variable)) return false; @@ -82,6 +84,11 @@ } public String toImplementation(String[] sideEffects) { - return name; + return accept(new JavaImplementationVisitor(), sideEffects); + } + + @Override + public String accept(IExpressionVisitor visitor, String[] sideEffects) { + return visitor.visit(this, sideEffects); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Channel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Channel.java index 8bf74da..2bec47e 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Channel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Channel.java @@ -1,25 +1,44 @@ package models.dataConstraintModel; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; +import models.algebra.Expression; import models.algebra.Variable; public class Channel { protected String channelName; - protected Set selectors = null; + protected Channel parent = null; + protected List children = null; + protected List selectors = null; protected Set channelMembers = null; protected String sourceText = null; + protected boolean isNative = false; public Channel(String channelName) { this.channelName = channelName; - selectors = new HashSet<>(); + this.parent = null; + this.children = new ArrayList<>(); + selectors = new ArrayList<>(); channelMembers = new HashSet<>(); } - public Channel(String channelName, Set variables) { + public Channel(String channelName, Variable variable) { this.channelName = channelName; - selectors = new HashSet<>(); + this.parent = null; + this.children = new ArrayList<>(); + selectors = new ArrayList<>(); + selectors.add(new Selector(variable)); + channelMembers = new HashSet<>(); + } + + public Channel(String channelName, List variables) { + this.channelName = channelName; + this.parent = null; + this.children = new ArrayList<>(); + selectors = new ArrayList<>(); for (Variable var: variables) { selectors.add(new Selector(var)); } @@ -30,17 +49,51 @@ return channelName; } - public Set getChannelSelectors() { + public Channel getParent() { + return parent; + } + + public List getChildren() { + return children; + } + + public void addChild(Channel child) { + children.add(child); + child.parent = this; + child.refleshOutside(); + } + + public List getSelectors() { return selectors; } - public void setChannelSelectors(Set selectors) { + public List getAllSelectors() { + List allSelectors = new ArrayList<>(); + if (parent != null) allSelectors.addAll(parent.getAllSelectors()); + allSelectors.addAll(selectors); + return allSelectors; + } + + public void setSelectors(List selectors) { this.selectors = selectors; } + public void addSelector(Variable var) { + selectors.add(new Selector(var)); + } + public void addSelector(Selector selector) { selectors.add(selector); } + + public List getAllSelectorVariables() { + List allSelectorVariables = new ArrayList<>(); + if (parent != null) allSelectorVariables.addAll(parent.getAllSelectorVariables()); + for (Selector sel: selectors) { + allSelectorVariables.add(sel.getExpression()); + } + return allSelectorVariables; + } public Set getChannelMembers() { return channelMembers; @@ -48,23 +101,55 @@ public void setChannelMembers(Set channelMembers) { this.channelMembers = channelMembers; - for (ChannelMember channelMember: channelMembers) { - for (Selector selector: channelMember.getSelectors()) { - addSelector(selector); - } - } } public void addChannelMember(ChannelMember channelMember) { channelMembers.add(channelMember); - for (Selector selector: channelMember.getSelectors()) { - addSelector(selector); + if (getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: getAllSelectors()) { + params.add(s.getExpression()); + } + if (!params.containsAll(channelMember.getResource().getPathParams())) { + channelMember.setOutside(true); + } + } else { + if (channelMember.getResource().getPathParams().size() == 0) { + channelMember.setOutside(false); + } else { + channelMember.setOutside(true); + } + } + if (isNative) { + channelMember.getResource().getResourceHierarchy().setNative(true); } } - public void removeChannelMember(ResourcePath id) { + public void refleshOutside() { + for (ChannelMember channelMember: channelMembers) { + if (getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: getAllSelectors()) { + params.add(s.getExpression()); + } + if (!params.containsAll(channelMember.getResource().getPathParams())) { + channelMember.setOutside(true); + } else { + channelMember.setOutside(false); + } + } else { + if (channelMember.getResource().getPathParams().size() == 0) { + channelMember.setOutside(false); + } else { + channelMember.setOutside(true); + } + } + } + } + + public void removeChannelMember(ResourcePath res) { for (ChannelMember cm: channelMembers) { - if (cm.getResource() == id) { + if (cm.getResource() == res) { channelMembers.remove(cm); break; } @@ -78,6 +163,17 @@ } return resources; } + + public boolean isNative() { + return isNative; + } + + public void setNative(boolean isNative) { + this.isNative = isNative; + for (ChannelMember member: channelMembers) { + member.getResource().getResourceHierarchy().setNative(isNative); + } + } public String toString() { return channelName; diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelMember.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelMember.java index 190a49f..370c3f7 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelMember.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelMember.java @@ -5,13 +5,13 @@ public class ChannelMember { private ResourcePath resourcePath = null; - private List selectors = null; private StateTransition stateTransition = null; + private boolean isOutside = false; public ChannelMember(ResourcePath resourcePath) { this.resourcePath = resourcePath; - selectors = new ArrayList<>(); stateTransition = new StateTransition(); + isOutside = false; } public ResourcePath getResource() { @@ -22,19 +22,6 @@ this.resourcePath = resourcePath; } - public List getSelectors() { - return selectors; - } - - public void setSelectors(List selectors) { - this.selectors = selectors; - } - - public ChannelMember addSelector(Selector selector) { - selectors.add(selector); - return this; - } - public StateTransition getStateTransition() { return stateTransition; } @@ -43,16 +30,24 @@ this.stateTransition = stateTransition; } + public boolean isOutside() { + return this.isOutside; + } + + public void setOutside(boolean isOutside) { + this.isOutside = isOutside; + } + @Override public String toString() { if (stateTransition.getNextStateExpression() == null) { - return resourcePath.getResourceName() + "(" + return resourcePath.toString() + "(" + stateTransition.getCurStateExpression() + "," + stateTransition.getMessageExpression() + ")"; } - return resourcePath.getResourceName() + "(" + return resourcePath.toString() + "(" + stateTransition.getCurStateExpression() + "," + stateTransition.getMessageExpression() + ")" - + " == " + stateTransition.getNextStateExpression(); + + " = " + stateTransition.getNextStateExpression(); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index 35b2aa7..33be5cc 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java @@ -1,48 +1,866 @@ package models.dataConstraintModel; +import java.util.AbstractMap; +import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Stack; +import generators.JavaSpecific; +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.LambdaAbstraction; import models.algebra.Symbol; +import models.algebra.Term; import models.algebra.Type; +import models.algebra.Variable; import parser.Parser; public class DataConstraintModel { - protected HashMap resourcePaths = null; + protected List resourcePaths = null; + protected HashMap resourceHierarchies = null; protected HashMap channels = null; - protected HashMap ioChannels = null; + protected HashMap inputChannels = null; protected HashMap types = null; protected HashMap symbols = null; - public static final Type typeInt = new Type("Int", "int"); - public static final Type typeLong = new Type("Long", "long", typeInt); - public static final Type typeFloat = new Type("Float", "float", typeInt); - public static final Type typeDouble = new Type("Double", "double", typeFloat); - public static final Type typeBoolean = new Type("Bool", "boolean"); - public static final Type typeString = new Type("Str", "String"); - public static final Type typeList = new Type("List", "ArrayList", "List"); - public static final Type typeListInt = new Type("List", "ArrayList<>", "List", typeList); - public static final Type typeListStr = new Type("List", "ArrayList<>", "List", typeList); - public static final Type typeTuple = new Type("Tuple", "AbstractMap.SimpleEntry", "Map.Entry"); - public static final Type typePair = new Type("Pair", "Pair", "Pair"); - public static final Type typePairInt = new Type("Pair", "Pair", "Pair", typePair); - public static final Type typePairStr = new Type("Pair", "Pair", "Pair", typePair); - public static final Type typePairDouble = new Type("Pair", "Pair", "Pair", typePair); - public static final Type typeMap = new Type("Map", "HashMap", "Map"); - public static final Symbol add = new Symbol(Parser.ADD, 2, Symbol.Type.INFIX); - public static final Symbol mul = new Symbol(Parser.MUL, 2, Symbol.Type.INFIX);; - public static final Symbol sub = new Symbol(Parser.SUB, 2, Symbol.Type.INFIX); - public static final Symbol div = new Symbol(Parser.DIV, 2, Symbol.Type.INFIX); - public static final Symbol minus = new Symbol(Parser.MINUS, 1); + public static final Type typeInt = new Type("Int", new code.ast.PrimitiveType("int")); + public static final Type typeLong = new Type("Long", new code.ast.PrimitiveType("long"), typeInt); + public static final Type typeFloat = new Type("Float", new code.ast.PrimitiveType("float"), typeInt); + public static final Type typeDouble = new Type("Double", new code.ast.PrimitiveType("double"), typeFloat); + public static final Type typeBoolean = new Type("Bool", new code.ast.PrimitiveType("boolean")); + public static final Type typeString = new Type("Str", JavaSpecific.typeString) { + public String valueToRepresentation(Object value) { + if (value instanceof String) { + return Parser.DOUBLE_QUOT + (String) value + Parser.DOUBLE_QUOT; + } + return value.toString(); + } + public Object representationToValue(String representation) { + if (representation.startsWith(Parser.DOUBLE_QUOT) && representation.endsWith(Parser.DOUBLE_QUOT)) { + return representation.substring(1, representation.length() - 1); + } + return representation; + } + }; + public static final Type typeList = new Type("List", JavaSpecific.typeArrayList, JavaSpecific.typeList); + public static final Type typeListInt = new Type("List", new code.ast.ParameterizedType(JavaSpecific.typeArrayList), new code.ast.ParameterizedType(JavaSpecific.typeList, List.of(JavaSpecific.typeInteger)), typeList); + public static final Type typeListStr = new Type("List", new code.ast.ParameterizedType(JavaSpecific.typeArrayList), new code.ast.ParameterizedType(JavaSpecific.typeList, List.of(JavaSpecific.typeString)), typeList); + public static final Type typeTuple = new Type("Tuple", new code.ast.SimpleType("AbstractMap.SimpleEntry"), new code.ast.SimpleType("Map.Entry")); + public static final Type typePair = new Type("Pair", new code.ast.SimpleType("Pair"), new code.ast.SimpleType("Pair")); + public static final Type typePairInt = new Type("Pair", new code.ast.ParameterizedType(JavaSpecific.typePair), new code.ast.ParameterizedType(JavaSpecific.typePair, List.of(JavaSpecific.typeInteger)), typePair); + public static final Type typePairStr = new Type("Pair", new code.ast.ParameterizedType(JavaSpecific.typePair), new code.ast.ParameterizedType(JavaSpecific.typePair, List.of(JavaSpecific.typeString)), typePair); + public static final Type typePairDouble = new Type("Pair", new code.ast.ParameterizedType(JavaSpecific.typePair), new code.ast.ParameterizedType(JavaSpecific.typePair, List.of(JavaSpecific.typeDouble)), typePair); + public static final Type typeMap = new Type("Map", new code.ast.ParameterizedType(JavaSpecific.typeHashMap), JavaSpecific.typeMap); + public static final JsonType typeJson = new JsonType("Json", new code.ast.ParameterizedType(JavaSpecific.typeHashMap), new code.ast.ParameterizedType(JavaSpecific.typeMap, List.of(JavaSpecific.typeString, JavaSpecific.typeObject))); + public static final Symbol add = new Symbol(Parser.ADD, 2, Symbol.Type.INFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + if (!(args.get(1).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + Constant arg1 = (Constant) args.get(1); + String sArg0 = arg0.getSymbol().toString(); + String sArg1 = arg1.getSymbol().toString(); + if (arg0.getType() != null && arg1.getType() != null) { + if (arg0.getType().equals(typeDouble) || arg1.getType().equals(typeDouble)) { + return new Constant(Double.toString(Double.parseDouble(sArg0) + Double.parseDouble(sArg1)), typeDouble); + } else if (arg0.getType().equals(typeFloat) || arg1.getType().equals(typeFloat)) { + return new Constant(Float.toString(Float.parseFloat(sArg0) + Float.parseFloat(sArg1)), typeFloat); + } else if (arg0.getType().equals(typeLong) || arg1.getType().equals(typeLong)) { + return new Constant(Long.toString(Long.parseLong(sArg0) + Long.parseLong(sArg1)), typeLong); + } else if (arg0.getType().equals(typeInt) || arg1.getType().equals(typeInt)) { + return new Constant(Integer.toString(Integer.parseInt(sArg0) + Integer.parseInt(sArg1)), typeInt); + } else if (arg0.getType().equals(typeString) || arg1.getType().equals(typeString)) { + return new Constant((String) arg0.getValue() + (String) arg1.getValue(), typeString); + } + } + if (sArg0.contains(Parser.DOT) || sArg1.contains(Parser.DOT)) { + return new Constant(Double.toString(Double.parseDouble(sArg0) + Double.parseDouble(sArg1)), typeDouble); + } else { + return new Constant(Integer.toString(Integer.parseInt(sArg0) + Integer.parseInt(sArg1)), typeInt); + } + } + }); + public static final Symbol mul = new Symbol(Parser.MUL, 2, Symbol.Type.INFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + if (!(args.get(1).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + Constant arg1 = (Constant) args.get(1); + String sArg0 = arg0.getSymbol().toString(); + String sArg1 = arg1.getSymbol().toString(); + if (arg0.getType() != null && arg1.getType() != null) { + if (arg0.getType().equals(typeDouble) || arg1.getType().equals(typeDouble)) { + return new Constant(Double.toString(Double.parseDouble(sArg0) * Double.parseDouble(sArg1)), typeDouble); + } else if (arg0.getType().equals(typeFloat) || arg1.getType().equals(typeFloat)) { + return new Constant(Float.toString(Float.parseFloat(sArg0) * Float.parseFloat(sArg1)), typeFloat); + } else if (arg0.getType().equals(typeLong) || arg1.getType().equals(typeLong)) { + return new Constant(Long.toString(Long.parseLong(sArg0) * Long.parseLong(sArg1)), typeLong); + } else if (arg0.getType().equals(typeInt) || arg1.getType().equals(typeInt)) { + return new Constant(Integer.toString(Integer.parseInt(sArg0) * Integer.parseInt(sArg1)), typeInt); + } + } + if (sArg0.contains(Parser.DOT) || sArg1.contains(Parser.DOT)) { + return new Constant(Double.toString(Double.parseDouble(sArg0) * Double.parseDouble(sArg1)), typeDouble); + } else { + return new Constant(Integer.toString(Integer.parseInt(sArg0) * Integer.parseInt(sArg1)), typeInt); + } + } + }); + public static final Symbol sub = new Symbol(Parser.SUB, 2, Symbol.Type.INFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + if (!(args.get(1).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + Constant arg1 = (Constant) args.get(1); + String sArg0 = arg0.getSymbol().toString(); + String sArg1 = arg1.getSymbol().toString(); + if (arg0.getType() != null && arg1.getType() != null) { + if (arg0.getType().equals(typeDouble) || arg1.getType().equals(typeDouble)) { + return new Constant(Double.toString(Double.parseDouble(sArg0) - Double.parseDouble(sArg1)), typeDouble); + } else if (arg0.getType().equals(typeFloat) || arg1.getType().equals(typeFloat)) { + return new Constant(Float.toString(Float.parseFloat(sArg0) - Float.parseFloat(sArg1)), typeFloat); + } else if (arg0.getType().equals(typeLong) || arg1.getType().equals(typeLong)) { + return new Constant(Long.toString(Long.parseLong(sArg0) - Long.parseLong(sArg1)), typeLong); + } else if (arg0.getType().equals(typeInt) || arg1.getType().equals(typeInt)) { + return new Constant(Integer.toString(Integer.parseInt(sArg0) - Integer.parseInt(sArg1)), typeInt); + } + } + if (sArg0.contains(Parser.DOT) || sArg1.contains(Parser.DOT)) { + return new Constant(Double.toString(Double.parseDouble(sArg0) - Double.parseDouble(sArg1)), typeDouble); + } else { + return new Constant(Integer.toString(Integer.parseInt(sArg0) - Integer.parseInt(sArg1)), typeInt); + } + } + }); + public static final Symbol div = new Symbol(Parser.DIV, 2, Symbol.Type.INFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + if (!(args.get(1).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + Constant arg1 = (Constant) args.get(1); + String sArg0 = arg0.getSymbol().toString(); + String sArg1 = arg1.getSymbol().toString(); + if (arg0.getType() != null && arg1.getType() != null) { + if (arg0.getType().equals(typeDouble) || arg1.getType().equals(typeDouble)) { + return new Constant(Double.toString(Double.parseDouble(sArg0) / Double.parseDouble(sArg1)), typeDouble); + } else if (arg0.getType().equals(typeFloat) || arg1.getType().equals(typeFloat)) { + return new Constant(Float.toString(Float.parseFloat(sArg0) / Float.parseFloat(sArg1)), typeFloat); + } else if (arg0.getType().equals(typeLong) || arg1.getType().equals(typeLong)) { + return new Constant(Long.toString(Long.parseLong(sArg0) / Long.parseLong(sArg1)), typeLong); + } else if (arg0.getType().equals(typeInt) || arg1.getType().equals(typeInt)) { + return new Constant(Integer.toString(Integer.parseInt(sArg0) / Integer.parseInt(sArg1)), typeInt); + } + } + if (sArg0.contains(Parser.DOT) || sArg1.contains(Parser.DOT)) { + return new Constant(Double.toString(Double.parseDouble(sArg0) / Double.parseDouble(sArg1)), typeDouble); + } else { + return new Constant(Integer.toString(Integer.parseInt(sArg0) / Integer.parseInt(sArg1)), typeInt); + } + } + }); + public static final Symbol mod = new Symbol(Parser.MOD, 2, Symbol.Type.INFIX, "%", Symbol.Type.INFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + if (!(args.get(1).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + Constant arg1 = (Constant) args.get(1); + String sArg0 = arg0.getSymbol().toString(); + String sArg1 = arg1.getSymbol().toString(); + if (arg0.getType() != null && arg1.getType() != null) { + if (arg0.getType().equals(typeLong) || arg1.getType().equals(typeLong)) { + return new Constant(Long.toString(Long.parseLong(sArg0) % Long.parseLong(sArg1)), typeLong); + } else if (arg0.getType().equals(typeInt) || arg1.getType().equals(typeInt)) { + return new Constant(Integer.toString(Integer.parseInt(sArg0) % Integer.parseInt(sArg1)), typeInt); + } + } + return new Constant(Integer.toString(Integer.parseInt(sArg0) % Integer.parseInt(sArg1))); + } + }); + public static final Symbol minus = new Symbol(Parser.MINUS, 1, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + Constant arg = (Constant) args.get(0); + String sArg = arg.getSymbol().toString(); + if (arg.getType() != null) { + if (arg.getType().equals(typeDouble)) { + return new Constant(Double.toString(-Double.parseDouble(sArg)), typeDouble); + } else if (arg.getType().equals(typeFloat)) { + return new Constant(Float.toString(-Float.parseFloat(sArg)), typeFloat); + } else if (arg.getType().equals(typeLong)) { + return new Constant(Long.toString(-Long.parseLong(sArg)), typeLong); + } else if (arg.getType().equals(typeInt)) { + return new Constant(Integer.toString(-Integer.parseInt(sArg)), typeInt); + } + } + if (sArg.contains(Parser.DOT)) { + return new Constant(Double.toString(-Double.parseDouble(sArg)), typeDouble); + } else { + return new Constant(Integer.toString(-Integer.parseInt(sArg)), typeInt); + } + } + }); + public static final Symbol eq = new Symbol(Parser.EQ, 2, Symbol.Type.INFIX, new Symbol.IImplGenerator() { + @Override + public String generate(Type type, Type[] childrenTypes, String[] children, String[] childrenSideEffects, String[] sideEffect) { + for (String s: childrenSideEffects) { + sideEffect[0] += s; + } + if (childrenTypes[0] != null && childrenTypes[0].equals(typeString) + && childrenTypes[1] != null && childrenTypes[1].equals(typeString)) { + return children[0] + ".equals(" + children[1] + ")"; + } + return "(" + children[0] + "==" + children[1] + ")"; + } + }, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + if (!(args.get(1).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + Constant arg1 = (Constant) args.get(1); + String sArg0 = arg0.getSymbol().toString(); + String sArg1 = arg1.getSymbol().toString(); + boolean result = false; + if (arg0.getType() == null || arg1.getType() == null) { + if (sArg0.contains(Parser.DOT) || sArg1.contains(Parser.DOT)) { + result = Double.parseDouble(sArg0) == Double.parseDouble(sArg1); + } else { + result = Integer.parseInt(sArg0) == Integer.parseInt(sArg1); + } + } + if (arg0.getType().equals(typeDouble) || arg1.getType().equals(typeDouble)) { + result = (Double.parseDouble(sArg0) == Double.parseDouble(sArg1)); + } else if (arg0.getType().equals(typeFloat) || arg1.getType().equals(typeFloat)) { + result = (Float.parseFloat(sArg0) == Float.parseFloat(sArg1)); + } else if (arg0.getType().equals(typeLong) || arg1.getType().equals(typeLong)) { + result = (Long.parseLong(sArg0) == Long.parseLong(sArg1)); + } else if (arg0.getType().equals(typeInt) || arg1.getType().equals(typeInt)) { + result = (Integer.parseInt(sArg0) == Integer.parseInt(sArg1)); + } else if (arg0.getType().equals(typeString) || arg1.getType().equals(typeString)) { + result = sArg0.toString().equals(sArg1.toString()); + } + if (result) { + return new Constant(true_); + } else { + return new Constant(false_); + } + } + }); + public static final Symbol neq = new Symbol(Parser.NEQ, 2, Symbol.Type.INFIX, new Symbol.IImplGenerator() { + @Override + public String generate(Type type, Type[] childrenTypes, String[] children, String[] childrenSideEffects, String[] sideEffect) { + for (String s: childrenSideEffects) { + sideEffect[0] += s; + } + if (childrenTypes[0] != null && childrenTypes[0].equals(typeString) + && childrenTypes[1] != null && childrenTypes[1].equals(typeString)) { + return "!" + children[0] + ".equals(" + children[1] + ")"; + } + return "(" + children[0] + "!=" + children[1] + ")"; + } + }, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + if (!(args.get(1).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + Constant arg1 = (Constant) args.get(1); + String sArg0 = arg0.getSymbol().toString(); + String sArg1 = arg1.getSymbol().toString(); + boolean result = false; + if (arg0.getType() == null || arg1.getType() == null) { + if (sArg0.contains(Parser.DOT) || sArg1.contains(Parser.DOT)) { + result = Double.parseDouble(sArg0) != Double.parseDouble(sArg1); + } else { + result = Integer.parseInt(sArg0) != Integer.parseInt(sArg1); + } + } + if (arg0.getType().equals(typeDouble) || arg1.getType().equals(typeDouble)) { + result = (Double.parseDouble(sArg0) != Double.parseDouble(sArg1)); + } else if (arg0.getType().equals(typeFloat) || arg1.getType().equals(typeFloat)) { + result = (Float.parseFloat(sArg0) != Float.parseFloat(sArg1)); + } else if (arg0.getType().equals(typeLong) || arg1.getType().equals(typeLong)) { + result = (Long.parseLong(sArg0) != Long.parseLong(sArg1)); + } else if (arg0.getType().equals(typeInt) || arg1.getType().equals(typeInt)) { + result = (Integer.parseInt(sArg0) != Integer.parseInt(sArg1)); + } else if (arg0.getType().equals(typeString) || arg1.getType().equals(typeString)) { + result = !(sArg0.toString().equals(sArg1.toString())); + } + if (result) { + return new Constant(true_); + } else { + return new Constant(false_); + } + } + }); + public static final Symbol gt = new Symbol(Parser.GT, 2, Symbol.Type.INFIX, ">", Symbol.Type.INFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + if (!(args.get(1).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + Constant arg1 = (Constant) args.get(1); + String sArg0 = arg0.getSymbol().toString(); + String sArg1 = arg1.getSymbol().toString(); + boolean result = false; + if (arg0.getType() == null || arg1.getType() == null) { + if (sArg0.contains(Parser.DOT) || sArg1.contains(Parser.DOT)) { + result = Double.parseDouble(sArg0) > Double.parseDouble(sArg1); + } else { + result = Integer.parseInt(sArg0) > Integer.parseInt(sArg1); + } + } + if (arg0.getType().equals(typeDouble) || arg1.getType().equals(typeDouble)) { + result = (Double.parseDouble(sArg0) > Double.parseDouble(sArg1)); + } else if (arg0.getType().equals(typeFloat) || arg1.getType().equals(typeFloat)) { + result = (Float.parseFloat(sArg0) > Float.parseFloat(sArg1)); + } else if (arg0.getType().equals(typeLong) || arg1.getType().equals(typeLong)) { + result = (Long.parseLong(sArg0) > Long.parseLong(sArg1)); + } else if (arg0.getType().equals(typeInt) || arg1.getType().equals(typeInt)) { + result = (Integer.parseInt(sArg0) > Integer.parseInt(sArg1)); + } + if (result) { + return new Constant(true_); + } else { + return new Constant(false_); + } + } + }); + public static final Symbol lt = new Symbol(Parser.LT, 2, Symbol.Type.INFIX, "<", Symbol.Type.INFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + if (!(args.get(1).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + Constant arg1 = (Constant) args.get(1); + String sArg0 = arg0.getSymbol().toString(); + String sArg1 = arg1.getSymbol().toString(); + boolean result = false; + if (arg0.getType() == null || arg1.getType() == null) { + if (sArg0.contains(Parser.DOT) || sArg1.contains(Parser.DOT)) { + result = Double.parseDouble(sArg0) < Double.parseDouble(sArg1); + } else { + result = Integer.parseInt(sArg0) < Integer.parseInt(sArg1); + } + } + if (arg0.getType().equals(typeDouble) || arg1.getType().equals(typeDouble)) { + result = (Double.parseDouble(sArg0) < Double.parseDouble(sArg1)); + } else if (arg0.getType().equals(typeFloat) || arg1.getType().equals(typeFloat)) { + result = (Float.parseFloat(sArg0) < Float.parseFloat(sArg1)); + } else if (arg0.getType().equals(typeLong) || arg1.getType().equals(typeLong)) { + result = (Long.parseLong(sArg0) < Long.parseLong(sArg1)); + } else if (arg0.getType().equals(typeInt) || arg1.getType().equals(typeInt)) { + result = (Integer.parseInt(sArg0) < Integer.parseInt(sArg1)); + } + if (result) { + return new Constant(true_); + } else { + return new Constant(false_); + } + } + }); + public static final Symbol ge = new Symbol(Parser.GE, 2, Symbol.Type.INFIX, ">=", Symbol.Type.INFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + if (!(args.get(1).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + Constant arg1 = (Constant) args.get(1); + String sArg0 = arg0.getSymbol().toString(); + String sArg1 = arg1.getSymbol().toString(); + boolean result = false; + if (arg0.getType() == null || arg1.getType() == null) { + if (sArg0.contains(Parser.DOT) || sArg1.contains(Parser.DOT)) { + result = Double.parseDouble(sArg0) >= Double.parseDouble(sArg1); + } else { + result = Integer.parseInt(sArg0) >= Integer.parseInt(sArg1); + } + } + if (arg0.getType().equals(typeDouble) || arg1.getType().equals(typeDouble)) { + result = (Double.parseDouble(sArg0) >= Double.parseDouble(sArg1)); + } else if (arg0.getType().equals(typeFloat) || arg1.getType().equals(typeFloat)) { + result = (Float.parseFloat(sArg0) >= Float.parseFloat(sArg1)); + } else if (arg0.getType().equals(typeLong) || arg1.getType().equals(typeLong)) { + result = (Long.parseLong(sArg0) >= Long.parseLong(sArg1)); + } else if (arg0.getType().equals(typeInt) || arg1.getType().equals(typeInt)) { + result = (Integer.parseInt(sArg0) >= Integer.parseInt(sArg1)); + } + if (result) { + return new Constant(true_); + } else { + return new Constant(false_); + } + } + }); + public static final Symbol le = new Symbol(Parser.LE, 2, Symbol.Type.INFIX, "<=", Symbol.Type.INFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + if (!(args.get(1).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + Constant arg1 = (Constant) args.get(1); + String sArg0 = arg0.getSymbol().toString(); + String sArg1 = arg1.getSymbol().toString(); + boolean result = false; + if (arg0.getType() == null || arg1.getType() == null) { + if (sArg0.contains(Parser.DOT) || sArg1.contains(Parser.DOT)) { + result = Double.parseDouble(sArg0) <= Double.parseDouble(sArg1); + } else { + result = Integer.parseInt(sArg0) <= Integer.parseInt(sArg1); + } + } + if (arg0.getType().equals(typeDouble) || arg1.getType().equals(typeDouble)) { + result = (Double.parseDouble(sArg0) <= Double.parseDouble(sArg1)); + } else if (arg0.getType().equals(typeFloat) || arg1.getType().equals(typeFloat)) { + result = (Float.parseFloat(sArg0) <= Float.parseFloat(sArg1)); + } else if (arg0.getType().equals(typeLong) || arg1.getType().equals(typeLong)) { + result = (Long.parseLong(sArg0) <= Long.parseLong(sArg1)); + } else if (arg0.getType().equals(typeInt) || arg1.getType().equals(typeInt)) { + result = (Integer.parseInt(sArg0) <= Integer.parseInt(sArg1)); + } + if (result) { + return new Constant(true_); + } else { + return new Constant(false_); + } + } + }); + public static final Symbol and = new Symbol(Parser.AND, 2, Symbol.Type.INFIX, "&&", Symbol.Type.INFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + if (!(args.get(1).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + Constant arg1 = (Constant) args.get(1); + String sArg0 = arg0.getSymbol().toString(); + String sArg1 = arg1.getSymbol().toString(); + boolean result = false; + if (arg0.getType() == null || arg1.getType() == null) return null; + if (arg0.getType().equals(typeBoolean) || arg1.getType().equals(typeBoolean)) { + result = (Boolean.parseBoolean(sArg0) && Boolean.parseBoolean(sArg1)); + } + if (result) { + return new Constant(true_); + } else { + return new Constant(false_); + } + } + }); + public static final Symbol or = new Symbol(Parser.OR, 2, Symbol.Type.INFIX, "||", Symbol.Type.INFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + if (!(args.get(1).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + Constant arg1 = (Constant) args.get(1); + String sArg0 = arg0.getSymbol().toString(); + String sArg1 = arg1.getSymbol().toString(); + boolean result = false; + if (arg0.getType() == null || arg1.getType() == null) return null; + if (arg0.getType().equals(typeBoolean) || arg1.getType().equals(typeBoolean)) { + result = (Boolean.parseBoolean(sArg0) || Boolean.parseBoolean(sArg1)); + } + if (result) { + return new Constant(true_); + } else { + return new Constant(false_); + } + } + }); + public static final Symbol neg = new Symbol(Parser.NEG, 1, Symbol.Type.PREFIX, "!", Symbol.Type.PREFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) { + return null; + } + Constant arg0 = (Constant) args.get(0); + String sArg0 = arg0.getSymbol().toString(); + boolean result = false; + if (arg0.getType() == null) return null; + if (arg0.getType().equals(typeBoolean)) { + result = !Boolean.parseBoolean(sArg0); + } + if (result) { + return new Constant(true_); + } else { + return new Constant(false_); + } + } + }); public static final Symbol cons = new Symbol("cons", 2, Symbol.Type.PREFIX, "($x,$y)->$x.add(0, $y)", Symbol.Type.LAMBDA_WITH_SIDE_EFFECT, new int[] {1, 0}); + public static final Symbol append = new Symbol("append", 2, Symbol.Type.PREFIX, "add", Symbol.Type.METHOD_WITH_SIDE_EFFECT); // Don't calculate here (Calculated in simulator). + public static final Symbol remove = new Symbol("remove", 2, Symbol.Type.PREFIX, "remove", Symbol.Type.METHOD_WITH_SIDE_EFFECT); // Don't calculate here (Calculated in simulator). public static final Symbol head = new Symbol("head", 1, Symbol.Type.PREFIX, "($x)->$x.get(0)", Symbol.Type.LAMBDA); public static final Symbol tail = new Symbol("tail", 1, Symbol.Type.PREFIX, "($x)->$x.subList(1, $x.size())", Symbol.Type.LAMBDA); - public static final Symbol length = new Symbol("length", 1, Symbol.Type.PREFIX, "($x)->$x.size()", Symbol.Type.LAMBDA); - public static final Symbol get = new Symbol("get", 2, Symbol.Type.PREFIX, "get", Symbol.Type.METHOD); - public static final Symbol set = new Symbol("set", 3, Symbol.Type.PREFIX, "set", Symbol.Type.METHOD_WITH_SIDE_EFFECT); - public static final Symbol contains = new Symbol("contains", 2, Symbol.Type.PREFIX, "contains", Symbol.Type.METHOD); - public static final Symbol nil = new Symbol("nil", 0, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { + public static final Symbol length = new Symbol("length", 1, Symbol.Type.PREFIX, "($x)->$x.size()", Symbol.Type.LAMBDA, new Symbol.ICalculator() { @Override - public String generate(Type type, String[] children, String[] childrenSideEffects, String[] sideEffect) { + public Expression calculate(List args) { + if (args.get(0).getClass() == Constant.class && ((Constant) args.get(0)).getSymbol().equals(nil)) { + return new Constant("0", typeInt); + } + if (args.get(0) instanceof Term) { + Term term = (Term) args.get(0); + Type type = term.getType(); + if (typeList.isAncestorOf(type)) { + int len = 0; + while (term.getSymbol().equals(DataConstraintModel.append)) { + len++; + term = (Term) term.getChild(0); + } + if (term instanceof ListTerm) { + len += ((ListTerm) term).getChildren().size(); + return new Constant(Integer.toString(len), typeInt); + } + } else if (typeMap.isAncestorOf(type)) { + HashSet keySet = new HashSet<>(); + while (term.getSymbol().equals(DataConstraintModel.insert)) { + if (term.getChild(1).getClass() == Constant.class) { + keySet.add((String) ((Constant) term.getChild(1)).getValue()); + } + term = (Term) term.getChild(0); + } + if (term instanceof MapTerm) { + keySet.addAll(((MapTerm) term).keySet()); + return new Constant(Integer.toString(keySet.size()), typeInt); + } + } else if (typeJson.isAncestorOf(type)) { + HashSet keySet = new HashSet<>(); + while (term.getSymbol().equals(DataConstraintModel.addMember)) { + if (term.getChild(1).getClass() == Constant.class) { + keySet.add((String) ((Constant) term.getChild(1)).getValue()); + } + term = (Term) term.getChild(0); + } + if (term instanceof JsonTerm) { + keySet.addAll(((JsonTerm) term).keySet()); + return new Constant(Integer.toString(keySet.size()), typeInt); + } + } else if (typeString.isAncestorOf(type)) { + int len = 0; + ArrayDeque strTerms = new ArrayDeque<>(); + strTerms.add(term); + while (strTerms.size() > 0) { + term = strTerms.poll(); + type = term.getType(); + if (term.getSymbol().equals(DataConstraintModel.add)) { + strTerms.add((Term) term.getChild(0)); + strTerms.add((Term) term.getChild(1)); + } else if (term instanceof Constant && typeString.isAncestorOf(type)) { + len += ((String) ((Constant) term).getValue()).length(); + } + } + return new Constant(Integer.toString(len), typeInt); + } + } + return null; + } + }); + public static final Symbol get = new Symbol("get", 2, Symbol.Type.PREFIX, "get", Symbol.Type.METHOD, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (args.get(1).getClass() == Constant.class && ((Constant) args.get(1)).getType().equals(typeInt)) { + int idx = Integer.parseInt(((Constant) args.get(1)).toString()); + if (args.get(0) instanceof Term) { + Term term = (Term) args.get(0); + Type type = term.getType(); + if (typeList.isAncestorOf(type)) { + Stack appendedChldren = new Stack<>(); + while (term.getSymbol().equals(DataConstraintModel.append)) { + if (!(term.getChild(0) instanceof Term)) { + return null; + } + appendedChldren.push(term.getChild(1)); + term = (Term) term.getChild(0); + } + if (term instanceof ListTerm) { + ListTerm listTerm = (ListTerm) term.clone(); + for (Expression child: appendedChldren) { + listTerm.append(child); + } + return listTerm.get(idx); + } + } + } + } + return null; + } + }); + public static final Symbol set = new Symbol("set", 3, Symbol.Type.PREFIX, "set", Symbol.Type.METHOD_WITH_SIDE_EFFECT); // Don't calculate here (Calculated in simulator). + public static final Symbol contains = new Symbol("contains", 2, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { + @Override + public String generate(Type type, Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { + for (String s: childrenSideEffects) { + sideEffect[0] += s; + } + if (childrenTypes[0] != null && (typeMap.isAncestorOf(childrenTypes[0]) || typeJson.isAncestorOf(childrenTypes[0]))) { + return childrenImpl[0] + "." + "containsKey(" + childrenImpl[1] + ")"; + } + return childrenImpl[0] + "." + "contains(" + childrenImpl[1] + ")"; + } + }, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (args.get(0).getClass() == Constant.class && ((Constant) args.get(0)).getSymbol().equals(nil)) { + return new Constant(false_); + } + if (args.get(0) instanceof Term) { + Term term = (Term) args.get(0); + Type type = term.getType(); + if (typeList.isAncestorOf(type)) { + while (term.getSymbol().equals(DataConstraintModel.append)) { + if (term.getChild(1).equals(args.get(1))) { + return new Constant(true_); + } + if (!(term.getChild(0) instanceof Term)) { + return new Constant(false_); + } + term = (Term) term.getChild(0); + } + if (term instanceof ListTerm) { + for (Expression element: term.getChildren()) { + if (element.equals(args.get(1))) { + return new Constant(true_); + } + } + return new Constant(false_); + } + } else if (typeMap.isAncestorOf(type)) { + while (term.getSymbol().equals(DataConstraintModel.insert)) { + if (term.getChild(1).equals(args.get(1))) { + return new Constant(true_); + } + if (!(term.getChild(0) instanceof Term)) { + return new Constant(false_); + } + term = (Term) term.getChild(0); + } + if (term instanceof MapTerm) { + String key; + if (args.get(1) instanceof Constant) { + key = (String) ((Constant) args.get(1)).getValue(); + } else { + key = args.get(1).toString(); + } + if (((MapTerm) term).keySet().contains(key)) { + return new Constant(true_); + } + return new Constant(false_); + } + } else if (typeJson.isAncestorOf(type)) { + while (term.getSymbol().equals(DataConstraintModel.addMember)) { + if (term.getChild(1).equals(args.get(1))) { + return new Constant(true_); + } + if (!(term.getChild(0) instanceof Term)) { + return new Constant(false_); + } + term = (Term) term.getChild(0); + } + if (term instanceof JsonTerm) { + String key; + if (args.get(1) instanceof Constant) { + key = (String) ((Constant) args.get(1)).getValue(); + } else { + key = args.get(1).toString(); + } + if (((JsonTerm) term).keySet().contains(key)) { + return new Constant(true_); + } + return new Constant(false_); + } + } + } + return null; + } + }); + public static final Symbol indexOf = new Symbol("indexOf", 2, Symbol.Type.PREFIX, "indexOf", Symbol.Type.METHOD, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (args.get(0) instanceof Term) { + Term term = (Term) args.get(0); + Type type = term.getType(); + if (typeList.isAncestorOf(type)) { + Stack appendedChldren = new Stack<>(); + while (term.getSymbol().equals(DataConstraintModel.append)) { + if (!(term.getChild(0) instanceof Term)) { + return null; + } + appendedChldren.push(term.getChild(1)); + term = (Term) term.getChild(0); + } + if (term instanceof ListTerm) { + int idx = 0; + ListTerm listTerm = (ListTerm) term; + for (Expression child: listTerm.getChildren()) { + if (child.equals(args.get(1))) { + return new Constant(Integer.toString(idx), typeInt); + } + idx++; + } + for (Expression child: appendedChldren) { + if (child.equals(args.get(1))) { + return new Constant(Integer.toString(idx), typeInt); + } + idx++; + } + } + } + } + return null; + } + }); + public static final Symbol search = new Symbol("search", 2, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { + final int count[] = {0}; + @Override + public String generate(Type type, Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { + for (String s: childrenSideEffects) { + sideEffect[0] += s; + } + String temp = "temp_search" + count[0]; + String impl = ""; + impl += "Map " + temp + " = new HashMap<>();\n"; + impl += "for (String key: " + childrenImpl[0] + ".keySet()) {\n"; + impl += "\tboolean isMatch = true;\n"; + impl += "\tfor (String qKey: " + childrenImpl[1] + ".keySet()) {\n"; + impl += "\t\tMap value = " + childrenImpl[0] + ".get(key).getValue();\n"; + impl += "\t\tfor (String valKey: value.keySet()) {\n"; + impl += "\t\t\tif (valKey.equals(qKey)) {\n"; + impl += "\t\t\t\tif (value.get(valKey).equals(" + childrenImpl[1] + ".get(qKey))) {\n"; + impl += "\t\t\t\t\tisMatch = false;\n"; + impl += "\t\t\t\t}\n"; + impl += "\t\t\t\tbreak;\n"; + impl += "\t\t\t}\n"; + impl += "\t\t}\n"; + impl += "\t\tif (!isMatch) break;\n"; + impl += "\t}\n"; + impl += "\tif (isMatch) {\n"; + impl += "\t\t" + temp + ".put(key, " + childrenImpl[0] + ".get(key));\n"; + impl += "\t}\n"; + impl += "}\n"; + sideEffect[0] += impl; + + count[0]++; + return temp; + } + }, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (args.size() != 2) + return null; + + Expression arg0 = args.get(0); + if (!(arg0 instanceof MapTerm)) { + return null; + } + MapTerm searchFrom = (MapTerm) arg0; + + Expression arg1 = args.get(1); + if (arg1 instanceof JsonTerm) { + JsonTerm queryTerm = (JsonTerm) arg1; + MapTerm result = new MapTerm(); + + for (String key: searchFrom.keySet()) { + boolean isMatch = true; + if (searchFrom.get(key) instanceof JsonTerm) { + JsonTerm value = (JsonTerm) searchFrom.get(key); + for (String qKey: queryTerm.keySet()) { + for (String valKey: value.keySet()) { + if (value.get(valKey) instanceof Constant) { + Constant valVal = (Constant) value.get(valKey); + if (!(valKey.equals(qKey))) { + continue; + } + if (queryTerm.get(qKey) instanceof Constant) { + Constant qVal = (Constant) queryTerm.get(qKey); + if (!(valVal.getValue().equals(qVal.getValue()))) { + isMatch = false; + } + } + break; + } + } + if (!isMatch) break; + } + if (isMatch) { + result.insert(key, value); + } + } else if (searchFrom.get(key) instanceof MapTerm) { + } else if (searchFrom.get(key) instanceof ListTerm) { + } + } + return result; + } + return null; + } + }); + public static final Symbol nil = new Symbol("nil", 0, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { + final int count[] = {0}; + @Override + public String generate(Type type, Type[] childrenTypes, String[] children, String[] childrenSideEffects, String[] sideEffect) { String compType = ""; if (type != null) { String interfaceType = type.getInterfaceTypeName(); @@ -53,27 +871,39 @@ if (implType.indexOf('<') >= 0) { implType = implType.substring(0, implType.indexOf('<')); } - return "new " + implType + "<" + compType + ">()"; - } + if (sideEffect == null) { + return "new " + implType + "<>()"; + } else { + String temp = "temp_nil" + count[0]; + if (sideEffect[0] == null) { + sideEffect[0] = ""; + } + sideEffect[0] += interfaceType + " " + temp + " = " + "new " + implType + "<" + compType + ">();\n"; + count[0]++; + return temp; + } + } return "new ArrayList<" + compType + ">()"; } - }); + }, true); public static final Symbol null_ = new Symbol("null", 0, Symbol.Type.PREFIX, "null", Symbol.Type.PREFIX); + public static final Symbol true_ = new Symbol("true", 0, Symbol.Type.PREFIX, "true", Symbol.Type.PREFIX); + public static final Symbol false_ = new Symbol("false", 0, Symbol.Type.PREFIX, "false", Symbol.Type.PREFIX); public static final Symbol cond = new Symbol("if", 3, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { final int count[] = {0}; @Override - public String generate(Type type, String[] children, String[] childrenSideEffects, String[] sideEffect) { + public String generate(Type type, Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { String temp = "temp_if" + count[0]; - String impl = ""; + String impl = ""; impl += type.getInterfaceTypeName() + " " + temp + ";\n"; if (childrenSideEffects[0] != null && childrenSideEffects[0].length() > 0) impl += childrenSideEffects[0]; - impl += "if (" + children[0] + ") {\n"; + impl += "if (" + childrenImpl[0] + ") {\n"; if (childrenSideEffects[1] != null && childrenSideEffects[1].length() > 0) impl += "\t" + childrenSideEffects[1]; - impl += "\t" + temp + " = " + children[1] + ";\n"; + impl += "\t" + temp + " = " + childrenImpl[1] + ";\n"; impl += "} else {\n"; if (childrenSideEffects[2] != null && childrenSideEffects[2].length() > 0) impl += "\t" + childrenSideEffects[2]; - impl += "\t" + temp + " = " + children[2] + ";\n"; + impl += "\t" + temp + " = " + childrenImpl[2] + ";\n"; impl += "}\n"; sideEffect[0] += impl; @@ -81,24 +911,21 @@ count[0]++; return temp; } + }, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (!(args.get(0).getClass() == Constant.class)) return null; + if (((Constant) args.get(0)).getSymbol().equals(true_)) { + return args.get(1); + } else if (((Constant) args.get(0)).getSymbol().equals(false_)) { + return args.get(2); + } + return null; + } }); - - - public static final Symbol mod = new Symbol("mod", 2, Symbol.Type.PREFIX, "%", Symbol.Type.INFIX); - public static final Symbol eq = new Symbol("eq", 2, Symbol.Type.PREFIX, "==", Symbol.Type.INFIX); - public static final Symbol neq = new Symbol("neq", 2, Symbol.Type.PREFIX, "!=", Symbol.Type.INFIX); - public static final Symbol gt = new Symbol("gt", 2, Symbol.Type.PREFIX, ">", Symbol.Type.INFIX); - public static final Symbol lt = new Symbol("lt", 2, Symbol.Type.PREFIX, "<", Symbol.Type.INFIX); - public static final Symbol ge = new Symbol("ge", 2, Symbol.Type.PREFIX, ">=", Symbol.Type.INFIX); - public static final Symbol le = new Symbol("le", 2, Symbol.Type.PREFIX, "<=", Symbol.Type.INFIX); - public static final Symbol and = new Symbol("and", 2, Symbol.Type.PREFIX, "&&", Symbol.Type.INFIX); - public static final Symbol or = new Symbol("or", 2, Symbol.Type.PREFIX, "||", Symbol.Type.INFIX); - public static final Symbol neg = new Symbol("neg", 1, Symbol.Type.PREFIX, "!", Symbol.Type.PREFIX); - public static final Symbol true_ = new Symbol("true", 0, Symbol.Type.PREFIX, "true", Symbol.Type.PREFIX); - public static final Symbol false_ = new Symbol("false", 0, Symbol.Type.PREFIX, "false", Symbol.Type.PREFIX); public static final Symbol pair = new Symbol("pair", -1, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { @Override - public String generate(Type type, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { + public String generate(Type type, Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { for (String s: childrenSideEffects) { sideEffect[0] += s; } @@ -108,7 +935,7 @@ }); public static final Symbol tuple = new Symbol("tuple", -1, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { @Override - public String generate(Type type, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { + public String generate(Type type, Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { for (String s: childrenSideEffects) { sideEffect[0] += s; } @@ -124,26 +951,76 @@ public static final Symbol snd = new Symbol("snd", 1, Symbol.Type.PREFIX, "getValue", Symbol.Type.METHOD); public static final Symbol left = new Symbol("left", 1, Symbol.Type.PREFIX, "getLeft", Symbol.Type.METHOD); public static final Symbol right = new Symbol("right", 1, Symbol.Type.PREFIX, "getRight", Symbol.Type.METHOD); - public static final Symbol insert = new Symbol("insert", 3, Symbol.Type.PREFIX, "put", Symbol.Type.METHOD_WITH_SIDE_EFFECT); -// public static final Symbol lookup = new Symbol("lookup", 2, Symbol.Type.PREFIX, "get", Symbol.Type.METHOD); - public static final Symbol lookup = new Symbol("lookup", 2, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { - final int count[] = {0}; + public static final Symbol insert = new Symbol("insert", 3, Symbol.Type.PREFIX, "put", Symbol.Type.METHOD_WITH_SIDE_EFFECT); // Don't calculate here (Calculated in simulator). + public static final Symbol delete = new Symbol("delete", 2, Symbol.Type.PREFIX, "remove", Symbol.Type.METHOD_WITH_SIDE_EFFECT); // Don't calculate here (Calculated in simulator). + public static final Symbol lookup = new Symbol("lookup", 2, Symbol.Type.PREFIX, "get", Symbol.Type.METHOD, new Symbol.ICalculator() { @Override - public String generate(Type type, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { - String temp = "temp_get" + count[0]; - String impl = childrenSideEffects[0] + childrenSideEffects[1]; - impl += type.getInterfaceTypeName() + " " + temp + ";\n"; - impl += "if (" + childrenImpl[0] + ".get(" + childrenImpl[1] + ") != null) {\n"; - impl += "\t" + temp + " = " + childrenImpl[0] + ".get(" + childrenImpl[1] + ");\n"; - impl += "} else {\n"; - impl += "\t" + temp + " = " + getDefaultValue(type) + ";\n"; - impl += "}\n"; - sideEffect[0] = impl; - count[0]++; - return temp; + public Expression calculate(List args) { + if (args.get(1).getClass() == Constant.class && + ((Constant) args.get(1)).getType() != null && ((Constant) args.get(1)).getType().equals(typeString)) { + String key = (String) ((Constant) args.get(1)).getValue(); + if (args.get(0) instanceof Term) { + Term term = (Term) args.get(0); + Type type = term.getType(); + if (typeMap.isAncestorOf(type)) { + Stack> appendedChldren = new Stack<>(); + while (term.getSymbol().equals(DataConstraintModel.insert)) { + if (!(term.getChild(0) instanceof Term)) { + return null; + } + appendedChldren.push(new AbstractMap.SimpleEntry<>(term.getChild(0), term.getChild(1))); + term = (Term) term.getChild(0); + } + if (term instanceof MapTerm) { + MapTerm mapTerm = (MapTerm) term.clone(); + for (Map.Entry childEnt: appendedChldren) { + if (childEnt.getKey().getClass() == Constant.class) + mapTerm.insert((String) ((Constant) childEnt.getKey()).getValue(), childEnt.getValue()); + } + return mapTerm.get(key); + } + } + } + } + return null; } }); - + public static final Symbol addMember = new Symbol("addMember", 3, Symbol.Type.PREFIX, "put", Symbol.Type.METHOD_WITH_SIDE_EFFECT); + public static final Symbol dot = new Symbol(Parser.DOT, 2, Symbol.Type.INFIX, "get", Symbol.Type.METHOD); + public static final Symbol dotParam = new Symbol(Parser.DOT, 2, Symbol.Type.INFIX, "get", Symbol.Type.METHOD); + public static final Symbol pi = new Symbol("PI", 0, Symbol.Type.PREFIX, "Math.PI", Symbol.Type.PREFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + return new Constant(Double.toString(Math.PI), typeDouble); + }}); + public static final Symbol E = new Symbol("E", 0, Symbol.Type.PREFIX, "Math.E", Symbol.Type.PREFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + return new Constant(Double.toString(Math.E), typeDouble); + }}); + public static final Symbol sqrt = new Symbol("sqrt", 1, Symbol.Type.PREFIX, "Math.sqrt", Symbol.Type.PREFIX, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (args.get(0).getClass() == Constant.class) { + if (((Constant) args.get(0)).getType().equals(typeDouble)) { + return new Constant(Double.toString(Math.sqrt(Double.parseDouble((String) ((Constant) args.get(0)).getValue()))), typeDouble); + } else if (((Constant) args.get(0)).getType().equals(typeFloat)) { + return new Constant(Float.toString((float) Math.sqrt(Float.parseFloat((String) ((Constant) args.get(0)).getValue()))), typeFloat); + } + } + return null; + }}); + public static final Symbol sin = new Symbol("sin", 1, Symbol.Type.PREFIX, "Math.sin", Symbol.Type.PREFIX); + public static final Symbol cos = new Symbol("cos", 1, Symbol.Type.PREFIX, "Math.cos", Symbol.Type.PREFIX); + public static final Symbol tan = new Symbol("tan", 1, Symbol.Type.PREFIX, "Math.tan", Symbol.Type.PREFIX); + public static final Symbol asin = new Symbol("asin", 1, Symbol.Type.PREFIX, "Math.asin", Symbol.Type.PREFIX); + public static final Symbol acos = new Symbol("acos", 1, Symbol.Type.PREFIX, "Math.acos", Symbol.Type.PREFIX); + public static final Symbol atan = new Symbol("atan", 1, Symbol.Type.PREFIX, "Math.atan", Symbol.Type.PREFIX); + public static final Symbol pow = new Symbol("pow", 2, Symbol.Type.PREFIX, "Math.pow", Symbol.Type.PREFIX); + public static final Symbol exp = new Symbol("exp", 1, Symbol.Type.PREFIX, "Math.exp", Symbol.Type.PREFIX); + public static final Symbol log = new Symbol("log", 1, Symbol.Type.PREFIX, "Math.log", Symbol.Type.PREFIX); + public static final Symbol abs = new Symbol("abs", 1, Symbol.Type.PREFIX, "Math.abs", Symbol.Type.PREFIX); + static { add.setInverses(new Symbol[] {sub, sub}); mul.setInverses(new Symbol[] {div, div}); @@ -151,12 +1028,6 @@ div.setInverses(new Symbol[] {mul}); minus.setInverses(new Symbol[] {minus}); mod.setSignature(new Type[] {typeInt, null, null}); - cons.setInverses(new Symbol[] {head, tail}); - cons.setSignature(new Type[] {typeList, null, typeList}); - contains.setSignature(new Type[] {typeBoolean, typeList, null}); - length.setSignature(new Type[] {typeInt, null}); - get.setSignature(new Type[] {null, typeList, typeInt}); - set.setSignature(new Type[] {typeList, typeList, typeInt, null}); eq.setSignature(new Type[] {typeBoolean, null, null}); neq.setSignature(new Type[] {typeBoolean, null, null}); gt.setSignature(new Type[] {typeBoolean, null, null}); @@ -166,25 +1037,62 @@ and.setSignature(new Type[] {typeBoolean, typeBoolean, typeBoolean}); or.setSignature(new Type[] {typeBoolean, typeBoolean, typeBoolean}); neg.setSignature(new Type[] {typeBoolean, typeBoolean}); + cons.setInverses(new Symbol[] {head, tail}); + cons.setSignature(new Type[] {typeList, null, typeList}); + append.setSignature(new Type[] {typeList, typeList, null}); + remove.setSignature(new Type[] {typeList, typeList, typeInt}); + head.setSignature(new Type[] {null, typeList}); + tail.setSignature(new Type[] {typeList, typeList}); + contains.setSignature(new Type[] {typeBoolean, null, null}); + indexOf.setSignature(new Type[] {typeInt, typeList, null}); + search.setSignature(new Type[] {typeMap, typeMap, typeJson}); + length.setSignature(new Type[] {typeInt, null}); + get.setSignature(new Type[] {null, typeList, typeInt}); + set.setSignature(new Type[] {typeList, typeList, typeInt, null}); + null_.setSignature(new Type[] {null}); true_.setSignature(new Type[] {typeBoolean}); false_.setSignature(new Type[] {typeBoolean}); - null_.setSignature(new Type[] {null}); - pair.setSignature(new Type[] {typePair,null,null}); + pair.setSignature(new Type[] {typePair, null, null}); pair.setInverses(new Symbol[] {left, right}); left.setSignature(new Type[] {null, typePair}); right.setSignature(new Type[] {null, typePair}); tuple.setSignature(new Type[] {typeTuple, null, null}); tuple.setInverses(new Symbol[] {fst, snd}); fst.setSignature(new Type[] {null, typeTuple}); + fst.setInverses(new Symbol[] {new LambdaAbstraction(new Variable("x"), new Term(tuple, new Expression[] {new Variable("x"), new Variable("y")}))}); snd.setSignature(new Type[] {null, typeTuple}); + snd.setInverses(new Symbol[] {new LambdaAbstraction(new Variable("y"), new Term(tuple, new Expression[] {new Variable("x"), new Variable("y")}))}); insert.setSignature(new Type[] {typeMap, typeMap, null, null}); + delete.setSignature(new Type[] {typeMap, typeMap, null}); lookup.setSignature(new Type[] {null, typeMap, null}); + addMember.setSignature(new Type[] {typeJson, typeJson, typeString, null}); + dot.setSignature(new Type[] {null, typeJson, typeString}); + dotParam.setSignature(new Type[] {null, typeJson, null}); + pi.setSignature(new Type[] {typeDouble}); + E.setSignature(new Type[] {typeDouble}); + sqrt.setSignature(new Type[] {typeDouble, typeDouble}); + sin.setSignature(new Type[] {typeDouble, typeDouble}); + cos.setSignature(new Type[] {typeDouble, typeDouble}); + tan.setSignature(new Type[] {typeDouble, typeDouble}); + asin.setSignature(new Type[] {typeDouble, typeDouble}); + asin.setInverses(new Symbol[] {sin}); + acos.setSignature(new Type[] {typeDouble, typeDouble}); + acos.setInverses(new Symbol[] {cos}); + atan.setSignature(new Type[] {typeDouble, typeDouble}); + atan.setInverses(new Symbol[] {tan}); + pow.setSignature(new Type[] {typeDouble, typeDouble, typeDouble}); + exp.setSignature(new Type[] {typeDouble, typeDouble}); + exp.setInverses(new Symbol[] {log}); + log.setSignature(new Type[] {typeDouble, typeDouble}); + log.setInverses(new Symbol[] {exp}); + abs.setSignature(new Type[] {typeDouble, typeDouble}); } public DataConstraintModel() { - resourcePaths = new HashMap<>(); + resourcePaths = new ArrayList<>(); + resourceHierarchies = new HashMap<>(); channels = new HashMap<>(); - ioChannels = new HashMap<>(); + inputChannels = new HashMap<>(); types = new HashMap<>(); addType(typeInt); addType(typeLong); @@ -196,6 +1104,7 @@ addType(typePair); addType(typeTuple); addType(typeMap); + addType(typeJson); symbols = new HashMap<>(); addSymbol(add); addSymbol(mul); @@ -203,15 +1112,6 @@ addSymbol(div); addSymbol(minus); addSymbol(mod); - addSymbol(cons); - addSymbol(head); - addSymbol(tail); - addSymbol(length); - addSymbol(contains); - addSymbol(get); - addSymbol(set); - addSymbol(nil); - addSymbol(cond); addSymbol(eq); addSymbol(neq); addSymbol(gt); @@ -221,9 +1121,22 @@ addSymbol(and); addSymbol(or); addSymbol(neg); + addSymbol(cons); + addSymbol(append); + addSymbol(remove); + addSymbol(head); + addSymbol(tail); + addSymbol(length); + addSymbol(contains); + addSymbol(search); + addSymbol(indexOf); + addSymbol(get); + addSymbol(set); + addSymbol(cond); + addSymbol(nil); + addSymbol(null_); addSymbol(true_); addSymbol(false_); - addSymbol(null_); addSymbol(pair); addSymbol(left); addSymbol(right); @@ -231,90 +1144,132 @@ addSymbol(fst); addSymbol(snd); addSymbol(insert); + addSymbol(delete); addSymbol(lookup); + addSymbol(addMember); + addSymbol(dot); + addSymbol(dotParam); + addSymbol(pi); + addSymbol(E); + addSymbol(sqrt); + addSymbol(sin); + addSymbol(cos); + addSymbol(tan); + addSymbol(asin); + addSymbol(acos); + addSymbol(atan); + addSymbol(pow); + addSymbol(exp); + addSymbol(log); + addSymbol(abs); } - public Collection getResourcePaths() { - return resourcePaths.values(); + public Collection getResourceHierarchies() { + return resourceHierarchies.values(); } - public ResourcePath getResourcePath(String resourceName) { - return resourcePaths.get(resourceName); + public ResourceHierarchy getResourceHierarchy(String hierarchy) { + return resourceHierarchies.get(hierarchy); + } + + public ResourceHierarchy getOrPutResourceHierarchy(ResourceHierarchy resourceHierarchy) { + String hierarchy = resourceHierarchy.toString(); + if (resourceHierarchies.get(hierarchy) != null) { + return resourceHierarchies.get(hierarchy); + } + resourceHierarchies.put(hierarchy, resourceHierarchy); + return resourceHierarchy; + } + + public List getResourcePaths() { + return resourcePaths; } public void addResourcePath(ResourcePath resourcePath) { - resourcePaths.put(resourcePath.getResourceName(), resourcePath); + resourcePaths.add(resourcePath); + ResourceHierarchy childHierarchy = null; + ResourceHierarchy hierarchy = null; + do { + hierarchy = resourcePath.getResourceHierarchy(); + if (hierarchy != null && resourceHierarchies.get(hierarchy.toString()) == null) { + resourceHierarchies.put(hierarchy.toString(), hierarchy); + } else { + hierarchy = resourceHierarchies.get(hierarchy.toString()); + resourcePath.setResourceHierarchy(hierarchy); + if (childHierarchy != null) { + childHierarchy.setParent(hierarchy); + } + } + resourcePath = resourcePath.getParent(); + childHierarchy = hierarchy; + } while (resourcePath != null); } - public void setResourcePaths(HashMap resourcePaths) { + public void setResourcePaths(List resourcePaths) { this.resourcePaths = resourcePaths; } - public void removeResourcePath(String resourceName) { - ResourcePath id = resourcePaths.get(resourceName); - resourcePaths.remove(resourceName); - for (Channel ch: channels.values()) { - ch.removeChannelMember(id); + public ResourcePath getResourcePath(String path) { + for (ResourcePath resourcePath: resourcePaths) { + if (resourcePath.toString().equals(path)) return resourcePath; } - for (Channel ch: ioChannels.values()) { - ch.removeChannelMember(id); + return null; + } + + public void removeResourcePath(String path) { + ResourcePath resourcePath = getResourcePath(path); + if (resourcePath == null) return; + resourcePaths.remove(resourcePath); + removeResourcePath(resourcePath); + } + + public void removeResourcePath(ResourcePath resourcePath) { + for (Channel ch: channels.values()) { + ch.removeChannelMember(resourcePath); + } + for (Channel ch: inputChannels.values()) { + ch.removeChannelMember(resourcePath); } } public Collection getChannels() { return channels.values(); } - + public Channel getChannel(String channelName) { return channels.get(channelName); } public void setChannels(HashMap channels) { this.channels = channels; - for (Channel g: channels.values()) { - for (ResourcePath id: g.getResources()) { - resourcePaths.put(id.getResourceName(), id); - } - } } public void addChannel(Channel channel) { channels.put(channel.getChannelName(), channel); - for (ResourcePath id: channel.getResources()) { - resourcePaths.put(id.getResourceName(), id); - } } public void removeChannel(String channelName) { channels.remove(channelName); } - public Collection getIOChannels() { - return ioChannels.values(); + public Collection getInputChannels() { + return inputChannels.values(); } - public Channel getIOChannel(String channelName) { - return ioChannels.get(channelName); + public Channel getInputChannel(String channelName) { + return inputChannels.get(channelName); } - public void setIOChannels(HashMap ioChannels) { - this.ioChannels = ioChannels; - for (Channel g: ioChannels.values()) { - for (ResourcePath id: g.getResources()) { - resourcePaths.put(id.getResourceName(), id); - } - } + public void setInputChannels(HashMap inputChannels) { + this.inputChannels = inputChannels; } - public void addIOChannel(Channel ioChannel) { - ioChannels.put(ioChannel.getChannelName(), ioChannel); - for (ResourcePath id: ioChannel.getResources()) { - resourcePaths.put(id.getResourceName(), id); - } + public void addInputChannel(Channel inputChannel) { + inputChannels.put(inputChannel.getChannelName(), inputChannel); } - public void removeIOChannel(String ioChannelName) { - ioChannels.remove(ioChannelName); + public void removeInputChannel(String inputChannelName) { + inputChannels.remove(inputChannelName); } public void addType(Type type) { @@ -349,7 +1304,7 @@ } public boolean isPrimitiveType(Type type) { - if (type == typeInt + if (type == typeInt || type == typeLong || type == typeFloat || type == typeDouble @@ -380,10 +1335,33 @@ return "new " + type.getImplementationTypeName() + "()"; } + public static Expression getDefaultValueExpression(Type type) { + if (type == typeInt) { + return new Constant("0", typeInt); + } else if (type == typeLong) { + return new Constant("0L", typeLong); + } else if (type == typeFloat) { + return new Constant("0.0f", typeFloat); + } else if (type == typeDouble) { + return new Constant("0.0", typeDouble); + } else if (type == typeBoolean) { + return new Constant(false_); + } else if (type == typeString) { + return new Constant("", typeString); + } else if (type.isAncestorOf(typeList)) { + return new ListTerm(); + } else if (type.isAncestorOf(typeMap)) { + return new MapTerm(); + } else if (type.isAncestorOf(typeJson)) { + return new JsonTerm(); + } + return null; + } + @Override public String toString() { String out = ""; - for (Channel channel: ioChannels.values()) { + for (Channel channel: inputChannels.values()) { out += channel.toString(); } for (Channel channel: channels.values()) { @@ -395,16 +1373,16 @@ public String getSourceText() { String out = ""; String init = ""; - for (ResourcePath resource: resourcePaths.values()) { + for (ResourceHierarchy resource: resourceHierarchies.values()) { String initializer = resource.getInitText(); if (initializer != null) { - init += initializer; + init += resource.toString() + " := " + initializer + "\n"; } } if (init.length() > 0) { out += "init {\n" + init + "}\n"; } - for (Channel channel: ioChannels.values()) { + for (Channel channel: inputChannels.values()) { out += channel.getSourceText(); } for (Channel channel: channels.values()) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java new file mode 100644 index 0000000..1cf0c22 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java @@ -0,0 +1,225 @@ +package models.dataConstraintModel; + +import generators.JavaImplementationVisitor; +import models.algebra.*; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class JsonAccessor extends Term { + + public JsonAccessor(Symbol symbol) { + super(symbol); + } + + @Override + public Expression reduce() { + Expression reducedTerm = super.reduce(); + if (reducedTerm instanceof Term) { + if (symbol == DataConstraintModel.dot && getChildren().size() >= 2) { + // this term is `json.key`. + Expression expJson = getChild(0); + Expression expKey = getChild(1); + if (expKey instanceof Constant && expJson instanceof Term) { + reducedTerm = getValue((Term) expJson, (Constant) expKey); + } + } else if (symbol == DataConstraintModel.dotParam && getChildren().size() >= 2) { + // this term is `json.{param}`. + Expression expJson = getChild(0); + Expression expKey = getChild(1); + if (expKey instanceof Variable && expJson instanceof Term) { + reducedTerm = getValue((Term) expJson, (Variable) expKey); + } + } + } + return reducedTerm; + } + + private Expression getValue(Term json, Expression key) { + if (json instanceof JsonTerm) { + if (key instanceof Constant) { + return ((JsonTerm) json).get((Constant) key); + } else if (key instanceof Variable) { + return ((JsonTerm) json).get((Variable) key); + } + } + if (key instanceof Constant || key instanceof Variable) { + if (json.getSymbol().equals(DataConstraintModel.addMember) || json.getSymbol().equals(DataConstraintModel.set)) { + if (json.getChild(1).equals(key)) { + Expression value = json.getChild(2); + if (value == null) { + return new Constant(DataConstraintModel.null_); + } + return value; + } + if (json.getChild(0) == null + || (json.getChild(0) instanceof Term && + (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) + || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil))) return null; + return getValue((Term) json.getChild(0), key); + } + } + return new Constant(DataConstraintModel.null_); + } + + private Expression getValue(Term json, Variable key) { + if (json instanceof JsonTerm) { + return ((JsonTerm) json).get(key); + } + if (json.getSymbol().equals(DataConstraintModel.addMember) || json.getSymbol().equals(DataConstraintModel.set)) { + if (json.getChild(1).equals(key)) { + Expression value = json.getChild(2); + if (value == null) { + return new Constant(DataConstraintModel.null_); + } + return value; + } + if (json.getChild(0) == null + || (json.getChild(0) instanceof Term && + (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) + || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil))) return null; + return getValue((Term) json.getChild(0), key); + } + if (json.getSymbol().equals(DataConstraintModel.insert)) { + if (json.getChild(1).equals(key)) { + Expression value = json.getChild(2); + if (value == null) { + return new Constant(DataConstraintModel.null_); + } + return value; + } + if (json.getChild(0) == null + || (json.getChild(0) instanceof Term && + (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) + || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil))) return null; + return getValue((Term) json.getChild(0), key); + } + return new Constant(DataConstraintModel.null_); + } + + @Override + public Expression getInverseMap(Expression outputValue, Position targetPos) { + if (targetPos.isEmpty()) return outputValue; + targetPos = (Position) targetPos.clone(); + int i = targetPos.removeHeadOrder(); + Symbol[] inverseSymbols = symbol.getInverses(); + if (i == 0) { + if (symbol == DataConstraintModel.dot && getChildren().size() >= 2) { + // this term is `json.key`. + Expression expJson = getChild(0); + Expression expKey = getChild(1); + Type jsonType = null; + if (expJson instanceof Variable) { + jsonType = ((Variable) expJson).getType(); + } else if (expJson instanceof Term) { + jsonType = ((Term) expJson).getType(); + } + String keyName = null; + if (expKey instanceof Constant) { + keyName = (String) ((Constant) expKey).getValue(); + Term jsonTerm = new Constant(DataConstraintModel.nil); + jsonTerm.setType(DataConstraintModel.typeJson); + int v = 1; + Map vars = new HashMap<>(); + Set keySet = new HashSet<>(); + if (jsonType == null || jsonType == DataConstraintModel.typeJson) { + keySet.add(keyName); + } else if (jsonType instanceof JsonType) { + keySet.addAll(((JsonType) jsonType).getKeys()); + if (keySet.size() == 0) { + keySet.add(keyName); + } + } + for (String key : keySet) { + Term addMemberTerm = new Term(DataConstraintModel.addMember); // addMember(jsonTerm, key, v) + addMemberTerm.addChild(jsonTerm); + addMemberTerm.addChild(new Constant(key, DataConstraintModel.typeString)); + Variable var = new Variable("v" + v); + addMemberTerm.addChild(var); + vars.put(key, var); + jsonTerm = addMemberTerm; + v++; + } + Variable var = vars.get(keyName); + LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, jsonTerm); // v -> addMember(jsonTerm, key, v) + inverseSymbols = new Symbol[]{lambdaAbstraction}; + } + } else if (symbol == DataConstraintModel.dotParam && getChildren().size() >= 2) { + // this term is `json.{param}`. + Expression expListOrMap = getChild(0); + Expression expKey = getChild(1); + JsonType jsonType = null; + if (expListOrMap instanceof Variable) { + jsonType = (JsonType) ((Variable) expListOrMap).getType(); + } else if (expListOrMap instanceof Term) { + jsonType = (JsonType) ((Term) expListOrMap).getType(); + } + Type keyType = null; + if (expKey instanceof Variable) { + keyType = ((Variable) expKey).getType(); + } else if (expKey instanceof Term) { + keyType = ((Term) expKey).getType(); + } + if (jsonType != null && keyType != null) { + if (DataConstraintModel.typeList.isAncestorOf(jsonType) || keyType.equals(DataConstraintModel.typeInt)) { + Term setElementTerm = new Term(DataConstraintModel.set); // set(list, idx, v) + setElementTerm.addChild(new Constant(DataConstraintModel.nil)); + setElementTerm.addChild(expKey); + Variable var = new Variable("v"); + setElementTerm.addChild(var); + LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, setElementTerm); // v -> set(list, idx, v) + inverseSymbols = new Symbol[]{lambdaAbstraction}; + } else if (DataConstraintModel.typeMap.isAncestorOf(jsonType) || keyType.equals(DataConstraintModel.typeString)) { + Term insertEntryTerm = new Term(DataConstraintModel.insert); // insert(map, key, v) + insertEntryTerm.addChild(new Constant(DataConstraintModel.nil)); + insertEntryTerm.addChild(expKey); + Variable var = new Variable("v"); + insertEntryTerm.addChild(var); + LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, insertEntryTerm); // v -> insert(map, key, v) + inverseSymbols = new Symbol[]{lambdaAbstraction}; + } + } + } + } + if (inverseSymbols == null || i >= inverseSymbols.length || inverseSymbols[i] == null) return null; + Term inverseMap = new Term(inverseSymbols[i]); + inverseMap.addChild(outputValue); + for (int n = 0; n < inverseSymbols[i].getArity(); n++) { + if (n != i) { + inverseMap.addChild(children.get(n)); + } + } + return children.get(i).getInverseMap(inverseMap, targetPos); + } + + public String toString() { + if (symbol.equals(DataConstraintModel.dotParam)) { + if (children.get(1) instanceof Constant) { + return children.get(0).toString() + symbol.toString() + (String) ((Constant) children.get(1)).getValue(); + } + return children.get(0).toString() + symbol.toString() + children.get(1).toString(); + } + return super.toString(); + } + + public String toImplementation(String[] sideEffects) { + return accept(new JavaImplementationVisitor(), sideEffects); + } + + @Override + public String accept(IExpressionVisitor visitor, String[] sideEffects) { + return visitor.visit(this, sideEffects); + } + + @Override + public Object clone() { + JsonAccessor newTerm = new JsonAccessor(symbol); + for (Expression e : children) { + newTerm.addChild((Expression) e.clone()); + } + newTerm.type = type; + return newTerm; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java new file mode 100644 index 0000000..608a27e --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java @@ -0,0 +1,101 @@ +package models.dataConstraintModel; + +import generators.JavaImplementationVisitor; +import models.algebra.*; +import parser.Parser; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class JsonTerm extends Term { + private Map keyToIndex = new HashMap<>(); + private static int count = 0; + + public JsonTerm() { + super(new Symbol("json", -1)); + setType(DataConstraintModel.typeJson); + } + + public void addMember(String key, Expression value) { + if (keyToIndex.containsKey(key)) { + setChild(keyToIndex.get(key), value); + } else { + keyToIndex.put(key, getChildren().size()); + addChild(value); + } + } + + public Set keySet() { + return keyToIndex.keySet(); + } + + public Expression get(String key) { + if (keyToIndex.get(key) == null) return null; + return getChild(keyToIndex.get(key)); + } + + public Expression get(Constant key) { + if (keyToIndex.get(key.getValue()) == null) return null; + return getChild(keyToIndex.get(key.getValue())); + } + + public Expression get(Variable key) { + if (keyToIndex.get(key.getName()) == null) return null; + return getChild(keyToIndex.get(key.getName())); + } + + @Override + public Expression unify(Expression another) { + if (another instanceof JsonTerm) { + JsonTerm anotherTerm = (JsonTerm) another; + JsonTerm unifiedTerm = new JsonTerm(); + Set keySet = new HashSet<>(); + keySet.addAll(this.keySet()); + keySet.addAll(anotherTerm.keySet()); + for (String key : keySet) { + if (this.keySet().contains(key)) { + if (anotherTerm.keySet().contains(key)) { + unifiedTerm.addMember(key, this.get(key).unify(anotherTerm.get(key))); + } else { + unifiedTerm.addMember(key, this.get(key)); + } + } else { + unifiedTerm.addMember(key, anotherTerm.get(key)); + } + } + return unifiedTerm; + } + return this; + } + + @Override + public Object clone() { + JsonTerm newTerm = new JsonTerm(); + for (Expression e : children) { + newTerm.addChild((Expression) e.clone()); + } + newTerm.keyToIndex = new HashMap(keyToIndex); + return newTerm; + } + + public String toString() { + String jsonStr = "{"; + String delim = ""; + for (String key : keyToIndex.keySet()) { + jsonStr += delim + Parser.DOUBLE_QUOT + key + Parser.DOUBLE_QUOT + ": " + getChild(keyToIndex.get(key)).toString(); + delim = ", "; + } + return jsonStr + "}"; + } + + public String toImplementation(String[] sideEffects) { + return accept(new JavaImplementationVisitor(), sideEffects); + } + + @Override + public String accept(IExpressionVisitor visitor, String[] sideEffects) { + return visitor.visit(this, sideEffects); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java new file mode 100644 index 0000000..0e098bc --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java @@ -0,0 +1,47 @@ +package models.dataConstraintModel; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import models.algebra.Type; + +public class JsonType extends Type { + protected Map memberTypes = null; + + public JsonType(String typeName, ITypeImpl implementationType) { + super(typeName, implementationType); + memberTypes = new HashMap<>(); + } + + public JsonType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType) { + super(typeName, implementationType, interfaceType); + memberTypes = new HashMap<>(); + } + + public JsonType(String typeName, ITypeImpl implementationType, Type parentType) { + super(typeName, implementationType, parentType); + memberTypes = new HashMap<>(); + } + + public JsonType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentType) { + super(typeName, implementationType, interfaceType, parentType); + memberTypes = new HashMap<>(); + } + + public Map getMemberTypes() { + return memberTypes; + } + + public Type getMemberType(String key) { + return memberTypes.get(key); + } + + public Set getKeys() { + return memberTypes.keySet(); + } + + public void addMemberType(String key, Type valueType) { + memberTypes.put(key, valueType); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListTerm.java new file mode 100644 index 0000000..afc4212 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListTerm.java @@ -0,0 +1,58 @@ +package models.dataConstraintModel; + +import models.algebra.Expression; +import models.algebra.Symbol; +import models.algebra.Term; + +public class ListTerm extends Term { + + public ListTerm() { + super(new Symbol("list", -1)); + setType(DataConstraintModel.typeList); + } + + public void append(Expression value) { + addChild(value); + } + + public Expression get(int index) { + return getChild(index); + } + + public int size() { + return children.size(); + } + + @Override + public Expression unify(Expression another) { + if (another instanceof ListTerm) { + ListTerm anotherTerm = (ListTerm) another; + if (children.size() != anotherTerm.children.size()) return null; + ListTerm unifiedTerm = new ListTerm(); + for (int i = 0; i < children.size(); i++) { + unifiedTerm.addChild(children.get(i).unify(anotherTerm.children.get(i))); + } + return unifiedTerm; + } + return this; + } + + @Override + public Object clone() { + ListTerm newTerm = new ListTerm(); + for (Expression e: children) { + newTerm.addChild((Expression) e.clone()); + } + return newTerm; + } + + public String toString() { + String listStr = "["; + String delim = ""; + for (Expression child: getChildren()) { + listStr += delim + child.toString(); + delim = ", "; + } + return listStr + "]"; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListType.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListType.java new file mode 100644 index 0000000..35e6589 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListType.java @@ -0,0 +1,32 @@ +package models.dataConstraintModel; + +import models.algebra.Type; + +public class ListType extends Type { + protected Type elementType = null; + + public ListType(String typeName, ITypeImpl implementationType) { + super(typeName, implementationType); + } + + public ListType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType) { + super(typeName, implementationType, interfaceType); + } + + public ListType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentListType) { + super(typeName, implementationType, interfaceType, parentListType); + } + + public ListType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentListType, Type elementType) { + super(typeName, implementationType, interfaceType, parentListType); + this.elementType = elementType; + } + + public Type getElementType() { + return elementType; + } + + public void setElementType(Type listElementType) { + this.elementType = listElementType; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapTerm.java new file mode 100644 index 0000000..18f2c9b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapTerm.java @@ -0,0 +1,87 @@ +package models.dataConstraintModel; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Symbol; +import models.algebra.Term; +import parser.Parser; + +public class MapTerm extends Term { + private Map keyToIndex = new HashMap<>(); + + public MapTerm() { + super(new Symbol("map", -1)); + setType(DataConstraintModel.typeMap); + } + + public void insert(String key, Expression value) { + if (keyToIndex.containsKey(key)) { + setChild(keyToIndex.get(key), value); + } else { + keyToIndex.put(key, getChildren().size()); + addChild(value); + } + } + + public Set keySet() { + return keyToIndex.keySet(); + } + + public Expression get(String key) { + return getChild(keyToIndex.get(key)); + } + + public Expression get(Constant key) { + if (keyToIndex.get(key.getValue()) == null) return null; + return getChild(keyToIndex.get(key.getValue())); + } + + @Override + public Expression unify(Expression another) { + if (another instanceof MapTerm) { + MapTerm anotherTerm = (MapTerm) another; + MapTerm unifiedTerm = new MapTerm(); + Set keySet = new HashSet<>(); + keySet.addAll(this.keySet()); + keySet.addAll(anotherTerm.keySet()); + for (String key: keySet) { + if (this.keySet().contains(key)) { + if (anotherTerm.keySet().contains(key)) { + unifiedTerm.insert(key, this.get(key).unify(anotherTerm.get(key))); + } else { + unifiedTerm.insert(key, this.get(key)); + } + } else { + unifiedTerm.insert(key, anotherTerm.get(key)); + } + } + return unifiedTerm; + } + return this; + } + + @Override + public Object clone() { + MapTerm newTerm = new MapTerm(); + for (Expression e: children) { + newTerm.addChild((Expression) e.clone()); + } + newTerm.keyToIndex = new HashMap(keyToIndex); + return newTerm; + } + + public String toString() { + String mapStr = "{"; + String delim = ""; + for (String key: keyToIndex.keySet()) { + mapStr += delim + Parser.DOUBLE_QUOT + key + Parser.DOUBLE_QUOT + ": " + getChild(keyToIndex.get(key)).toString(); + delim = ", "; + } + return mapStr + "}"; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapType.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapType.java new file mode 100644 index 0000000..b9f3233 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapType.java @@ -0,0 +1,49 @@ +package models.dataConstraintModel; + +import models.algebra.Type; + +public class MapType extends Type { + protected Type keyType = null; + protected Type valueType = null; + + public MapType(String typeName, ITypeImpl implementationType) { + super(typeName, implementationType); + } + + public MapType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType) { + super(typeName, implementationType, interfaceType); + } + + public MapType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentMapType) { + super(typeName, implementationType, interfaceType, parentMapType); + } + + public MapType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type keyType, Type valueType) { + super(typeName, implementationType, interfaceType); + this.keyType = keyType; + this.valueType = valueType; + } + + public MapType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentMapType, Type keyType, Type valueType) { + super(typeName, implementationType, interfaceType, parentMapType); + this.keyType = keyType; + this.valueType = valueType; + } + + public Type getKeyType() { + return keyType; + } + + public void setKeyType(Type keyType) { + this.keyType = keyType; + } + + public Type getValueType() { + return valueType; + } + + public void setValueType(Type valueType) { + this.valueType = valueType; + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/PairType.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/PairType.java new file mode 100644 index 0000000..5e79573 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/PairType.java @@ -0,0 +1,19 @@ +package models.dataConstraintModel; + +import models.algebra.Type; + +public class PairType extends Type { + protected Type componentType = null; + + public PairType(String typeName, ITypeImpl implementationType) { + super(typeName, implementationType); + } + + public Type getComponentType() { + return componentType; + } + + public void setComponentType(Type pairComponentType) { + this.componentType = pairComponentType; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourceHierarchy.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourceHierarchy.java new file mode 100644 index 0000000..9ce7e94 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourceHierarchy.java @@ -0,0 +1,257 @@ +package models.dataConstraintModel; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import models.algebra.Expression; +import models.algebra.Term; +import models.algebra.Type; +import models.algebra.Variable; + +public class ResourceHierarchy { + private ResourceHierarchy parent = null; + private Set children = null; + private String resourceName = null; + private Type resourceStateType = null; + private int numParameters = 0; + protected Expression initialValue; + protected String initText; + protected boolean isNative = false; + + public ResourceHierarchy(String resourceName) { + this.parent = null; + this.children = new HashSet<>(); + this.resourceName = resourceName; + this.numParameters = 0; + } + + public ResourceHierarchy(String resourceName, Type resourceStateType) { + this.parent = null; + this.children = new HashSet<>(); + this.resourceName = resourceName; + this.numParameters = 0; + this.resourceStateType = resourceStateType; + } + + public ResourceHierarchy(ResourceHierarchy parent, String resourceName) { + this.parent = parent; + this.children = new HashSet<>(); + this.resourceName = resourceName; + this.numParameters = 0; + if (parent != null) { + parent.addChild(this); + if (parent.getResourceStateType() == null) { + parent.setResourceStateType(DataConstraintModel.typeJson); + } + } + } + + public ResourceHierarchy(ResourceHierarchy parent, String resourceName, Type resourceStateType) { + this.parent = parent; + this.children = new HashSet<>(); + this.resourceName = resourceName; + this.numParameters = 0; + this.resourceStateType = resourceStateType; + if (parent != null) { + parent.addChild(this); + if (parent.getResourceStateType() == null) { + parent.setResourceStateType(DataConstraintModel.typeJson); + } + } + } + + public ResourceHierarchy(ResourceHierarchy parent, int numParameters) { + this.parent = parent; + this.children = new HashSet<>(); + this.resourceName = null; + this.numParameters = numParameters; + if (parent != null) { + parent.addChild(this); + } + } + + public ResourceHierarchy(ResourceHierarchy parent, Expression parameterExp) { + this.parent = parent; + this.children = new HashSet<>(); + this.resourceName = null; + this.numParameters = 1; + if (parent != null) { + parent.addChild(this); + if (parent.getResourceStateType() == null) { + Type paramType = null; + if (parameterExp instanceof Variable) { + paramType = ((Variable) parameterExp).getType(); + } else if (parameterExp instanceof Term) { + paramType = ((Term) parameterExp).getType(); + } + if (paramType != null) { + if (paramType.equals(DataConstraintModel.typeInt)) { + parent.setResourceStateType(DataConstraintModel.typeList); + } else if (paramType.equals(DataConstraintModel.typeString)) { + parent.setResourceStateType(DataConstraintModel.typeMap); + } + } + } + } + } + + public ResourceHierarchy(ResourceHierarchy parent, Expression parameterExp, Type resourceStateType) { + this.parent = parent; + if (this.children == null) this.children = new HashSet<>(); + this.resourceName = null; + this.numParameters = 1; + this.resourceStateType = resourceStateType; + if (parent != null) { + parent.addChild(this); + if (parent.getResourceStateType() == null) { + Type paramType = null; + if (parameterExp instanceof Variable) { + paramType = ((Variable) parameterExp).getType(); + } else if (parameterExp instanceof Term) { + paramType = ((Term) parameterExp).getType(); + } + if (paramType.equals(DataConstraintModel.typeInt)) { + parent.setResourceStateType(DataConstraintModel.typeList); + } else if (paramType.equals(DataConstraintModel.typeString)) { + parent.setResourceStateType(DataConstraintModel.typeMap); + } + } + } + } + + public ResourceHierarchy(ResourceHierarchy parent, int numParameters, Type resourceStateType) { + this.parent = parent; + if (this.children == null) this.children = new HashSet<>(); + this.resourceName = null; + this.numParameters = numParameters; + this.resourceStateType = resourceStateType; + if (parent != null) { + parent.addChild(this); + } + } + + public ResourceHierarchy getParent() { + return parent; + } + + public void setParent(ResourceHierarchy parent) { + this.parent = parent; + if (parent != null) { + parent.addChild(this); + } + } + + public Set getChildren() { + return children; + } + + protected void addChild(ResourceHierarchy child) { + children.add(child); + } + + public ResourceHierarchy getRoot() { + if (parent == null) return this; + return parent.getRoot(); + } + + public boolean isAncestorOf(ResourceHierarchy another) { + if (another == null) return false; + if (this == another) return true; + return isAncestorOf(another.getParent()); + } + + public String getResourceName() { + if (resourceName == null) return parent.getResourceName(); + return resourceName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + + public Type getResourceStateType() { + return resourceStateType; + } + + public void setResourceStateType(Type resourceStateType) { + this.resourceStateType = resourceStateType; + if (initialValue != null) { + if (initialValue instanceof Term) { + ((Term) initialValue).setType(resourceStateType); + } + } + } + + public int getNumParameters() { + return numParameters; + } + + public int getTotalNumParameters() { + if (parent == null) return numParameters; + return numParameters + parent.getTotalNumParameters(); + } + + public void setNumParameters(int numParameters) { + this.numParameters = numParameters; + } + + public Expression getInitialValue() { + return initialValue; + } + + public void setInitialValue(Expression initialValue) { + this.initialValue = initialValue; + } + + public String getInitText() { + return initText; + } + + public void setInitText(String initText) { + this.initText = initText; + } + + public boolean isNative() { + return isNative; + } + + public void setNative(boolean isNative) { + this.isNative = isNative; + } + + public String toString() { + if (parent == null) return resourceName; + if (resourceName != null) { + return parent.toString() + "." + resourceName; + } else { + return parent.toString() + ".{}"; + } + } + + public String toString(List> pathParams) { + if (parent == null) return resourceName; + if (resourceName != null) { + return parent.toString(pathParams) + "." + resourceName; + } else { + Map.Entry lastParam = pathParams.get(pathParams.size() - 1); + pathParams = pathParams.subList(0, pathParams.size() - 1); + if (lastParam.getValue() == null) { + return parent.toString(pathParams) + ".{" + lastParam.getKey() +"}"; + } + return parent.toString(pathParams) + ".{" + lastParam.getKey() + "=" + lastParam.getValue() +"}"; + } + } + + public String toResourcePath(List pathParams) { + if (parent == null) return resourceName; + if (resourceName != null) { + return parent.toResourcePath(pathParams) + "/" + resourceName; + } else { + String lastParam = pathParams.get(pathParams.size() - 1); + pathParams = pathParams.subList(0, pathParams.size() - 1); + return parent.toResourcePath(pathParams) + "/" + lastParam; + } + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourcePath.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourcePath.java index e530016..bfd163b 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourcePath.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourcePath.java @@ -1,70 +1,210 @@ package models.dataConstraintModel; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.AbstractMap; +import java.util.AbstractMap.SimpleEntry; + import models.algebra.Expression; -import models.algebra.Term; import models.algebra.Type; +import models.algebra.Symbol; +import models.algebra.Term; -public class ResourcePath { - private String resourceName = null; - private Type resourceStateType = null; - private int numParameters = 0; - private Expression initialValue = null; - protected String initText = null; +public class ResourcePath extends Symbol { + protected ResourcePath parent = null; + protected ResourceHierarchy resourceHierarchy = null; + protected List> pathParams = null; + + public ResourcePath(String fullResourceName) { + super(fullResourceName); + this.parent = null; + this.resourceHierarchy = new ResourceHierarchy(null, fullResourceName); + this.pathParams = new ArrayList<>(); + } - public ResourcePath(String resourceName, int numParameters) { - this.resourceName = resourceName; - this.numParameters = numParameters; + public ResourcePath(String fullResourceName, ResourceHierarchy resourceHierarchy) { + super(fullResourceName); + this.parent = null; + this.resourceHierarchy = resourceHierarchy; + this.pathParams = new ArrayList<>(); + } + + public ResourcePath(ResourcePath parent, String leafResourceName) { + super(parent.toString() + "." + leafResourceName); + this.parent = parent; + this.resourceHierarchy = new ResourceHierarchy(parent.getResourceHierarchy(), leafResourceName); + this.pathParams = parent.getPathParamsAndConstraints(); + } + + public ResourcePath(ResourcePath parent, String leafResourceName, ResourceHierarchy resourceHierarchy) { + super(parent.toString() + "." + leafResourceName); + this.parent = parent; + this.resourceHierarchy = resourceHierarchy; + this.pathParams = parent.getPathParamsAndConstraints(); + } + + public ResourcePath(ResourcePath parent, Expression exp) { + super(parent.toString() + ".{" + exp + "}"); + this.parent = parent; + this.resourceHierarchy = new ResourceHierarchy(parent.getResourceHierarchy(), exp); + this.pathParams = new ArrayList<>(parent.getPathParamsAndConstraints()); + this.pathParams.add(new AbstractMap.SimpleEntry<>(exp, null)); + } + + public ResourcePath(ResourcePath parent, Expression exp, Expression constraint) { + super(parent.toString() + ".{" + exp + "=" + constraint + "}"); + this.parent = parent; + this.resourceHierarchy = new ResourceHierarchy(parent.getResourceHierarchy(), exp); + this.pathParams = new ArrayList<>(parent.getPathParamsAndConstraints()); + this.pathParams.add(new AbstractMap.SimpleEntry<>(exp, constraint)); + } + + public ResourcePath(ResourcePath parent, Expression exp, ResourceHierarchy resourceHierarchy) { + super(parent.toString() + ".{" + exp + "}"); + this.parent = parent; + this.resourceHierarchy = resourceHierarchy; + this.pathParams = new ArrayList<>(parent.getPathParamsAndConstraints()); + this.pathParams.add(new AbstractMap.SimpleEntry<>(exp, null)); + } + + public ResourcePath(ResourcePath parent, Expression exp, Expression constraint, ResourceHierarchy resourceHierarchy) { + super(parent.toString() + ".{" + exp + "=" + constraint + "}"); + this.parent = parent; + this.resourceHierarchy = resourceHierarchy; + this.pathParams = new ArrayList<>(parent.getPathParamsAndConstraints()); + this.pathParams.add(new AbstractMap.SimpleEntry<>(exp, constraint)); + } + + public ResourcePath(ResourcePath another) { + super(another.name); + if (another.parent != null) { + this.parent = new ResourcePath(another.parent); + } else { + this.parent = null; + } + this.resourceHierarchy = another.resourceHierarchy; + this.pathParams = new ArrayList<>(another.getPathParamsAndConstraints()); } - public ResourcePath(String resourceName, Type resourceStateType, int numParameters) { - this.resourceName = resourceName; - this.resourceStateType = resourceStateType; - this.numParameters = numParameters; + public ResourceHierarchy getResourceHierarchy() { + return resourceHierarchy; } - public String getResourceName() { - return resourceName; + public void setResourceHierarchy(ResourceHierarchy resourceHierarchy) { + this.resourceHierarchy = resourceHierarchy; + } + + public String getLeafResourceName() { + return resourceHierarchy.getResourceName(); } public int getNumberOfParameters() { - return numParameters; + return resourceHierarchy.getTotalNumParameters(); } - public Type getResourceStateType() { - return resourceStateType; + public models.algebra.Type getResourceStateType() { + return resourceHierarchy.getResourceStateType(); } - public void setResourceStateType(Type resourceStateType) { - this.resourceStateType = resourceStateType; - if (initialValue != null) { - if (initialValue instanceof Term) { - ((Term) initialValue).setType(resourceStateType); - } + public void setResourceStateType(models.algebra.Type resourceStateType) { + this.resourceHierarchy.setResourceStateType(resourceStateType); + } + + public List getPathParams() { + List params = new ArrayList<>(); + for (Map.Entry paramEnt: this.pathParams) { + params.add(paramEnt.getKey()); + } + return params; + } + + public List> getPathParamsAndConstraints() { + return pathParams; + } + + public void setPathParams(List> pathParams) { + this.pathParams = pathParams; + } + + public void addPathParam(Expression pathParam) { + pathParams.add(new AbstractMap.SimpleEntry<>(pathParam, null)); + } + + public void addPathParamWithConstraint(Expression pathParam, Expression pathConstraint) { + pathParams.add(new AbstractMap.SimpleEntry<>(pathParam, pathConstraint)); + } + + public void replacePathParam(int i, Expression pathParam, Expression pathConstraint) { + if (i < pathParams.size()) { + pathParams.set(i, new AbstractMap.SimpleEntry<>(pathParam, pathConstraint)); + parent.replacePathParam(i, pathParam, pathConstraint); } } - public Expression getInitialValue() { - return initialValue; - } - - public void setInitialValue(Expression initialValue) { - this.initialValue = initialValue; - } - - public void setInitText(String initText) { - this.initText = initText; + public boolean endsWithParam() { + if (resourceHierarchy.getNumParameters() > 0) return true; + return false; } - public String getInitText() { - return initText; - } - - public boolean equals(Object another) { - if (!(another instanceof ResourcePath)) return false; - return resourceName.equals(((ResourcePath) another).resourceName); + public Expression getLastParam() { + if (endsWithParam()) { + return pathParams.get(pathParams.size() - 1).getKey(); + } + return null; } - public int hashCode() { - return resourceName.hashCode(); + public Map.Entry getLastParamAndConstraint() { + if (endsWithParam()) { + return pathParams.get(pathParams.size() - 1); + } + return null; + } + + public ResourcePath getParent() { + return parent; + } + + public ResourcePath getRoot() { + if (parent == null) return this; + return parent.getRoot(); + } + + public ResourcePath getCommonPrefix(ResourcePath another) { + Set ancestors = new HashSet<>(); + while (another != null) { + ancestors.add(another); + another = another.getParent(); + } + ResourcePath curPath = this; + while (!ancestors.contains(curPath)) { + curPath = curPath.getParent(); + if (curPath == null) return null; + } + return curPath; + } + + public boolean isAncestorOf(ResourcePath another) { + Set ancestors = new HashSet<>(); + while (another != null) { + ancestors.add(another); + another = another.getParent(); + } + return ancestors.contains(this); + } + + public String toString() { + return resourceHierarchy.toString(pathParams); + } + + public String toResourcePath() { + List params = new ArrayList<>(); + String[] sideEffects = new String[] {""}; + for (Map.Entry param: pathParams) { + params.add("{" + param.getKey().toString() + "}"); + } + return resourceHierarchy.toResourcePath(params); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Selector.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Selector.java index a29f8e3..f170a07 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Selector.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Selector.java @@ -1,19 +1,19 @@ package models.dataConstraintModel; -import models.algebra.Variable; +import models.algebra.Expression; public class Selector { - private Variable variable = null; + private Expression exp = null; - public Selector(Variable variable) { - this.setVariable(variable); + public Selector(Expression exp) { + this.exp = exp; } - public Variable getVariable() { - return variable; + public Expression getExpression() { + return exp; } - public void setVariable(Variable variable) { - this.variable = variable; + public void setExpression(Expression exp) { + this.exp = exp; } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java index 011045a..997d1f6 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java @@ -3,7 +3,9 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map.Entry; +import java.util.Set; +import models.algebra.Constant; import models.algebra.Expression; import models.algebra.InvalidMessage; import models.algebra.Position; @@ -42,13 +44,24 @@ } public boolean isRightUnary() { - for (Position pos : curStateExpression.getVariables().keySet()) { - if (nextStateExpression.contains(curStateExpression.getVariables().get(pos))) return false; + for (Variable var: curStateExpression.getVariables().values()) { + if (nextStateExpression.contains(var)) return false; } return true; } + + public boolean isRightPartial() { + for (Variable var: curStateExpression.getVariables().values()) { + if (messageExpression.contains(var)) return true; + } + if (isRightUnary()) return false; + for (Variable var: messageExpression.getVariables().values()) { + if (nextStateExpression.contains(var)) return true; + } + return false; + } - public Expression deriveMessageConstraintFor(Expression curStateValue, Expression nextStateValue) throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { + public Expression deriveMessageConstraintFor(Expression curStateValue, Expression nextStateValue, Set substitutedPositions) throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { HashMap> bindings = new HashMap<>(); Expression curStateTerm = getCurStateExpression(); @@ -58,6 +71,9 @@ Position varPos = curStateVarEnt.getKey(); Expression valueCalc = curStateTerm.getInverseMap(curStateValue, varPos); if (valueCalc != null) { + if (valueCalc instanceof Term && !(valueCalc instanceof Constant)) { + valueCalc = ((Term) valueCalc).reduce(); + } ArrayList values = bindings.get(var); if (values == null) { values = new ArrayList(); @@ -87,6 +103,9 @@ Position varPos = nextStateVarEnt.getKey(); Expression valueCalc = nextStateTerm.getInverseMap(nextStateValue, varPos); if (valueCalc != null) { + if (valueCalc instanceof Term) { + valueCalc = ((Term) valueCalc).reduce(); + } ArrayList values = bindings.get(var); if (values == null) { values = new ArrayList(); @@ -97,18 +116,10 @@ } Expression messageTerm = getMessageExpression(); - if (!(messageTerm instanceof Term)) throw new InvalidMessage(); - HashMap messageVars = messageTerm.getVariables(); - for (Variable var: messageVars.values()) { - if (bindings.get(var) != null) { - if (bindings.get(var).size() > 1) throw new ResolvingMultipleDefinitionIsFutureWork(); - messageTerm = ((Term) messageTerm).substitute(var, bindings.get(var).iterator().next()); - } - } - return messageTerm; + return substituteValues(messageTerm, bindings, substitutedPositions); } - public Expression deriveMessageConstraintFor(Expression curStateValue) throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { + public Expression deriveMessageConstraintFor(Expression curStateValue, Set substitutedPositions) throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { HashMap> bindings = new HashMap<>(); Expression curStateTerm = getCurStateExpression(); @@ -118,6 +129,9 @@ Position varPos = curStateVarEnt.getKey(); Expression valueCalc = curStateTerm.getInverseMap(curStateValue, varPos); if (valueCalc != null) { + if (valueCalc instanceof Term && !(valueCalc instanceof Constant)) { + valueCalc = ((Term) valueCalc).reduce(); + } ArrayList values = bindings.get(var); if (values == null) { values = new ArrayList(); @@ -128,12 +142,26 @@ } Expression messageTerm = getMessageExpression(); - if (!(messageTerm instanceof Term)) throw new InvalidMessage(); + return substituteValues(messageTerm, bindings, substitutedPositions); + } + + private Expression substituteValues(Expression messageTerm, HashMap> bindings, Set substitutedPositions) + throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { + if (!(messageTerm instanceof Term) && !(messageTerm instanceof Variable)) throw new InvalidMessage(); HashMap messageVars = messageTerm.getVariables(); - for (Variable var: messageVars.values()) { + for (Entry varEnt: messageVars.entrySet()) { + Variable var = varEnt.getValue(); if (bindings.get(var) != null) { if (bindings.get(var).size() > 1) throw new ResolvingMultipleDefinitionIsFutureWork(); - messageTerm = ((Term) messageTerm).substitute(var, bindings.get(var).iterator().next()); + if (messageTerm instanceof Term) { + substitutedPositions.add(varEnt.getKey()); + messageTerm = ((Term) messageTerm).substitute(var, bindings.get(var).iterator().next()); + } else if (messageTerm instanceof Variable) { + if (messageTerm.equals(var)) { + substitutedPositions.add(new Position()); + return bindings.get(var).iterator().next(); + } + } } } return messageTerm; @@ -150,6 +178,9 @@ Position varPos = curStateVarEnt.getKey(); Expression valueCalc = curStateTerm.getInverseMap(curStateValue, varPos); if (valueCalc != null) { + if (valueCalc instanceof Term && !(valueCalc instanceof Constant)) { + valueCalc = ((Term) valueCalc).reduce(); + } if (bindings.get(var) != null) throw new ResolvingMultipleDefinitionIsFutureWork(); bindings.put(var, valueCalc); } @@ -178,6 +209,9 @@ nextStateTerm = ((Term) nextStateTerm).substitute(var, bindings.get(var)); } } + if (nextStateTerm instanceof Term && !(nextStateTerm instanceof Constant)) { + nextStateTerm = ((Term) nextStateTerm).reduce(); + } return nextStateTerm; } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransitionTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransitionTerm.java new file mode 100644 index 0000000..6baeff1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransitionTerm.java @@ -0,0 +1,12 @@ +package models.dataConstraintModel; + +import models.algebra.Symbol; +import models.algebra.Term; + +public class StateTransitionTerm extends Term { + + public StateTransitionTerm(ResourcePath path) { + super(path); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/TupleType.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/TupleType.java new file mode 100644 index 0000000..a0ed0aa --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/TupleType.java @@ -0,0 +1,44 @@ +package models.dataConstraintModel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import models.algebra.Type; + +public class TupleType extends Type { + protected List componentTypes; + + public TupleType(String typeName, ITypeImpl implementationType) { + super(typeName, implementationType); + this.componentTypes = new ArrayList<>(); + } + + public TupleType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType) { + super(typeName, implementationType, interfaceType); + this.componentTypes = new ArrayList<>(); + } + + public TupleType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentTupleType) { + super(typeName, implementationType, interfaceType, parentTupleType); + this.componentTypes = new ArrayList<>(); + } + + public TupleType(String typeName, code.ast.Type implementationType, code.ast.Type interfaceType, Type parentTupleType, List componentTypes) { + super(typeName, implementationType, interfaceType, parentTupleType); + this.componentTypes = componentTypes; + } + + public List getComponentTypes() { + return componentTypes; + } + + public Type getComponentType(int idx) { + return componentTypes.get(idx); + } + + public void addComponentType(Type componentType) { + componentTypes.add(componentType); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ChannelNode.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ChannelNode.java new file mode 100644 index 0000000..0371ca0 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ChannelNode.java @@ -0,0 +1,60 @@ +package models.dataFlowModel; + +import java.util.HashSet; +import java.util.Set; + +import models.Node; + +public class ChannelNode extends Node { + protected ChannelNode parent = null; + protected Set children = null; + protected DataTransferChannel channel = null; + + public ChannelNode(ChannelNode parent, DataTransferChannel channel) { + this.parent = parent; + this.channel = channel; + this.children = new HashSet<>(); + } + + public ChannelNode getParent() { + return parent; + } + + public Set getChildren() { + return children; + } + + public Set getAncestors(){ + if (parent == null) { + return new HashSet<>(); + } + Set ancestors = parent.getAncestors(); + ancestors.add(parent); + return ancestors; + } + + public Set getDescendants() { + if (children == null) { + return new HashSet<>(); + } + Set descendants = new HashSet<>(); + for (ChannelNode child: children) { + descendants.addAll(child.getDescendants()); + descendants.add(child); + } + return descendants; + } + + public void addChild(ChannelNode child) { + children.add(child); + child.parent = this; + } + + public DataTransferChannel getChannel() { + return channel; + } + + public void setChannel(DataTransferChannel channel) { + this.channel = channel; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowEdge.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowEdge.java index 9de9359..6b35380 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowEdge.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowEdge.java @@ -3,18 +3,23 @@ import models.*; public class DataFlowEdge extends Edge { - protected DataTransferChannel channel = null; + protected boolean channelToResource = false; - public DataFlowEdge(ResourceNode src, ResourceNode dst, DataTransferChannel channel) { + public DataFlowEdge(ResourceNode src, ChannelNode dst) { super(src, dst); - this.channel = channel; + channelToResource = false; } - - public DataTransferChannel getChannel() { - return channel; + + public DataFlowEdge(ChannelNode src, ResourceNode dst) { + super(src, dst); + channelToResource = true; } - - public String toString() { - return channel.getChannelName(); + + public boolean isChannelToResource() { + return channelToResource; } + +// public String toString() { +// return channel.getChannelName(); +// } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java index 2c540ed..a86dc97 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java @@ -1,40 +1,173 @@ package models.dataFlowModel; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import models.DirectedGraph; +import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; public class DataFlowGraph extends DirectedGraph { - protected Map nodeMap = null; + protected Set rootResourceNodes = null; + protected Set rootChannelNodes = null; + protected Map channelNodeMap = null; + protected Map resourceNodeMap = null; public DataFlowGraph() { super(); - nodeMap = new HashMap<>(); + rootResourceNodes = new HashSet<>(); + rootChannelNodes = new HashSet<>(); + channelNodeMap = new HashMap<>(); + resourceNodeMap = new HashMap<>(); } - public void addNode(ResourcePath id) { - if (nodeMap.get(id) == null) { - ResourceNode node = new ResourceNode(id); - addNode(node); - nodeMap.put(id, node); + public ResourceNode addResourceNode(ResourceNode parent, + ResourcePath outSideResource, + DataTransferChannel outSideChannel) { + ResourceNode node = null; + if (outSideResource.getNumberOfParameters() == 0) { + // a global (possibly non-root) resource node + Collection nodes = getResourceNodes(outSideResource.getResourceHierarchy()); + if (nodes.size() > 0) { + node = nodes.iterator().next(); + if (outSideChannel != null) { + // not a terminal node + node.addOutSideResource(outSideChannel, outSideResource); + } + } + } else { + // a channel local resource node + node = resourceNodeMap.get(System.identityHashCode(outSideResource)); } + if (node != null) return node; + node = new ResourceNode(parent, outSideResource, outSideChannel); + addNode(node); + if (parent == null) { + rootResourceNodes.add(node); + } else { + parent.addChild(node); + } + resourceNodeMap.put(System.identityHashCode(outSideResource), node); + return node; + } + + public ResourceNode addTerminalResourceNode(ResourceNode parent, + DataTransferChannel inSideChannel, + ResourcePath inSideResource) { + ResourceNode node = null; + if (inSideResource.getNumberOfParameters() == 0) { + // a global (possibly non-root) terminal resource node + Collection nodes = getResourceNodes(inSideResource.getResourceHierarchy()); + if (nodes.size() > 0) { + node = nodes.iterator().next(); + } + } else { + // a channel local terminal resource node + node = resourceNodeMap.get(System.identityHashCode(inSideResource)); + } + if (node != null) return node; + node = new ResourceNode(parent, inSideResource, inSideChannel, true); + addNode(node); + if (parent == null) { + rootResourceNodes.add(node); + } else { + parent.addChild(node); + } + resourceNodeMap.put(System.identityHashCode(inSideResource), node); + return node; + } + + public ResourceNode addResourceNode(ResourceNode parent, + Map inSide, + Map outSide) { + ResourceNode node = null; + for (ResourcePath outRes: outSide.values()) { + node = resourceNodeMap.get(System.identityHashCode(outRes)); + if (node != null) return node; + } + for (ResourcePath inRes: inSide.values()) { + node = resourceNodeMap.get(System.identityHashCode(inRes)); + if (node != null) return node; + } + node = new ResourceNode(parent, inSide, outSide); + addNode(node); + if (parent == null) { + rootResourceNodes.add(node); + } else { + parent.addChild(node); + } + for (ResourcePath outRes: outSide.values()) { + resourceNodeMap.put(System.identityHashCode(outRes), node); + } + for (ResourcePath inRes: inSide.values()) { + resourceNodeMap.put(System.identityHashCode(inRes), node); + } + return node; + } + + public ChannelNode addChannelNode(ChannelNode parent, DataTransferChannel ch) { + ChannelNode node = channelNodeMap.get(ch); + if (node != null) return node; + node = new ChannelNode(parent, ch); + addNode(node); + if (parent == null) { + rootChannelNodes.add(node); + } else { + parent.addChild(node); + } + channelNodeMap.put(ch, node); + return node; + } + + public ResourceNode getResourceNode(ResourcePath resPath) { + return resourceNodeMap.get(System.identityHashCode(resPath)); + } + + public ChannelNode getChannelNode(DataTransferChannel channel) { + return channelNodeMap.get(channel); + } + + public Collection getResourceNodes() { + HashSet result = new HashSet<>(resourceNodeMap.values()); + return result; + } + + public Collection getResourceNodes(ResourceHierarchy resourceHierarchy) { + Collection resourceNodes = new ArrayList<>(); + for (ResourceNode rn: resourceNodeMap.values()) { + if (rn.getResourceHierarchy() == resourceHierarchy) { + resourceNodes.add(rn); + } + } + return resourceNodes; } - public void addEdge(ResourcePath in, ResourcePath out, DataTransferChannel dfChannelGen) { - ResourceNode srcNode = nodeMap.get(in); - if (srcNode == null) { - srcNode = new ResourceNode(in); - addNode(srcNode); - nodeMap.put(in, srcNode); - } - ResourceNode dstNode = nodeMap.get(out); - if (dstNode == null) { - dstNode = new ResourceNode(out); - addNode(dstNode); - nodeMap.put(out, dstNode); - } - addEdge(new DataFlowEdge(srcNode, dstNode, dfChannelGen)); + + public Collection getChannelNodes() { + return channelNodeMap.values(); + } + + public Set getRootResourceNodes() { + return rootResourceNodes; + } + + public Set getRootChannelNodes() { + return rootChannelNodes; + } + + public DataFlowEdge addEdge(ResourceNode srcNode, ChannelNode dstNode) { + DataFlowEdge edge =new DataFlowEdge(srcNode, dstNode); + addEdge(edge); + return edge; + } + + public DataFlowEdge addEdge(ChannelNode srcNode, ResourceNode dstNode) { + DataFlowEdge edge = new DataFlowEdge(srcNode, dstNode); + addEdge(edge); + return edge; } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java index b3f3bf0..6ab539a 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java @@ -1,9 +1,14 @@ package models.dataFlowModel; +import java.util.AbstractMap; import java.util.HashMap; import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; +import models.algebra.Constant; import models.algebra.Expression; import models.algebra.InvalidMessage; import models.algebra.Parameter; @@ -13,7 +18,11 @@ import models.algebra.UnificationFailed; import models.algebra.ValueUndefined; import models.algebra.Variable; -import models.dataConstraintModel.*; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; +import parser.Parser; public class DataTransferChannel extends Channel { protected Set inputChannelMembers = null; @@ -27,15 +36,38 @@ referenceChannelMembers = new HashSet<>(); } + public DataTransferChannel(String channelName, Variable variable) { + super(channelName, variable); + inputChannelMembers = new HashSet<>(); + outputChannelMembers = new HashSet<>(); + referenceChannelMembers = new HashSet<>(); + } + + public DataTransferChannel(String channelName, List variables) { + super(channelName, variables); + inputChannelMembers = new HashSet<>(); + outputChannelMembers = new HashSet<>(); + referenceChannelMembers = new HashSet<>(); + } + public Set getInputChannelMembers() { return inputChannelMembers; } + public Set getAllInputChannelMembers() { + Set allInputChannelMembers = new HashSet<>(); + allInputChannelMembers.addAll(inputChannelMembers); + for (Channel child: children) { + allInputChannelMembers.addAll(((DataTransferChannel) child).getAllInputChannelMembers()); + } + return allInputChannelMembers; + } + public void setInputChannelMembers(Set inputChannelMembers) { this.inputChannelMembers = inputChannelMembers; } - public void addInputChannelMember(ChannelMember inputChannelMember) { + private void addInputChannelMember(ChannelMember inputChannelMember) { inputChannelMembers.add(inputChannelMember); } @@ -47,7 +79,7 @@ this.outputChannelMembers = outputChannelMembers; } - public void addOutputChannelMember(ChannelMember outputChannelMember) { + private void addOutputChannelMember(ChannelMember outputChannelMember) { outputChannelMembers.add(outputChannelMember); } @@ -59,23 +91,23 @@ this.referenceChannelMembers = referenceChannelMembers; } - public void addReferenceChannelMember(ChannelMember referenceChannelMember) { + private void addReferenceChannelMember(ChannelMember referenceChannelMember) { referenceChannelMembers.add(referenceChannelMember); } - public void addChannelMemberAsInput(ChannelMember groupDependentResource) { - addChannelMember(groupDependentResource); - addInputChannelMember(groupDependentResource); + public void addChannelMemberAsInput(ChannelMember inputChannelMember) { + addChannelMember(inputChannelMember); + addInputChannelMember(inputChannelMember); } - public void addChannelMemberAsOutput(ChannelMember groupDependentResource) { - addChannelMember(groupDependentResource); - addOutputChannelMember(groupDependentResource); + public void addChannelMemberAsOutput(ChannelMember outputChannelMember) { + addChannelMember(outputChannelMember); + addOutputChannelMember(outputChannelMember); } - public void addChannelMemberAsReference(ChannelMember groupDependentResource) { - addChannelMember(groupDependentResource); - addReferenceChannelMember(groupDependentResource); + public void addChannelMemberAsReference(ChannelMember referenceChannelMember) { + addChannelMember(referenceChannelMember); + addReferenceChannelMember(referenceChannelMember); } public void removeChannelMember(ResourcePath id) { @@ -142,8 +174,8 @@ HashMap nextStateParams = new HashMap<>(); @Override - public Expression getCurrentStateAccessorFor(ResourcePath target, ResourcePath from) { - String resource = target.getResourceName(); + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + String resource = target.getResource().getLeafResourceName(); Parameter curStateParam = curStateParams.get(resource); if (curStateParam == null) { curStateParam = new Parameter("cur" + resource); @@ -153,72 +185,283 @@ } @Override - public Expression getNextStateAccessorFor(ResourcePath target, ResourcePath from) { - String resource = target.getResourceName(); + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + String resource = target.getResource().getLeafResourceName(); Parameter nextStateParam = nextStateParams.get(resource); if (nextStateParam == null) { - nextStateParam = new Parameter("next" + resource); + nextStateParam = new Parameter("next" + target); nextStateParams.put(resource, nextStateParam); } return nextStateParam; } + + @Override + public Expression getDirectStateAccessorFor(ResourcePath target, ResourcePath from) { + String resource = target.getLeafResourceName(); + Parameter curStateParam = curStateParams.get(resource); + if (curStateParam == null) { + curStateParam = new Parameter("cur" + resource); + curStateParams.put(resource, curStateParam); + } + return curStateParam; + } }; - return deriveUpdateExpressionOf(targetMember, defaultStateAccessor); + return deriveUpdateExpressionOf(targetMember, defaultStateAccessor).getKey(); } /** - * Derive the update expression of the state of the target channel member with a given resource state accessor. + * Derive the state update calculation of the target channel member with a given resource push/pull state accessor. * @param targetMember a channel member whose state is to be updated - * @param stateAccessor a resource state accessor - * @return the derived update expression + * @param stateAccessor a push/pull resource state accessor + * @return the derived update calculation and the unified message * @throws ParameterizedIdentifierIsFutureWork * @throws ResolvingMultipleDefinitionIsFutureWork * @throws InvalidMessage * @throws UnificationFailed * @throws ValueUndefined */ - public Expression deriveUpdateExpressionOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor) + public Map.Entry deriveUpdateExpressionOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor) throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { return deriveUpdateExpressionOf(targetMember, stateAccessor, null); } - public Expression deriveUpdateExpressionOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor, HashMap inputResourceToStateAccessor) + /** + * Derive the state update calculation of the target channel member with a given resource push/pull state accessor. + * @param targetMember a channel member whose state is to be updated + * @param stateAccessor a push/pull resource state accessor + * @param inputResourceToStateAccessor push/pull resource state accessors (if null, stateAccessor is used.) + * @return the derived update calculation and the unified message + * @throws ParameterizedIdentifierIsFutureWork + * @throws ResolvingMultipleDefinitionIsFutureWork + * @throws InvalidMessage + * @throws UnificationFailed + * @throws ValueUndefined + */ + public Map.Entry deriveUpdateExpressionOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor, Map inputResourceToStateAccessor) throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { if (!getOutputChannelMembers().contains(targetMember)) return null; - HashSet messageConstraints = new HashSet<>(); + + // Calculate unified message constraints + Map> substitutedPositionsFromChannels = new HashMap<>(); + Term unifiedMessage = calcUnifiedMessage(targetMember, stateAccessor, inputResourceToStateAccessor, substitutedPositionsFromChannels); + + // Calculate the next state of target resource from the unified message and the current resource state + Expression curOutputStateAccessor = stateAccessor.getCurrentStateAccessorFor(targetMember, targetMember); + if (unifiedMessage == null) { + // for IOChannel + if (targetMember.getStateTransition().getMessageExpression() instanceof Term) { + unifiedMessage = (Term) targetMember.getStateTransition().getMessageExpression(); + } + } + return new AbstractMap.SimpleEntry<>(targetMember.getStateTransition().deriveNextStateExpressionFor(curOutputStateAccessor, unifiedMessage), unifiedMessage); + } + + /** + * Derive the state update calculation of the target channel member with a message and a given resource push/pull state accessor. + * @param targetMember a channel member whose state is to be updated + * @param message a message on the channel + * @param stateAccessor a push/pull resource state accessor + * @return the derived update calculation + * @throws ParameterizedIdentifierIsFutureWork + * @throws ResolvingMultipleDefinitionIsFutureWork + * @throws InvalidMessage + * @throws UnificationFailed + * @throws ValueUndefined + */ + public Expression deriveUpdateExpressionOf(ChannelMember targetMember, Term message, IResourceStateAccessor stateAccessor) + throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { + if (!getOutputChannelMembers().contains(targetMember)) return null; + + // Calculate the next state of target resource from the unified message and the current resource state + Expression curOutputStateAccessor = stateAccessor.getCurrentStateAccessorFor(targetMember, targetMember); + return targetMember.getStateTransition().deriveNextStateExpressionFor(curOutputStateAccessor, message); + } + + /** + * Fill outside resource paths with a given resource push/pull state accessor. + * @param targetMember a channel member whose state is to be updated + * @param stateAccessor a push/pull resource state accessor + * @return map from a depending channel member to the pair of the filled resource path and the set of the depended channel members + * @throws ParameterizedIdentifierIsFutureWork + * @throws ResolvingMultipleDefinitionIsFutureWork + * @throws InvalidMessage + * @throws UnificationFailed + * @throws ValueUndefined + */ + public Map>> fillOutsideResourcePaths(ChannelMember targetMember, IResourceStateAccessor stateAccessor) + throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { + if (!getOutputChannelMembers().contains(targetMember)) return null; + return fillOutsideResourcePaths(targetMember, stateAccessor, null).getKey(); + } + + /** + * Fill outside resource paths with a given resource push/pull state accessor. + * @param targetMember a channel member whose state is to be updated + * @param stateAccessor a push/pull resource state accessor + * @param inputResourceToStateAccessor push/pull resource state accessors (if null, stateAccessor is used.) + * @return map from a depending channel member to the pair of the filled resource path and the set of the depended channel members + * @throws ParameterizedIdentifierIsFutureWork + * @throws ResolvingMultipleDefinitionIsFutureWork + * @throws InvalidMessage + * @throws UnificationFailed + * @throws ValueUndefined + */ + public Map.Entry>>, Term> fillOutsideResourcePaths(ChannelMember targetMember, IResourceStateAccessor stateAccessor, Map inputResourceToStateAccessor) + throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { + Map>> resourcePaths = new HashMap<>(); + + // Calculate unified message constraints from input and reference state transitions + Map> substitutedPositionsInMessageFromChannels = new HashMap<>(); + Term unifiedMessage = calcUnifiedMessage(targetMember, stateAccessor, inputResourceToStateAccessor, substitutedPositionsInMessageFromChannels); + + // Fill outside resource paths + if (unifiedMessage != null) { + for (ChannelMember cm: getInputChannelMembers()) { + if (cm.isOutside()) { + Set dependingVarPosInMessage = new HashSet<>(); + ResourcePath filledResPath = fillOutsideResourcePath(cm.getResource(), unifiedMessage, targetMember.getStateTransition().getMessageExpression(), dependingVarPosInMessage); + Set dependingChannelMembers = new HashSet<>(); + for (ChannelMember otherCm: substitutedPositionsInMessageFromChannels.keySet()) { + for (Position otherPos: substitutedPositionsInMessageFromChannels.get(otherCm)) { + for (Position thisPos: dependingVarPosInMessage) { + if (thisPos.isAncestorOf(otherPos)) { + dependingChannelMembers.add(otherCm); + break; + } + } + if (dependingChannelMembers.contains(otherCm)) break; + } + } + resourcePaths.put(cm, new AbstractMap.SimpleEntry<>(filledResPath, dependingChannelMembers)); + } + } + for (ChannelMember cm: getReferenceChannelMembers()) { + if (cm.isOutside()) { + Set dependingVarPosInMessage = new HashSet<>(); + ResourcePath filledResPath = fillOutsideResourcePath(cm.getResource(), unifiedMessage, targetMember.getStateTransition().getMessageExpression(), dependingVarPosInMessage); + Set dependingChannelMembers = new HashSet<>(); + for (ChannelMember otherCm: substitutedPositionsInMessageFromChannels.keySet()) { + for (Position otherPos: substitutedPositionsInMessageFromChannels.get(otherCm)) { + for (Position thisPos: dependingVarPosInMessage) { + if (thisPos.isAncestorOf(otherPos)) { + dependingChannelMembers.add(otherCm); + break; + } + } + if (dependingChannelMembers.contains(otherCm)) break; + } + } + resourcePaths.put(cm, new AbstractMap.SimpleEntry<>(filledResPath, dependingChannelMembers)); + } + } + for (ChannelMember cm: getOutputChannelMembers()) { + if (cm.isOutside()) { + Set dependingVarPosInMessage = new HashSet<>(); + ResourcePath filledResPath = fillOutsideResourcePath(cm.getResource(), unifiedMessage, targetMember.getStateTransition().getMessageExpression(), dependingVarPosInMessage); + Set dependingChannelMembers = new HashSet<>(); + for (ChannelMember otherCm: substitutedPositionsInMessageFromChannels.keySet()) { + for (Position otherPos: substitutedPositionsInMessageFromChannels.get(otherCm)) { + for (Position thisPos: dependingVarPosInMessage) { + if (thisPos.isAncestorOf(otherPos)) { + dependingChannelMembers.add(otherCm); + break; + } + } + if (dependingChannelMembers.contains(otherCm)) break; + } + } + resourcePaths.put(cm, new AbstractMap.SimpleEntry<>(filledResPath, dependingChannelMembers)); + } + } + } + return new AbstractMap.SimpleEntry<>(resourcePaths, unifiedMessage); + } + + /** + * Get the dependency from the values of the 'path parameters' of a channel member to the state values of other channel members. + * + * @return a map from a depending channel member to depended channel members + */ + public Map> getMemberDependency() { + Map> dependency = new HashMap<>(); + + // Collect depended channel members and their positions in the message + Map> substitutedPositionsInMessage = getDependedChannelMembersAndTheirPositionsInMessage(); + + // Resolve dependency for each outside resource path + if (substitutedPositionsInMessage != null) { + for (ChannelMember cm: getInputChannelMembers()) { + if (cm.isOutside()) { + Set dependingVarPosInMessage = getPossitionsInMessageThatChannelMemberDependsOn(cm.getResource(), cm.getStateTransition().getMessageExpression()); + Set dependingChannelMembers = new HashSet<>(); + for (ChannelMember otherCm: substitutedPositionsInMessage.keySet()) { + for (Position otherPos: substitutedPositionsInMessage.get(otherCm)) { + for (Position thisPos: dependingVarPosInMessage) { + if (thisPos.isAncestorOf(otherPos) && otherCm != cm) { + dependingChannelMembers.add(otherCm); + break; + } + } + if (dependingChannelMembers.contains(otherCm)) break; + } + } + dependency.put(cm, dependingChannelMembers); + } + } + for (ChannelMember cm: getReferenceChannelMembers()) { + if (cm.isOutside()) { + Set dependingVarPosInMessage = getPossitionsInMessageThatChannelMemberDependsOn(cm.getResource(), cm.getStateTransition().getMessageExpression()); + Set dependingChannelMembers = new HashSet<>(); + for (ChannelMember otherCm: substitutedPositionsInMessage.keySet()) { + for (Position otherPos: substitutedPositionsInMessage.get(otherCm)) { + for (Position thisPos: dependingVarPosInMessage) { + if (thisPos.isAncestorOf(otherPos) && otherCm != cm) { + dependingChannelMembers.add(otherCm); + break; + } + } + if (dependingChannelMembers.contains(otherCm)) break; + } + } + dependency.put(cm, dependingChannelMembers); + } + } + for (ChannelMember cm: getOutputChannelMembers()) { + if (cm.isOutside()) { + Set dependingVarPosInMessage = getPossitionsInMessageThatChannelMemberDependsOn(cm.getResource(), cm.getStateTransition().getMessageExpression()); + Set dependingChannelMembers = new HashSet<>(); + for (ChannelMember otherCm: substitutedPositionsInMessage.keySet()) { + for (Position otherPos: substitutedPositionsInMessage.get(otherCm)) { + for (Position thisPos: dependingVarPosInMessage) { + if (thisPos.isAncestorOf(otherPos) && otherCm != cm) { + dependingChannelMembers.add(otherCm); + break; + } + } + if (dependingChannelMembers.contains(otherCm)) break; + } + } + dependency.put(cm, dependingChannelMembers); + } + } + } + return dependency; + } + + private Term calcUnifiedMessage(ChannelMember targetMember, IResourceStateAccessor stateAccessor, + Map inputResourceToStateAccessor, Map> substitutedPositionsInMessageFromChannels) + throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork, UnificationFailed { + Set messageConstraints = new HashSet<>(); // Calculate message constraints from input state transitions for (ChannelMember inputMember: getInputChannelMembers()) { - ResourcePath inputResource = inputMember.getResource(); - if (inputResource.getNumberOfParameters() > 0) { - throw new ParameterizedIdentifierIsFutureWork(); - } - Expression curInputStateAccessor = null; - Expression nextInputStateAccessor = null; - if (inputResourceToStateAccessor == null) { - curInputStateAccessor = stateAccessor.getCurrentStateAccessorFor(inputResource, targetMember.getResource()); - nextInputStateAccessor = stateAccessor.getNextStateAccessorFor(inputResource, targetMember.getResource()); - } else { - curInputStateAccessor = inputResourceToStateAccessor.get(inputResource).getCurrentStateAccessorFor(inputResource, targetMember.getResource()); - nextInputStateAccessor = inputResourceToStateAccessor.get(inputResource).getNextStateAccessorFor(inputResource, targetMember.getResource()); - } - Expression messageConstraintByInput = inputMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor, nextInputStateAccessor); + Expression messageConstraintByInput = calcMessageConstraintForInputMember(inputMember, targetMember, stateAccessor, inputResourceToStateAccessor, substitutedPositionsInMessageFromChannels); messageConstraints.add((Term) messageConstraintByInput); } // Calculate message constraints from reference state transitions for (ChannelMember referenceMember: getReferenceChannelMembers()) { - ResourcePath referenceResource = referenceMember.getResource(); - if (referenceResource.getNumberOfParameters() > 0) { - throw new ParameterizedIdentifierIsFutureWork(); - } - Expression curInputStateAccessor = null; - if (inputResourceToStateAccessor == null) { - curInputStateAccessor = stateAccessor.getCurrentStateAccessorFor(referenceResource, targetMember.getResource()); - } else { - curInputStateAccessor = inputResourceToStateAccessor.get(referenceResource).getCurrentStateAccessorFor(referenceResource, targetMember.getResource()); - } - Expression messageConstraintByReference = referenceMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor); + Expression messageConstraintByReference = calcMessageConstraintForReferenceMember(referenceMember, targetMember, stateAccessor, inputResourceToStateAccessor, substitutedPositionsInMessageFromChannels); messageConstraints.add((Term) messageConstraintByReference); } @@ -234,40 +477,221 @@ } } } - - // Calculate the next state of target resource from the unified message and the current resource state - ResourcePath targetResource = targetMember.getResource(); - if (targetResource.getNumberOfParameters() > 0) { - throw new ParameterizedIdentifierIsFutureWork(); + return unifiedMessage; + } + + public Expression calcMessageConstraintForInputMember(ChannelMember inputMember, ChannelMember targetMember, IResourceStateAccessor stateAccessor, + Map inputResourceToStateAccessor, Map> substitutedPositionsInMessageFromChannels) + throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { + Expression curInputStateAccessor = null; + Expression nextInputStateAccessor = null; + if (inputResourceToStateAccessor == null) { + curInputStateAccessor = stateAccessor.getCurrentStateAccessorFor(inputMember, targetMember); + nextInputStateAccessor = stateAccessor.getNextStateAccessorFor(inputMember, targetMember); + } else { + curInputStateAccessor = inputResourceToStateAccessor.get(inputMember).getCurrentStateAccessorFor(inputMember, targetMember); + nextInputStateAccessor = inputResourceToStateAccessor.get(inputMember).getNextStateAccessorFor(inputMember, targetMember); } - Expression curOutputStateAccessor = stateAccessor.getCurrentStateAccessorFor(targetResource, targetResource); - if (unifiedMessage == null) { - // for IOChannel - if (targetMember.getStateTransition().getMessageExpression() instanceof Term) { - unifiedMessage = (Term) targetMember.getStateTransition().getMessageExpression(); + Set substitutedPositionsInMessage = new HashSet<>(); + Expression messageConstraintByInput = inputMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor, nextInputStateAccessor, substitutedPositionsInMessage); + if (substitutedPositionsInMessage.size() > 0) substitutedPositionsInMessageFromChannels.put(inputMember, substitutedPositionsInMessage); + return messageConstraintByInput; + } + + public Expression calcMessageConstraintForReferenceMember(ChannelMember referenceMember, ChannelMember targetMember, IResourceStateAccessor stateAccessor, + Map inputResourceToStateAccessor, Map> substitutedPositionsInMessageFromChannels) + throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { + Expression curInputStateAccessor = null; + if (inputResourceToStateAccessor == null) { + curInputStateAccessor = stateAccessor.getCurrentStateAccessorFor(referenceMember, targetMember); + } else { + curInputStateAccessor = inputResourceToStateAccessor.get(referenceMember).getCurrentStateAccessorFor(referenceMember, targetMember); + } + Set substitutedPositions = new HashSet<>(); + Expression messageConstraintByReference = referenceMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor, substitutedPositions); + if (substitutedPositions.size() > 0) substitutedPositionsInMessageFromChannels.put(referenceMember, substitutedPositions); + return messageConstraintByReference; + } + + /** + * Get depended channel members and their positions in the message. + * + * @return depended channel members and their positions in the message + */ + private Map> getDependedChannelMembersAndTheirPositionsInMessage() { + Map> channelMembersMessageDependsOn = new HashMap<>(); + // Collect channel members that the message depends on from input state transitions + for (ChannelMember inputMember: getInputChannelMembers()) { + Set substitutedPositionsInMessage = new HashSet<>(); + Expression messageTerm = inputMember.getStateTransition().getMessageExpression(); + Expression curStateTerm = inputMember.getStateTransition().getCurStateExpression(); + Expression nextStateTerm = inputMember.getStateTransition().getNextStateExpression(); + HashMap messageVars = messageTerm.getVariables(); + for (Entry varEnt: messageVars.entrySet()) { + Variable var = varEnt.getValue(); + if (curStateTerm.getVariables().values().contains(var) || nextStateTerm.getVariables().values().contains(var)) { + if (messageTerm instanceof Term) { + substitutedPositionsInMessage.add(varEnt.getKey()); + } else if (messageTerm instanceof Variable) { + if (messageTerm.equals(var)) { + substitutedPositionsInMessage.add(new Position()); + } + } + } + } + if (substitutedPositionsInMessage.size() > 0) channelMembersMessageDependsOn.put(inputMember, substitutedPositionsInMessage); + } + + // Collect channel members that the message depends on from reference state transitions + for (ChannelMember referenceMember: getReferenceChannelMembers()) { + Set substitutedPositionsInMessage = new HashSet<>(); + Expression messageTerm = referenceMember.getStateTransition().getMessageExpression(); + Expression curStateTerm = referenceMember.getStateTransition().getCurStateExpression(); +// Expression nextStateTerm = referenceMember.getStateTransition().getNextStateExpression(); + HashMap messageVars = messageTerm.getVariables(); + for (Entry varEnt: messageVars.entrySet()) { + Variable var = varEnt.getValue(); + if (curStateTerm.getVariables().values().contains(var)) { + if (messageTerm instanceof Term) { + substitutedPositionsInMessage.add(varEnt.getKey()); + } else if (messageTerm instanceof Variable) { + if (messageTerm.equals(var)) { + substitutedPositionsInMessage.add(new Position()); + } + } + } + } + if (substitutedPositionsInMessage.size() > 0) channelMembersMessageDependsOn.put(referenceMember, substitutedPositionsInMessage); + } + return channelMembersMessageDependsOn; + } + + public ResourcePath fillOutsideResourcePath(ResourcePath resource, Expression unifiedMessage, Expression messageTerm, Set dependingVarPosInMessage) + throws ResolvingMultipleDefinitionIsFutureWork { + ResourcePath filledResourcePath = new ResourcePath(resource); + + Map> bindings = new HashMap<>(); + Map messageVars = messageTerm.getVariables(); + for (Entry messageVarEnt: messageVars.entrySet()) { + Variable var = messageVarEnt.getValue(); + Position varPos = messageVarEnt.getKey(); + Expression valueCalc = unifiedMessage.getSubTerm(varPos); + if (valueCalc != null) { + if (bindings.get(var) != null) throw new ResolvingMultipleDefinitionIsFutureWork(); + bindings.put(var, new AbstractMap.SimpleEntry<>(varPos, valueCalc)); } } - return targetMember.getStateTransition().deriveNextStateExpressionFor(curOutputStateAccessor, unifiedMessage); + + List> dstParams = filledResourcePath.getPathParamsAndConstraints(); + for (int i = 0; i < filledResourcePath.getPathParams().size(); i++) { + Expression pathParam = dstParams.get(i).getKey(); + Expression pathValue = dstParams.get(i).getValue(); + if (pathParam instanceof Variable) { + if (pathValue == null) { + if (bindings.get((Variable) pathParam) != null) { + filledResourcePath.replacePathParam(i, bindings.get((Variable) pathParam).getValue(), null); // Replace a path parameter with a value in the unified message. + dependingVarPosInMessage.add(bindings.get((Variable) pathParam).getKey()); // The position of the replaced variable in the message. + } + } else { + // If the path parameter has a constraint. + if (pathValue instanceof Term) { + Map pathValueVars = ((Term) pathValue).getVariables(); + for (Variable var: bindings.keySet()) { + if (pathValueVars.values().contains(var)) { // var is a subterm of a path parameter + pathValue = ((Term) pathValue).substitute(var, bindings.get(var).getValue()); // Substitute a value in the unified message to var. + dependingVarPosInMessage.add(bindings.get((Variable) var).getKey()); // The position of the replaced variable in the message. + } + } + if (!(pathValue instanceof Constant)) { + pathValue = ((Term) pathValue).reduce(); + } + filledResourcePath.replacePathParam(i, pathValue, null); // Replace a path parameter with the substituted term. + } + } + } else if (pathParam instanceof Term) { + Map pathParamVars = ((Term) pathParam).getVariables(); + for (Variable var: bindings.keySet()) { + if (pathParamVars.values().contains(var)) { // var is a subterm of a path parameter + pathParam = ((Term) pathParam).substitute(var, bindings.get(var).getValue()); // Substitute a value in the unified message to var. + dependingVarPosInMessage.add(bindings.get((Variable) var).getKey()); // The position of the replaced variable in the message. + } + } + if (!(pathParam instanceof Constant)) { + pathParam = ((Term) pathParam).reduce(); + } + filledResourcePath.replacePathParam(i, pathParam, null); // Replace a path parameter with the substituted term. + } + } + return filledResourcePath; + } + + private Set getPossitionsInMessageThatChannelMemberDependsOn(ResourcePath resourcePath, Expression messageTerm) { + Set dependingVarPosInMessage = new HashSet<>(); + Map messageVars = messageTerm.getVariables(); + for (Map.Entry pathParamEnt: resourcePath.getPathParamsAndConstraints()) { + Expression pathParam = pathParamEnt.getKey(); + if (pathParam instanceof Variable) { + for (Entry messageVarEnt: messageVars.entrySet()) { + Variable var = messageVarEnt.getValue(); + Position varPos = messageVarEnt.getKey(); + if (pathParam.equals(var)) { + dependingVarPosInMessage.add(varPos); + } + } + } else if (pathParam instanceof Term) { + Map pathParamVars = ((Term) pathParam).getVariables(); + for (Entry messageVarEnt: messageVars.entrySet()) { + Variable var = messageVarEnt.getValue(); + Position varPos = messageVarEnt.getKey(); + if (pathParamVars.values().contains(var)) { + dependingVarPosInMessage.add(varPos); + } + } + } + } + return dependingVarPosInMessage; } @Override public String toString() { - String channelSource = "channel " + getChannelName() + " {\n"; + String channelSource = ""; + if (isNative()) { + channelSource += Parser.NATIVE + " "; + } + if (parent == null) { + channelSource += Parser.CHANNEL + " " + getChannelName(); + } else { + channelSource += Parser.SUB_CHANNEL + " " + getChannelName(); + } + if (getSelectors().size() > 0) { + channelSource += "("; + String delimitor = ""; + for (Selector selector: getSelectors()) { + channelSource += delimitor + selector.getExpression().toString(); + delimitor = ", "; + } + channelSource += ")"; + } + channelSource += " {\n"; for (ChannelMember inputMember: inputChannelMembers) { - channelSource += "\t in " + inputMember + "\n"; + channelSource += "\t " + Parser.IN + " " + inputMember + "\n"; } for (ChannelMember refMember: referenceChannelMembers) { - channelSource += "\t ref " + refMember + "\n"; + channelSource += "\t " + Parser.REF + " " + refMember + "\n"; } for (ChannelMember outputMember: outputChannelMembers) { - channelSource += "\t out " + outputMember + "\n"; + channelSource += "\t " + Parser.OUT + " " + outputMember + "\n"; + } + for (Channel childCh: getChildren()) { + channelSource += childCh.toString(); } channelSource += "}\n"; return channelSource; } public interface IResourceStateAccessor { - Expression getCurrentStateAccessorFor(ResourcePath target, ResourcePath from); - Expression getNextStateAccessorFor(ResourcePath target, ResourcePath from); + Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from); + Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from); + Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferModel.java index db43b80..ad92b74 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferModel.java @@ -1,31 +1,304 @@ package models.dataFlowModel; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; import java.util.Set; import models.dataConstraintModel.Channel; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; public class DataTransferModel extends DataConstraintModel { public DataFlowGraph getDataFlowGraph() { DataFlowGraph dataFlowGraph = new DataFlowGraph(); + Map>> channelLocalResMap = new HashMap<>(); for (Channel channel: getChannels()) { - DataTransferChannel dfChannel = (DataTransferChannel)channel; - Set inputResources = dfChannel.getInputResources(); - Set outputResources = dfChannel.getOutputResources(); - for (ResourcePath in: inputResources) { - for (ResourcePath out: outputResources) { - dataFlowGraph.addEdge(in ,out, dfChannel); - } - } + addResourceToChannelEdges(dataFlowGraph, channel, null, channelLocalResMap); } - for (Channel channel: getIOChannels()) { - DataTransferChannel dfChannel = (DataTransferChannel)channel; - Set outputResources = dfChannel.getOutputResources(); - for (ResourcePath out: outputResources) { - dataFlowGraph.addNode(out); - } + for (Channel channel: getChannels()) { + addReferenceResources(dataFlowGraph, channel, null, channelLocalResMap); + } + for (Channel channel: getChannels()) { + addChannelToResourceEdges(dataFlowGraph, channel, null, channelLocalResMap); + } + for (Channel channel: getInputChannels()) { + addChannelToResourceEdges(dataFlowGraph, channel, null, channelLocalResMap); } return dataFlowGraph; } + + private void addResourceToChannelEdges(DataFlowGraph dataFlowGraph, Channel dstChannel, ChannelNode parentChannelNode, + Map>> channelLocalResMap) { + DataTransferChannel dstDfChannel = (DataTransferChannel) dstChannel; + ChannelNode dstChannelNode = dataFlowGraph.addChannelNode(parentChannelNode, dstDfChannel); + for (ResourcePath srcRes: dstDfChannel.getInputResources()) { + Map> chLocalResNodes = channelLocalResMap.get(srcRes.getResourceHierarchy()); + if (srcRes.getNumberOfParameters() == 0) { + // ResourcePath without parameter corresponds to a global ResourceNode. + ResourceNode srcResNode = addResourceNodes(dataFlowGraph, srcRes, dstDfChannel, channelLocalResMap, false); + dataFlowGraph.addEdge(srcResNode, dstChannelNode); + } else { + if (chLocalResNodes == null || chLocalResNodes.get(dstChannel) == null) { + // There is no channel-local ResourcePath. + // Then, create a new channel-local ResourceNode. + ResourceNode srcResNode = addResourceNodes(dataFlowGraph, srcRes, dstDfChannel, channelLocalResMap, false); + dataFlowGraph.addEdge(srcResNode, dstChannelNode); + } else { + // There already has been a channel-local ResourceNode. + Set nodes = chLocalResNodes.get(dstChannel); // channel-local ResourceNodes. + boolean bExists = false; + for (ResourceNode node: nodes) { + ResourcePath r = node.getOutSideResource(dstDfChannel); + if (r.toString().equals(srcRes.toString())) { + bExists = true; // There exists a textually identical ResourecPath within the same channel. + break; + } + } + if (!bExists) { + // Create a new channel-local ResourceNode. + ResourceNode srcResNode = addResourceNodes(dataFlowGraph, srcRes, dstDfChannel, channelLocalResMap, false); + dataFlowGraph.addEdge(srcResNode, dstChannelNode); + } + } + } + } + for (Channel childChannel: dstDfChannel.getChildren()) { + addResourceToChannelEdges(dataFlowGraph, childChannel, dstChannelNode, channelLocalResMap); + } + } + + private void addReferenceResources(DataFlowGraph dataFlowGraph, Channel dstChannel, ChannelNode parentChannelNode, + Map>> channelLocalResMap) { + DataTransferChannel dstDfChannel = (DataTransferChannel) dstChannel; + ChannelNode dstChannelNode = dataFlowGraph.addChannelNode(parentChannelNode, dstDfChannel); + for (ResourcePath srcRes: dstDfChannel.getReferenceResources()) { + Map> chLocalResNodes = channelLocalResMap.get(srcRes.getResourceHierarchy()); + if (srcRes.getNumberOfParameters() == 0) { + // ResourcePath without parameter corresponds to a global ResourceNode. + ResourceNode srcResNode = addResourceNodes(dataFlowGraph, srcRes, dstDfChannel, channelLocalResMap, false); + } else { + if (chLocalResNodes == null) { + // There is no channel-local ResourcePath. + // Then, create a new channel-local ResourceNode. + ResourceNode srcResNode = addResourceNodes(dataFlowGraph, srcRes, dstDfChannel, channelLocalResMap, false); + } else { + boolean bExists = false; + for (Channel ch: chLocalResNodes.keySet()) { + Set nodes = chLocalResNodes.get(ch); + for (ResourceNode node: nodes) { + ResourcePath r = node.getOutSideResource((DataTransferChannel) ch); + if (r.toString().equals(srcRes.toString())) { + bExists = true; // There exists the same ResourecPath within some channel. + break; + } + } + } + if (!bExists) { + // Create a new channel-local ResourceNode. + ResourceNode srcResNode = addResourceNodes(dataFlowGraph, srcRes, dstDfChannel, channelLocalResMap, false); + } + } + } + } + for (Channel childChannel: dstDfChannel.getChildren()) { + addReferenceResources(dataFlowGraph, childChannel, dstChannelNode, channelLocalResMap); + } + } + + private void addChannelToResourceEdges(DataFlowGraph dataFlowGraph, Channel srcChannel, ChannelNode parentChannelNode, + Map>> channelLocalResMap) { + DataTransferChannel srcDfChannel = (DataTransferChannel) srcChannel; + ChannelNode srcChannelNode = dataFlowGraph.addChannelNode(parentChannelNode, srcDfChannel); + for (ResourcePath dstRes: srcDfChannel.getOutputResources()) { + Map> chLocalResNodes = channelLocalResMap.get(dstRes.getResourceHierarchy()); // ResourceNodes that have the same ResourceHierarchy. + Set dstResSet = new HashSet<>(); + if (dstRes.getNumberOfParameters() == 0) { + // ResourcePath without parameter corresponds to a global ResourceNode. + if (chLocalResNodes == null) { + // Create a new global terminal ResourceNode. + ResourceNode dstResNode = addResourceNodes(dataFlowGraph, dstRes, srcDfChannel, channelLocalResMap, true); + dstResSet.add(dstResNode); + } else { + // Select all (usually one) global ResourceNodes. + for (Set resSet: chLocalResNodes.values()) { + dstResSet.addAll(resSet); + } + } + } else { + if (chLocalResNodes == null) { + // There is no corresponding ResourceNode. + // Create a new channel-local terminal ResourceNode. + ResourceNode dstResNode = addResourceNodes(dataFlowGraph, dstRes, srcDfChannel, channelLocalResMap, true); + dstResSet.add(dstResNode); + } else { + if (chLocalResNodes.get(srcDfChannel) == null) { + // Select all non-terminal ResourceNodes. + for (Set resSet: chLocalResNodes.values()) { + dstResSet.addAll(resSet); + } + } else { + // There already has been a channel-local terminal ResourceNode. + if (chLocalResNodes.size() > 0) { + // There already has been a channel-local ResourceNode. + for (Set resNodes: chLocalResNodes.values()) { + for (ResourceNode localResNode: resNodes) { + for (ResourcePath localResPath: localResNode.getInSideResources()) { + if (localResPath.toString().equals(dstRes.toString())) { + // Channel-local ResourcePath should be identical, and the identical ResourcePath is selected on top priority. + dstResSet.add(localResNode); + } + } + } + } + } + // Search a common channel-local ancestor. + if (dstResSet.size() == 0) { + ResourcePath dstParent = dstRes.getParent(); + while (dstParent != null && dstParent.getNumberOfParameters() > 0) { + Map> chToLocalDstNodes = channelLocalResMap.get(dstParent.getResourceHierarchy()); + if (chToLocalDstNodes != null) { + for (Channel dstCh: chToLocalDstNodes.keySet()) { + for (ResourceNode localParentNode: chToLocalDstNodes.get(dstCh)) { + for (ResourcePath localParentPath: localParentNode.getInSideResources()) { + if (localParentPath.toString().equals(dstParent.toString())) { + // There already has been a common channel-local ancestor. + ResourceNode dstResNode = addResourceNodes(dataFlowGraph, dstRes, (DataTransferChannel)dstCh, channelLocalResMap, false); + dstResSet.add(dstResNode); + break; + } + } + if (dstResSet.size() > 0) break; + } + if (dstResSet.size() > 0) break; + } + if (dstResSet.size() > 0) break; + } + dstParent = dstParent.getParent(); + } + } + if (dstResSet.size() == 0) { + for (Set nodes: chLocalResNodes.values()) { + // Select all corresponding ResourceNodes. + dstResSet.addAll(nodes); + } + } + if (dstResSet.size() == 0) { + // Otherwise create a new ResourceNode. + ResourceNode dstResNode = addResourceNodes(dataFlowGraph, dstRes, srcDfChannel, channelLocalResMap, false); + dstResSet.add(dstResNode); + } + } + } + } + for (ResourceNode dstResNode: dstResSet) { + dstResNode.addInSideResource(srcDfChannel, dstRes); + dataFlowGraph.addEdge(srcChannelNode, dstResNode); // Connect to each ResourceNode that has the same ResourceHierarchy. + } + } + for (Channel childChannel: srcDfChannel.getChildren()) { + addChannelToResourceEdges(dataFlowGraph, childChannel, srcChannelNode, channelLocalResMap); + } + } + + private ResourceNode addResourceNodes(DataFlowGraph dataFlowGraph, ResourcePath resPath, DataTransferChannel dfChannel, + Map>> channelLocalResMap, boolean isTerminal) { + ResourceNode resNode = null; + if (resPath.getParent() == null) { + if (!isTerminal) { + resNode = dataFlowGraph.addResourceNode(null, resPath, dfChannel); + } else { + resNode = dataFlowGraph.addTerminalResourceNode(null, dfChannel, resPath); + } + } else { + // Search an identical parent ResourceNode. + ResourceNode parent = null; + DataTransferChannel parentDfChannel = dfChannel; + if (resPath.getResourceHierarchy().getParent().getNumParameters() == 0) { + parentDfChannel = null; + } + if (channelLocalResMap.get(resPath.getResourceHierarchy().getParent()) != null) { + Set chLocalNodes = channelLocalResMap.get(resPath.getResourceHierarchy().getParent()).get(parentDfChannel); + if (chLocalNodes != null) { + for (ResourceNode node: chLocalNodes) { + for (ResourcePath r: node.getOutSideResources()) { + if (r.toString().equals(resPath.getParent().toString())) { + parent = node; + break; + } + } + if (parent != null) break; + for (ResourcePath r: node.getInSideResources()) { + if (r.toString().equals(resPath.getParent().toString())) { + parent = node; + break; + } + } + if (parent != null) break; + } + } + } + if (parent == null) { + parent = addResourceNodes(dataFlowGraph, resPath.getParent(), parentDfChannel, channelLocalResMap, false); + } + if (!isTerminal) { + resNode = dataFlowGraph.addResourceNode(parent, resPath, dfChannel); + } else { + resNode = dataFlowGraph.addTerminalResourceNode(parent, dfChannel, resPath); + } + } + Map> chToLocalNodes = channelLocalResMap.get(resPath.getResourceHierarchy()); + if (chToLocalNodes == null) { + chToLocalNodes = new HashMap<>(); + channelLocalResMap.put(resPath.getResourceHierarchy(), chToLocalNodes); + } + Set chLocalNodes = chToLocalNodes.get(dfChannel); + if (chLocalNodes == null) { + chLocalNodes = new HashSet<>(); + chToLocalNodes.put(dfChannel, chLocalNodes); + } + chLocalNodes.add(resNode); + return resNode; + } + +// private ResourceNode addResourceNodes(DataFlowGraph dataFlowGraph, ResourcePath resPath, DataTransferChannel dfChannel, +// Map>> resourceMap) { +// if (resPath.getNumberOfParameters() == 0) { +// // ResourcePath without parameter corresponds to a global ResourceNode. +// dfChannel = null; +// } +// if (resourceMap.get(resPath.getResourceHierarchy()) != null && resourceMap.get(resPath.getResourceHierarchy()).get(dfChannel) != null) { +// Set nodes = resourceMap.get(resPath.getResourceHierarchy()).get(dfChannel); +// for (ResourceNode node: nodes) { +// if (node.getOutSideResource().toString().equals(resPath.toString())) { +// return node; +// } +// for (ResourcePath res: node.getInSideResources()) { +// if (res.toString().toString().equals(resPath.toString())) { +// return node; +// } +// } +// } +// } +// ResourceNode resNode = null; +// if (resPath.getParent() == null) { +// resNode = dataFlowGraph.addResourceNode(null, dfChannel, resPath); +// } else { +// ResourceNode parent = addResourceNodes(dataFlowGraph, resPath.getParent(), dfChannel, resourceMap); +// resNode = dataFlowGraph.addResourceNode(parent, dfChannel, resPath); +// } +// Map> chToNodes = resourceMap.get(resPath.getResourceHierarchy()); +// if (chToNodes == null) { +// chToNodes = new HashMap<>(); +// resourceMap.put(resPath.getResourceHierarchy(), chToNodes); +// } +// Set nodes = chToNodes.get(dfChannel); +// if (nodes == null) { +// nodes = new HashSet<>(); +// chToNodes.put(dfChannel, nodes); +// } +// nodes.add(resNode); +// return resNode; +// } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ModelExtension.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ModelExtension.java index d8aa4af..bff95f8 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ModelExtension.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ModelExtension.java @@ -26,7 +26,7 @@ final int[] count = new int[] {0}; sum.setGenerator(new Symbol.IImplGenerator() { @Override - public String generate(Type type, String[] children, String[] childrenSideEffects, String[] sideEffect) { + public String generate(Type type, Type[] childrenTypes, String[] children, String[] childrenSideEffects, String[] sideEffect) { String compType = "Integer"; if (type != null) { String interfaceType = type.getInterfaceTypeName(); @@ -56,8 +56,8 @@ final int[] count = new int[] {0}; merge.setGenerator(new Symbol.IImplGenerator() { @Override - public String generate(Type type, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { - String implType = "Arrayist<>"; + public String generate(Type type, Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { + String implType = "ArrayList<>"; String interfaceType = "List"; String compType = "Integer"; if (type != null) { @@ -109,7 +109,7 @@ extractFaceDown.setArity(1); extractFaceDown.setGenerator(new Symbol.IImplGenerator() { @Override - public String generate(Type type, String[] children, String[] childrenSideEffects, String[] sideEffect) { + public String generate(Type type, Type[] childrenTypes, String[] children, String[] childrenSideEffects, String[] sideEffect) { return children[0]+".stream().filter(item -> item.getValue()==false).collect(Collectors.toList())"; } }); @@ -124,7 +124,7 @@ sortByKey.setArity(1); sortByKey.setGenerator(new Symbol.IImplGenerator() { @Override - public String generate(Type type, String[] children, String[] childrenSideEffects, String[] sideEffect) { + public String generate(Type type, Type[] childrenTypes, String[] children, String[] childrenSideEffects, String[] sideEffect) { String compType = ""; String temp_sort="temp_sort"; if (type != null) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/PushPullAttribute.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/PushPullAttribute.java index 598894a..ad0da87 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/PushPullAttribute.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/PushPullAttribute.java @@ -20,6 +20,10 @@ public List getOptions() { return options; } + + public PushPullValue getSelectedOption() { + return options.get(0); + } public void setOptions(List options) { this.options = options; @@ -37,6 +41,13 @@ this.options.retainAll(options); } + public boolean selectOption(PushPullValue option) { + if (!options.contains(option)) return false; + options.remove(option); + options.add(0, option); + return true; + } + public String[] getOptionStrings() { String[] optionString = new String[options.size()]; for (int i = 0; i < options.size(); i++) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ReferenceEdge.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ReferenceEdge.java new file mode 100644 index 0000000..c8ff371 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ReferenceEdge.java @@ -0,0 +1,11 @@ +package models.dataFlowModel; + +import models.Edge; + +public class ReferenceEdge extends Edge { + + public ReferenceEdge(ResourceNode src, ResourceNode dst) { + super(src, dst); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java index ef286af..6c56bcb 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java @@ -1,30 +1,205 @@ package models.dataFlowModel; +import java.util.AbstractMap; +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + import models.Node; +import models.algebra.Expression; +import models.algebra.Type; +import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; public class ResourceNode extends Node { - protected ResourcePath resourcePath = null; + protected ResourceNode parent = null; + protected Set children = null; + protected ResourceHierarchy resourceHierarchy = null; + protected ResourcePath primaryResourcePath = null; // for temporal use at the modeling stage + protected Map inSide = null; + protected Map outSide = null; + protected List selectors = null; + + public ResourceNode(ResourceNode parent, ResourcePath primaryResourcePath) { + this.parent = parent; + this.children = new HashSet<>(); + this.inSide = new HashMap<>(); + this.outSide = new HashMap<>(); + this.resourceHierarchy = primaryResourcePath.getResourceHierarchy(); + this.primaryResourcePath = primaryResourcePath; + this.selectors = new ArrayList<>(); + if (resourceHierarchy.getNumParameters() > 0) { + List pathParams = primaryResourcePath.getPathParams(); + selectors.add(new Selector(pathParams.get(pathParams.size() - 1))); + } + } - public ResourceNode(ResourcePath resourcePath) { - this.resourcePath = resourcePath; + public ResourceNode(ResourceNode parent, ResourcePath outSideResource, DataTransferChannel outSideChannel) { + this.parent = parent; + this.children = new HashSet<>(); + this.inSide = new HashMap<>(); + this.outSide = new HashMap<>(); + this.outSide.put(outSideChannel, outSideResource); + this.resourceHierarchy = outSideResource.getResourceHierarchy(); + this.selectors = new ArrayList<>(); + if (resourceHierarchy.getNumParameters() > 0) { + if (outSideChannel != null) { + selectors.addAll(outSideChannel.getSelectors()); + } else { + List pathParams = outSideResource.getPathParams(); + selectors.add(new Selector(pathParams.get(pathParams.size() - 1))); + } + } + } + + public ResourceNode(ResourceNode parent, ResourcePath resource, DataTransferChannel channel, boolean isInside) { + this.parent = parent; + this.children = new HashSet<>(); + this.inSide = new HashMap<>(); + this.outSide = new HashMap<>(); + if (isInside) { + this.inSide.put(channel, resource); + } else { + this.outSide.put(channel, resource); + } + this.resourceHierarchy = resource.getResourceHierarchy(); + this.selectors = new ArrayList<>(); + if (resourceHierarchy.getNumParameters() > 0) { + if (channel != null) { + selectors.addAll(channel.getSelectors()); + } else { + List pathParams = resource.getPathParams(); + selectors.add(new Selector(pathParams.get(pathParams.size() - 1))); + } + } } - public ResourcePath getResource() { - return resourcePath; + public ResourceNode(ResourceNode parent, Map outSide, Map inSide) { + this.parent = parent; + this.children = new HashSet<>(); + this.inSide = inSide; + this.outSide = outSide; + this.selectors = new ArrayList<>(); + for (Map.Entry outsideEnt: outSide.entrySet()) { + DataTransferChannel outSideChannel = outsideEnt.getKey(); + ResourcePath outSideResource = outsideEnt.getValue(); + if (this.resourceHierarchy == null) { + this.resourceHierarchy = outSideResource.getResourceHierarchy(); + } + if (resourceHierarchy.getNumParameters() > 0) { + if (outSideChannel != null) { + selectors.addAll(outSideChannel.getSelectors()); + } else { + List pathParams = outSideResource.getPathParams(); + selectors.add(new Selector(pathParams.get(pathParams.size() - 1))); + } + } + } } - public boolean equals(Object another) { - if (this == another) return true; - if (!(another instanceof ResourceNode)) return false; - return resourcePath.equals(((ResourceNode)another).resourcePath); + public ResourceHierarchy getResourceHierarchy() { + return resourceHierarchy; } - public int hashCode() { - return resourcePath.hashCode(); + public String getResourceName() { + return resourceHierarchy.getResourceName(); } - public String toString() { - return resourcePath.getResourceName(); + public Type getResourceStateType() { + return resourceHierarchy.getResourceStateType(); } + + public int getNumberOfParameters() { + return resourceHierarchy.getTotalNumParameters(); + } + + public ResourceNode getParent() { + return parent; + } + + public Set getChildren() { + return children; + } + + public void addChild(ResourceNode child) { + children.add(child); + child.parent = this; + } + + public ResourcePath getPrimaryResourcePath() { + if (primaryResourcePath != null) return primaryResourcePath; + if (outSide.size() > 0) return outSide.values().iterator().next(); + return inSide.values().iterator().next(); + } + + public Collection getInSideResources() { + return inSide.values(); + } + + public ResourcePath getInSideResource(DataTransferChannel channel) { + return inSide.get(channel); + } + + public Set getInSideChannels() { + return inSide.keySet(); + } + + public Collection getOutSideResources() { + return outSide.values(); + } + + public ResourcePath getOutSideResource(DataTransferChannel channel) { + return outSide.get(channel); + } + + public Set getOutSideChannels() { + return outSide.keySet(); + } + + public void addInSideResource(DataTransferChannel channel, ResourcePath inResource) { + primaryResourcePath = null; + inSide.put(channel, inResource); + } + + public void addOutSideResource(DataTransferChannel channel, ResourcePath outResource) { + primaryResourcePath = null; + outSide.put(channel, outResource); + } + + public List getSelectors() { + return selectors; + } + + public Selector getLastSelector() { + return selectors.get(resourceHierarchy.getTotalNumParameters() - 1); + } + + public List getAllSelectors() { + List selectors = new ArrayList<>(); + if (parent != null) { + selectors.addAll(parent.getAllSelectors()); + } + selectors.addAll(this.selectors); + return selectors; + } + +// public boolean equals(Object another) { +// if (this == another) return true; +// if (!(another instanceof ResourceNode)) return false; +// return resourcePath.equals(((ResourceNode)another).resourcePath); +// } +// +// public int hashCode() { +// return resourcePath.hashCode(); +// } +// +// public String toString() { +// return resourcePath.toString(); +// } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/visualModel/FormulaChannel.java b/AlgebraicDataflowArchitectureModel/src/models/visualModel/FormulaChannel.java index 581d31e..2fb57ee 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/visualModel/FormulaChannel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/visualModel/FormulaChannel.java @@ -32,24 +32,24 @@ // channelMember.setStateTransition(st); super.addChannelMemberAsInput(channelMember); if (formula != null && getInputChannelMembers().size() > 1) { - formula += " " + defaultOperator + " " + channelMember.getResource().getResourceName(); + formula += " " + defaultOperator + " " + channelMember.getResource().getLeafResourceName(); if (formulaRhs != null) { if (formulaRhs instanceof Variable) { Term newTerm = new Term(defaultOperator); newTerm.addChild(formulaRhs); - newTerm.addChild(new Variable(channelMember.getResource().getResourceName()), true); + newTerm.addChild(new Variable(channelMember.getResource().getLeafResourceName()), true); formulaRhs = newTerm; } else if (formulaRhs instanceof Term) { Term newTerm = new Term(defaultOperator); newTerm.addChild(formulaRhs); - newTerm.addChild(new Variable(channelMember.getResource().getResourceName())); + newTerm.addChild(new Variable(channelMember.getResource().getLeafResourceName())); formulaRhs = newTerm; } } } else { if (formula == null) formula = ""; - formula += channelMember.getResource().getResourceName(); - formulaRhs = new Variable(channelMember.getResource().getResourceName()); + formula += channelMember.getResource().getLeafResourceName(); + formulaRhs = new Variable(channelMember.getResource().getLeafResourceName()); } if (formulaRhs != null) { setFormulaTerm(formulaRhs); @@ -63,8 +63,8 @@ super.addChannelMemberAsOutput(channelMember); if (getOutputChannelMembers().size() == 1) { if (formula == null) formula = ""; - if (!formula.contains("==")) { - formula = channelMember.getResource().getResourceName() + " == " + formula; + if (!formula.contains("=")) { + formula = channelMember.getResource().getLeafResourceName() + " = " + formula; } } if (formulaRhs != null) { @@ -96,7 +96,7 @@ Map resToNextVar = new HashMap<>(); for (ChannelMember cm: this.getInputChannelMembers()) { ResourcePath id = cm.getResource(); - String resName = id.getResourceName(); + String resName = id.getLeafResourceName(); Variable curVar = new Variable(resName + "1"); Variable nextVar = new Variable(resName + "2"); curStates.put(id, curVar); @@ -134,7 +134,7 @@ for (ChannelMember cm: getOutputChannelMembers()) { ResourcePath id = cm.getResource(); StateTransition st = new StateTransition(); - String resName = id.getResourceName(); + String resName = id.getLeafResourceName(); Variable curVar = new Variable(resName + "1"); st.setCurStateExpression(curVar); st.setNextStateExpression(rhs); diff --git a/AlgebraicDataflowArchitectureModel/src/parser/Parser.java b/AlgebraicDataflowArchitectureModel/src/parser/Parser.java index 876ee6f..8e2eb56 100644 --- a/AlgebraicDataflowArchitectureModel/src/parser/Parser.java +++ b/AlgebraicDataflowArchitectureModel/src/parser/Parser.java @@ -1,6 +1,5 @@ package parser; -import java.awt.image.DataBufferDouble; import java.io.BufferedReader; import java.io.IOException; import java.util.ArrayList; @@ -14,20 +13,30 @@ import models.algebra.Type; import models.algebra.Variable; import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.JsonAccessor; +import models.dataConstraintModel.JsonTerm; +import models.dataConstraintModel.ListTerm; +import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.StateTransition; +import models.dataConstraintModel.StateTransitionTerm; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.DataTransferChannel; import parser.exceptions.ExpectedAssignment; import parser.exceptions.ExpectedChannel; import parser.exceptions.ExpectedChannelName; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; import parser.exceptions.ExpectedEquals; -import parser.exceptions.ExpectedInOrOutOrRefKeyword; +import parser.exceptions.ExpectedInOrOutOrRefOrSubKeyword; import parser.exceptions.ExpectedLeftCurlyBracket; import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; +import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; public class Parser { @@ -35,6 +44,11 @@ public static final String CHANNEL = "channel"; public static final String INIT = "init"; + public static final String IN = "in"; + public static final String OUT = "out"; + public static final String REF = "ref"; + public static final String SUB_CHANNEL = "for"; + public static final String NATIVE = "native"; public static final String LEFT_CURLY_BRACKET = "{"; public static final String RIGHT_CURLY_BRACKET = "}"; public static final String LEFT_CURLY_BRACKET_REGX = "\\{"; @@ -43,23 +57,37 @@ public static final String RIGHT_BRACKET = ")"; public static final String LEFT_BRACKET_REGX = "\\("; public static final String RIGHT_BRACKET_REGX = "\\)"; + public static final String LEFT_SQUARE_BRACKET = "["; + public static final String RIGHT_SQUARE_BRACKET = "]"; + public static final String LEFT_SQUARE_BRACKET_REGX = "\\["; + public static final String RIGHT_SQUARE_BRACKET_REGX = "\\]"; public static final String ADD = "+"; public static final String MUL = "*"; public static final String SUB = "-"; public static final String DIV = "/"; + public static final String MOD = "%"; public static final String MINUS = "-"; + public static final String EQ = "=="; + public static final String NEQ = "!="; + public static final String GT = ">"; + public static final String LT = "<"; + public static final String GE = ">="; + public static final String LE = "<="; + public static final String AND = "&&"; + public static final String OR = "||"; + public static final String NEG = "!"; public static final String ADD_REGX = "\\+"; public static final String MUL_REGX = "\\*"; public static final String SUB_REGX = "\\-"; public static final String DIV_REGX = "/"; - public static final String IN = "in"; - public static final String OUT = "out"; - public static final String REF = "ref"; - public static final String EQUALS = "=="; + public static final String OR_REGX = "\\|\\|"; + public static final String EQUALS = "="; public static final String ASSIGNMENT = "="; public static final String COMMA = ","; public static final String COLON = ":"; - + public static final String DOT = "."; + public static final String DOT_REGX = "\\."; + public static final String DOUBLE_QUOT = "\""; public Parser(final TokenStream stream) { this.stream = stream; @@ -79,17 +107,21 @@ } public DataTransferModel doParse() - throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment { + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedRightCurlyBracket, + ExpectedInOrOutOrRefOrSubKeyword, ExpectedStateTransition, ExpectedEquals, + ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, WrongPathExpression, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { return parseDataFlowModel(); } public DataTransferModel parseDataFlowModel() - throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment { + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedRightCurlyBracket, + ExpectedInOrOutOrRefOrSubKeyword, ExpectedStateTransition, ExpectedEquals, + ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, WrongPathExpression, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { DataTransferModel model = new DataTransferModel(); DataTransferChannel channel; while ((channel = parseChannel(model)) != null) { - if (channel.getInputChannelMembers().size() == 0) { - model.addIOChannel(channel); + if (channel.getAllInputChannelMembers().size() == 0) { + model.addInputChannel(channel); } else { model.addChannel(channel); } @@ -98,20 +130,29 @@ } public DataTransferChannel parseChannel(DataTransferModel model) - throws - ExpectedLeftCurlyBracket, ExpectedRightBracket, ExpectedAssignment, - ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, - ExpectedChannel, ExpectedChannelName, ExpectedInOrOutOrRefKeyword, - ExpectedStateTransition, ExpectedEquals - { + throws ExpectedLeftCurlyBracket, ExpectedRightBracket, ExpectedRightCurlyBracket, ExpectedAssignment, + ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, + ExpectedChannel, ExpectedChannelName, ExpectedInOrOutOrRefOrSubKeyword, + ExpectedStateTransition, ExpectedEquals, WrongPathExpression, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { if (!stream.hasNext()) return null; if (stream.checkNext().equals(RIGHT_CURLY_BRACKET)) return null; - String channelOrInitKeyword = stream.next(); - if (!channelOrInitKeyword.equals(CHANNEL)) { - if (!channelOrInitKeyword.equals(INIT)) throw new ExpectedChannel(stream.getLine()); + boolean isNative = false; + String channelOrInitOrNativeKeyword = stream.next(); + if (channelOrInitOrNativeKeyword.equals(NATIVE)) { + // A native channel + isNative = true; + channelOrInitOrNativeKeyword = stream.next(); + } + if (!channelOrInitOrNativeKeyword.equals(CHANNEL) && !channelOrInitOrNativeKeyword.equals(SUB_CHANNEL)) { + if (!channelOrInitOrNativeKeyword.equals(INIT)) throw new ExpectedChannel(stream.getLine()); parseInit(model); - channelOrInitKeyword = stream.next(); + channelOrInitOrNativeKeyword = stream.next(); + if (channelOrInitOrNativeKeyword.equals(NATIVE)) { + // A native channel + isNative = true; + channelOrInitOrNativeKeyword = stream.next(); + } } if (!stream.hasNext()) throw new ExpectedChannelName(stream.getLine()); @@ -120,50 +161,68 @@ int fromLine = stream.getLine(); DataTransferChannel channel = new DataTransferChannel(channelName); + if (isNative) { + channel.setNative(true); + } String leftBracket = stream.next(); + if (leftBracket.equals(LEFT_BRACKET)) { + // has selectors + String rightBracket = null; + do { + String selector = stream.next(); + Variable var = parseVariable(stream, model, selector); + channel.addSelector(var); + rightBracket = stream.next(); + } while (rightBracket.equals(COMMA)); + if (!rightBracket.equals(RIGHT_BRACKET)) throw new ExpectedRightBracket(stream.getLine()); + leftBracket = stream.next(); + } if (!leftBracket.equals(LEFT_CURLY_BRACKET)) throw new ExpectedLeftCurlyBracket(stream.getLine()); - String inOrOutOrRef = null; - while (stream.hasNext() && !(inOrOutOrRef = stream.next()).equals(RIGHT_CURLY_BRACKET)) { + String inOrOutOrRefOrSub = null; + while (stream.hasNext() && !(inOrOutOrRefOrSub = stream.checkNext()).equals(RIGHT_CURLY_BRACKET)) { ChannelMember channelMember = null; - if (inOrOutOrRef.equals(IN)) { - channelMember = parseChannelMember(model, inOrOutOrRef); + if (inOrOutOrRefOrSub.equals(IN)) { + stream.next(); + channelMember = parseChannelMember(model, inOrOutOrRefOrSub); if (channelMember != null) { channel.addChannelMemberAsInput(channelMember); } - } else if (inOrOutOrRef.equals(OUT)) { - channelMember = parseChannelMember(model, inOrOutOrRef); + } else if (inOrOutOrRefOrSub.equals(OUT)) { + stream.next(); + channelMember = parseChannelMember(model, inOrOutOrRefOrSub); if (channelMember != null) { channel.addChannelMemberAsOutput(channelMember); } - } else if (inOrOutOrRef.equals(REF)) { - channelMember = parseChannelMember(model, inOrOutOrRef); + } else if (inOrOutOrRefOrSub.equals(REF)) { + stream.next(); + channelMember = parseChannelMember(model, inOrOutOrRefOrSub); if (channelMember != null) { channel.addChannelMemberAsReference(channelMember); - } + } + } else if (inOrOutOrRefOrSub.equals(SUB_CHANNEL)) { + DataTransferChannel subChannel = parseChannel(model); + if (subChannel != null) { + channel.addChild(subChannel); + } } else { - throw new ExpectedInOrOutOrRefKeyword(stream.getLine()); + throw new ExpectedInOrOutOrRefOrSubKeyword(stream.getLine()); } } + if (stream.hasNext()) stream.next(); int toLine = stream.getLine(); channel.setSourceText(stream.getSourceText(fromLine, toLine)); return channel; } public void parseInit(DataTransferModel model) - throws - ExpectedLeftCurlyBracket, ExpectedAssignment, ExpectedRHSExpression, WrongRHSExpression, ExpectedRightBracket - { + throws ExpectedLeftCurlyBracket, ExpectedAssignment, ExpectedRHSExpression, WrongRHSExpression, + ExpectedRightBracket, ExpectedRightCurlyBracket, WrongPathExpression, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { String leftBracket = stream.next(); if (!leftBracket.equals(LEFT_CURLY_BRACKET)) throw new ExpectedLeftCurlyBracket(stream.getLine()); - String resourceName = null; - while (stream.hasNext() && !(resourceName = stream.next()).equals(RIGHT_CURLY_BRACKET)) { + while (stream.hasNext() && !stream.checkNext().equals(RIGHT_CURLY_BRACKET)) { int fromLine = stream.getLine(); - ResourcePath resourcePath = model.getResourcePath(resourceName); - if (resourcePath == null) { - resourcePath = new ResourcePath(resourceName, 0); - model.addResourcePath(resourcePath); - } + ResourceHierarchy resourceHierarchy = parseResourceHierarchy(stream, model); if (!stream.hasNext()) throw new ExpectedAssignment(stream.getLine()); String colon = stream.next(); @@ -178,18 +237,17 @@ rightTerm = parseTerm(stream, model); if (rightTerm == null) throw new WrongRHSExpression(stream.getLine()); - resourcePath.setInitialValue(rightTerm); - resourcePath.setInitText(stream.getSourceText(fromLine, toLine)); + resourceHierarchy.setInitialValue(rightTerm); + resourceHierarchy.setInitText(stream.getSourceText(fromLine, toLine)); } + if (stream.hasNext()) stream.next(); } public ChannelMember parseChannelMember(DataTransferModel model, final String inOrOutOrRef) - throws - ExpectedRightBracket, ExpectedStateTransition, ExpectedEquals, - ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression - { + throws ExpectedRightBracket, ExpectedRightCurlyBracket, ExpectedStateTransition, ExpectedEquals, + ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, WrongPathExpression, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { if (!stream.hasNext()) throw new ExpectedStateTransition(stream.getLine()); - Expression leftTerm = parseTerm(stream, model); + StateTransitionTerm leftTerm = parseStateTransitionTerm(stream, model); if (leftTerm == null || !(leftTerm instanceof Term)) throw new WrongLHSExpression(stream.getLine()); Expression rightTerm = null; @@ -203,12 +261,7 @@ if (rightTerm == null) throw new WrongRHSExpression(stream.getLine()); } - String resourceName = ((Term) leftTerm).getSymbol().getName(); - ResourcePath resourcePath = model.getResourcePath(resourceName); - if (resourcePath == null) { - resourcePath = new ResourcePath(resourceName, 0); - model.addResourcePath(resourcePath); - } + ResourcePath resourcePath = (ResourcePath) leftTerm.getSymbol(); ChannelMember channelMember = new ChannelMember(resourcePath); StateTransition stateTransition = new StateTransition(); stateTransition.setCurStateExpression(((Term) leftTerm).getChild(0)); @@ -239,27 +292,42 @@ return channelMember; } - public Expression parseTerm(TokenStream stream, DataTransferModel model) - throws ExpectedRightBracket - { + public Expression parseTerm(TokenStream stream, DataTransferModel model) throws ExpectedRightBracket, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { ArrayList expressions = new ArrayList<>(); ArrayList operators = new ArrayList<>(); String operator = null; for (;;) { - String leftBracketOrMinus = stream.next(); - if (leftBracketOrMinus.equals(LEFT_BRACKET)) { + String leftBracketOrMinusOrNeg = stream.next(); + if (leftBracketOrMinusOrNeg.equals(LEFT_BRACKET)) { Expression exp = parseTerm(stream, model); String rightBracket = stream.next(); if (!rightBracket.equals(RIGHT_BRACKET)) throw new ExpectedRightBracket(stream.getLine()); expressions.add(exp); + } else if (leftBracketOrMinusOrNeg.equals(LEFT_CURLY_BRACKET)) { + Expression exp = parseJsonTerm(stream, model); + String rightBracket = stream.next(); + if (!rightBracket.equals(RIGHT_CURLY_BRACKET)) throw new ExpectedRightBracket(stream.getLine()); + expressions.add(exp); + } else if (leftBracketOrMinusOrNeg.equals(LEFT_SQUARE_BRACKET)) { + Expression exp = parseListTerm(stream, model); + String rightBracket = stream.next(); + if (!rightBracket.equals(RIGHT_SQUARE_BRACKET)) throw new ExpectedRightBracket(stream.getLine()); + expressions.add(exp); } else { - Symbol minus = null; + Symbol minusOrNeg = null; String symbolName = null; - if (leftBracketOrMinus.equals(MINUS)) { - minus = DataTransferModel.minus; // not sub + if (leftBracketOrMinusOrNeg.equals(MINUS)) { + minusOrNeg = DataTransferModel.minus; // not sub symbolName = stream.next(); + } else if (leftBracketOrMinusOrNeg.equals(NEG)) { + minusOrNeg = DataTransferModel.neg; + symbolName = stream.next(); + } else if (leftBracketOrMinusOrNeg.equals(DOUBLE_QUOT)) { + symbolName = DOUBLE_QUOT + stream.next() + DOUBLE_QUOT; + String doubleQuot = stream.next(); + if (!doubleQuot.equals(DOUBLE_QUOT)) throw new ExpectedDoubleQuotation(stream.getLine()); } else { - symbolName = leftBracketOrMinus; + symbolName = leftBracketOrMinusOrNeg; } Expression exp = null; if (stream.checkNext() != null && stream.checkNext().equals(LEFT_BRACKET)) { @@ -273,6 +341,7 @@ int arity = 0; do { stream.next(); // LEFT_BRACKET or COMMA + if (stream.checkNext().equals(RIGHT_BRACKET)) break; arity++; Expression subTerm = parseTerm(stream, model); term.addChild(subTerm, true); @@ -283,38 +352,39 @@ symbol.setArity(arity); exp = term; } else { - // constant or variable - try { - Symbol symbol = model.getSymbol(symbolName); - if (symbol != null && symbol.getArity() == 0) { - exp = new Constant(symbol); - } else { + // constant or variable or json access + Symbol symbol = model.getSymbol(symbolName); + if (symbol != null && symbol.getArity() == 0) { + // a constant + exp = new Constant(symbol); + } else { + if (Character.isDigit(symbolName.charAt(0))) { + // maybe a numerical value + if (stream.checkNext() != null && stream.checkNext().equals(DOT)) { + // Because tokens are separated by a DOT. + stream.next(); + symbolName += DOT + stream.next(); // decimal fraction + } Double d = Double.parseDouble(symbolName); - if (symbolName.contains(".")) { + // a numerical value + if (symbolName.contains(DOT)) { exp = new Constant(symbolName, DataTransferModel.typeDouble); } else { exp = new Constant(symbolName, DataTransferModel.typeInt); } - } - } catch (NumberFormatException e) { - if (stream.checkNext() != null && stream.checkNext().equals(COLON)) { - // when a type is specified. - stream.next(); - String typeName = stream.next(); - Type type = model.getType(typeName); - if (type == null) { - type = new Type(typeName, typeName); - } - exp = new Variable(symbolName, type); + } else if (symbolName.startsWith(DOUBLE_QUOT) && symbolName.endsWith(DOUBLE_QUOT)) { + // a string value + exp = new Constant(symbolName.substring(1, symbolName.length() - 1), DataTransferModel.typeString); } else { - exp = new Variable(symbolName); + // a variable + exp = parseVariable(stream, model, symbolName); } } } - if (minus != null) { - Term minusTerm = new Term(minus); - minusTerm.addChild(exp); - expressions.add(minusTerm); + if (minusOrNeg != null) { + Term minusOrNegTerm = new Term(minusOrNeg); + minusOrNegTerm.addChild(exp); + expressions.add(minusOrNegTerm); } else { expressions.add(exp); } @@ -324,16 +394,136 @@ break; } else if (operator.equals(ADD)) { operators.add(DataTransferModel.add); + stream.next(); } else if (operator.equals(MUL)) { operators.add(DataTransferModel.mul); + stream.next(); } else if (operator.equals(SUB)) { operators.add(DataTransferModel.sub); // not minus + stream.next(); } else if (operator.equals(DIV)) { operators.add(DataTransferModel.div); + stream.next(); + } else if (operator.equals(MOD)) { + operators.add(DataTransferModel.mod); + stream.next(); + } else if (operator.equals(EQ)) { + operators.add(DataTransferModel.eq); + stream.next(); + } else if (operator.equals(NEQ)) { + operators.add(DataTransferModel.neq); + stream.next(); + } else if (operator.equals(GT)) { + operators.add(DataTransferModel.gt); + stream.next(); + } else if (operator.equals(LT)) { + operators.add(DataTransferModel.lt); + stream.next(); + } else if (operator.equals(GE)) { + operators.add(DataTransferModel.ge); + stream.next(); + } else if (operator.equals(LE)) { + operators.add(DataTransferModel.le); + stream.next(); + } else if (operator.equals(AND)) { + operators.add(DataTransferModel.and); + stream.next(); + } else if (operator.equals(OR)) { + operators.add(DataTransferModel.or); + stream.next(); + } else if (operator.equals(DOT)) { + // json accessor + while (operator.equals(DOT)) { + Expression exp = expressions.remove(expressions.size() - 1); + stream.next(); // DOT + if (stream.checkNext() == null) throw new WrongJsonExpression(stream.getLine()); + String literalOrLeftCurlyBracket = stream.next(); + Expression paramTerm = null; + if (literalOrLeftCurlyBracket.equals(LEFT_CURLY_BRACKET)) { + // parameter + paramTerm = parseTerm(stream, model); + String rightCurlyBracket = stream.next(); + if (rightCurlyBracket == null || !rightCurlyBracket.equals(RIGHT_CURLY_BRACKET)) throw new WrongJsonExpression(stream.getLine()); + } else { + // literal + paramTerm = new Constant(literalOrLeftCurlyBracket, DataTransferModel.typeString); + } + Type paramType = null; + if (paramTerm instanceof Variable) { + paramType = ((Variable) paramTerm).getType(); + } else if (paramTerm instanceof Term) { + paramType = ((Term) paramTerm).getType(); + } + Term term = null; + if (literalOrLeftCurlyBracket.equals(LEFT_CURLY_BRACKET)) { + term = new JsonAccessor(DataTransferModel.dotParam); + } else { + term = new JsonAccessor(DataTransferModel.dot); + } + term.addChild(exp); + term.addChild(paramTerm); + expressions.add(term); + operator = stream.checkNext(); + if (operator == null) break; + if (operator.equals(COLON)) { + // when a type is specified. + stream.next(); + String typeName = stream.next(); + Type type = model.getType(typeName); + if (type == null) { + type = new Type(typeName, new code.ast.SimpleType(typeName)); + } + term.setType(type); + break; + } + } + if (operator == null) { + break; + } else if (operator.equals(ADD)) { + operators.add(DataTransferModel.add); + stream.next(); + } else if (operator.equals(MUL)) { + operators.add(DataTransferModel.mul); + stream.next(); + } else if (operator.equals(SUB)) { + operators.add(DataTransferModel.sub); // not minus + stream.next(); + } else if (operator.equals(DIV)) { + operators.add(DataTransferModel.div); + stream.next(); + } else if (operator.equals(MOD)) { + operators.add(DataTransferModel.mod); + stream.next(); + } else if (operator.equals(EQ)) { + operators.add(DataTransferModel.eq); + stream.next(); + } else if (operator.equals(NEQ)) { + operators.add(DataTransferModel.neq); + stream.next(); + } else if (operator.equals(GT)) { + operators.add(DataTransferModel.gt); + stream.next(); + } else if (operator.equals(LT)) { + operators.add(DataTransferModel.lt); + stream.next(); + } else if (operator.equals(GE)) { + operators.add(DataTransferModel.ge); + stream.next(); + } else if (operator.equals(LE)) { + operators.add(DataTransferModel.le); + stream.next(); + } else if (operator.equals(AND)) { + operators.add(DataTransferModel.and); + stream.next(); + } else if (operator.equals(OR)) { + operators.add(DataTransferModel.or); + stream.next(); + } else { + break; + } } else { break; } - stream.next(); // an arithmetic operator } if (expressions.size() == 1) { // no arithmetic operators @@ -343,13 +533,41 @@ ArrayList addSubs = new ArrayList<>(); Expression first = expressions.get(0); int i = 1; + Term rootTerm = null; for (Symbol op: operators) { Expression second = expressions.get(i); - if (op.getName().equals(MUL) || op.getName().equals(DIV)) { + if (op.getName().equals(MUL) || op.getName().equals(DIV) || op.getName().equals(MOD)) { + // higher priority than add and sub Term term = new Term(op); term.addChild(first); term.addChild(second); first = term; + } else if (op.getName().equals(EQ) || op.getName().equals(NEQ) || op.getName().equals(GT) || op.getName().equals(LT) + || op.getName().equals(GE) || op.getName().equals(LE) || op.getName().equals(AND) || op.getName().equals(OR)) { + // lower priority than add and sub + if (first != null) monomials.add(first); + Expression firstMonomial = monomials.get(0); + int j = 1; + for (Symbol op2: addSubs) { + Expression secondMonomial = monomials.get(j); + Term term = new Term(op2); + term.addChild(firstMonomial); + term.addChild(secondMonomial); + firstMonomial = term; + j++; + } + if (rootTerm == null) { + rootTerm = new Term(op); + rootTerm.addChild(firstMonomial); + } else { + rootTerm.addChild(firstMonomial); + firstMonomial = rootTerm; + rootTerm = new Term(op); + rootTerm.addChild(firstMonomial); + } + monomials.clear(); + addSubs.clear(); + first = second; } else { // add or sub ==> new monomial monomials.add(first); @@ -369,29 +587,168 @@ firstMonomial = term; i++; } - return firstMonomial; + if (rootTerm == null) { + return firstMonomial; + } else { + rootTerm.addChild(firstMonomial); + return rootTerm; + } } - /**-------------------------------------------------------------------------------- - * [protected] - /**-------------------------------------------------------------------------------- - * checking the token has a token. - * - * @param token - * @param specificTokenName - */ - protected Boolean isMatchKeyword(final String token, final String specificTokenName) { +// private Expression parseJsonTerm(TokenStream stream, DataTransferModel model) throws ExpectedRightBracket, WrongJsonExpression, ExpectedColon { +// Term jsonTerm = new Constant(DataConstraintModel.nil); +// jsonTerm.setType(DataConstraintModel.typeJson); +// while (stream.checkNext() != null && !stream.checkNext().equals(RIGHT_CURLY_BRACKET)) { +// String key = stream.next(); +// Constant keyExp = new Constant(key); +// keyExp.setType(DataConstraintModel.typeString); +// if (stream.checkNext() == null || !stream.checkNext().equals(COLON)) throw new ExpectedColon(stream.getLine()); +// String colon = stream.next(); +// Expression value = parseTerm(stream, model); +// Term nextTerm = new Term(DataConstraintModel.addMember); +// nextTerm.addChild(jsonTerm); +// nextTerm.addChild(keyExp); +// nextTerm.addChild(value); +// jsonTerm = nextTerm; +// if (stream.checkNext() == null || !stream.checkNext().equals(COMMA)) break; +// String comma = stream.next(); +// } +// return jsonTerm; +// } + + private Expression parseJsonTerm(TokenStream stream, DataTransferModel model) throws ExpectedRightBracket, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { + JsonTerm jsonTerm = new JsonTerm(); + while (stream.checkNext() != null && !stream.checkNext().equals(RIGHT_CURLY_BRACKET)) { + if (stream.checkNext() == null || !stream.checkNext().equals(DOUBLE_QUOT)) throw new ExpectedDoubleQuotation(stream.getLine()); + String doubleQuot = stream.next(); + String key = stream.next(); + if (stream.checkNext() == null || !stream.checkNext().equals(DOUBLE_QUOT)) throw new ExpectedDoubleQuotation(stream.getLine()); + doubleQuot = stream.next(); + if (stream.checkNext() == null || !stream.checkNext().equals(COLON)) throw new ExpectedColon(stream.getLine()); + String colon = stream.next(); + Expression value = parseTerm(stream, model); + jsonTerm.addMember(key, value); + if (stream.checkNext() == null || !stream.checkNext().equals(COMMA)) break; + String comma = stream.next(); + } + return jsonTerm; + } + + private Expression parseListTerm(TokenStream stream2, DataTransferModel model) throws ExpectedRightBracket, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { + ListTerm listTerm = new ListTerm(); + listTerm.setType(DataTransferModel.typeList); + while (stream.checkNext() != null && !stream.checkNext().equals(RIGHT_SQUARE_BRACKET)) { + Expression element = parseTerm(stream, model); + listTerm.addChild(element); + if (stream.checkNext() == null || !stream.checkNext().equals(COMMA)) break; + String comma = stream.next(); + } + return listTerm; + } + + public Variable parseVariable(TokenStream stream, DataTransferModel model, String symbolName) { + Variable var; + if (stream.checkNext() != null && stream.checkNext().equals(COLON)) { + // when a type is specified. + stream.next(); + String typeName = stream.next(); + Type type = model.getType(typeName); + if (type == null) { + type = new Type(typeName, new code.ast.SimpleType(typeName)); + } + var = new Variable(symbolName, type); + } else { + var = new Variable(symbolName); + } + return var; + } + + public StateTransitionTerm parseStateTransitionTerm(TokenStream stream, DataTransferModel model) + throws ExpectedRightBracket, ExpectedRightCurlyBracket, WrongPathExpression, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { + ResourcePath resourcePath = parseResourcePath(stream, model); + StateTransitionTerm term = new StateTransitionTerm(resourcePath); + int arity = 0; + do { + stream.next(); // LEFT_BRACKET or COMMA + arity++; + Expression subTerm = parseTerm(stream, model); + term.addChild(subTerm, true); + if (!stream.hasNext()) throw new ExpectedRightBracket(stream.getLine()); + } while (stream.checkNext().equals(COMMA)); + String rightBracket = stream.next(); + if (!rightBracket.equals(RIGHT_BRACKET)) throw new ExpectedRightBracket(stream.getLine()); + resourcePath.setArity(arity); + return term; + } + + public ResourceHierarchy parseResourceHierarchy(TokenStream stream, DataTransferModel model) + throws ExpectedRightBracket, ExpectedRightCurlyBracket, WrongPathExpression { + ResourceHierarchy hierarchy = null; + do { + String literalOrLeftCurlyBracket = stream.next(); + if (literalOrLeftCurlyBracket.equals(LEFT_CURLY_BRACKET)) { + // No path parameter + String rightCurlyBracket = stream.next(); + if (rightCurlyBracket == null || !rightCurlyBracket.equals(RIGHT_CURLY_BRACKET)) throw new ExpectedRightCurlyBracket(stream.getLine()); + hierarchy = new ResourceHierarchy(hierarchy, 1); + } else { + // Path literal + hierarchy = new ResourceHierarchy(hierarchy, literalOrLeftCurlyBracket); + } + if (!stream.hasNext()) throw new WrongPathExpression(stream.getLine()); + if (stream.checkNext().equals(LEFT_BRACKET)) break; + if (stream.checkNext().equals(COLON)) break; + } while (stream.next().equals(DOT)); + hierarchy = model.getOrPutResourceHierarchy(hierarchy); + return hierarchy; + } + + public ResourcePath parseResourcePath(TokenStream stream, DataTransferModel model) + throws ExpectedRightBracket, ExpectedRightCurlyBracket, WrongPathExpression, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { + ResourcePath path = null; + do { + String literalOrLeftCurlyBracket = stream.next(); + if (literalOrLeftCurlyBracket.equals(LEFT_CURLY_BRACKET)) { + // Path parameter + Expression paramTerm = parseTerm(stream, model); + String rightCurlyBracket = stream.next(); + if (rightCurlyBracket == null) throw new ExpectedRightCurlyBracket(stream.getLine()); + Expression paramConstraint = null; + if (rightCurlyBracket.equals(EQUALS)) { + // Path constraint + paramConstraint = parseTerm(stream, model); + rightCurlyBracket = stream.next(); + if (rightCurlyBracket == null) throw new ExpectedRightCurlyBracket(stream.getLine()); + } + if (!rightCurlyBracket.equals(RIGHT_CURLY_BRACKET)) throw new ExpectedRightCurlyBracket(stream.getLine()); + if (paramConstraint == null) { + path = new ResourcePath(path, paramTerm); + } else { + path = new ResourcePath(path, paramTerm, paramConstraint); + } + } else { + // Path literal + if (path == null) { + path = new ResourcePath(literalOrLeftCurlyBracket); + } else { + path = new ResourcePath(path, literalOrLeftCurlyBracket); + } + } + if (!stream.hasNext()) throw new WrongPathExpression(stream.getLine()); + if (stream.checkNext().equals(LEFT_BRACKET)) break; + } while (stream.next().equals(DOT)); + model.addResourcePath(path); + return path; + } + + protected Boolean doesMatchToKeyword(final String token, final String specificTokenName) { if(token == null) return false; if(specificTokenName == null) return false; return token.equals(specificTokenName); } - /**-------------------------------------------------------------------------------- - * [inner class] - * "TokenStream" has a token what is read from description of "Architecture Language Model". - */ public static class TokenStream { - private ArrayList> tokens = new ArrayList<>(); + private ArrayList> tokens = new ArrayList<>(); private ArrayList lines = new ArrayList<>(); private int line = 0; private int n = 0; @@ -404,61 +761,83 @@ public void addLine(String line) { lines.add(line); line = line.trim(); - tokens.add( - splitBy( - splitBy( - splitBy( - splitBy( - splitBy( - splitBy( - splitBy( - splitBy( - splitBy( - splitBy( - splitBy( - Arrays.asList(line.split("[ \t]")), - ADD, - ADD_REGX), - MUL, - MUL_REGX), - SUB, - SUB_REGX), - DIV, - DIV_REGX), - COMMA, - COMMA), - COLON, - COLON), - LEFT_BRACKET, - LEFT_BRACKET_REGX), - RIGHT_BRACKET, - RIGHT_BRACKET_REGX), - EQUALS, - EQUALS), - LEFT_CURLY_BRACKET, - LEFT_CURLY_BRACKET_REGX), - RIGHT_CURLY_BRACKET, - RIGHT_CURLY_BRACKET_REGX)); + ArrayList tokenList = splitByDoubleQuotation(line); + tokenList = splitBy(tokenList, ADD, ADD_REGX); + tokenList = splitBy(tokenList, MUL, MUL_REGX); + tokenList = splitBy(tokenList, SUB, SUB_REGX); + tokenList = splitBy(tokenList, DIV, DIV_REGX); + tokenList = splitBy(tokenList, MOD, MOD); + tokenList = splitBy(tokenList, EQ, EQ); + tokenList = splitBy(tokenList, NEQ, NEQ); + tokenList = splitBy(tokenList, GE, GE); + tokenList = splitBy(tokenList, LE, LE); + tokenList = splitBy(tokenList, GT, GT); + tokenList = splitBy(tokenList, LT, LT); + tokenList = splitBy(tokenList, AND, AND); + tokenList = splitBy(tokenList, OR, OR_REGX); + tokenList = splitBy(tokenList, NEG, NEG); + tokenList = splitBy(tokenList, DOT, DOT_REGX); + tokenList = splitBy(tokenList, COMMA, COMMA); + tokenList = splitBy(tokenList, COLON, COLON); + tokenList = splitBy(tokenList, LEFT_BRACKET, LEFT_BRACKET_REGX); + tokenList = splitBy(tokenList, RIGHT_BRACKET, RIGHT_BRACKET_REGX); + tokenList = splitBy(tokenList, EQUALS, EQUALS); + tokenList = splitBy(tokenList, LEFT_CURLY_BRACKET, LEFT_CURLY_BRACKET_REGX); + tokenList = splitBy(tokenList, RIGHT_CURLY_BRACKET, RIGHT_CURLY_BRACKET_REGX); + tokenList = splitBy(tokenList, LEFT_SQUARE_BRACKET, LEFT_SQUARE_BRACKET_REGX); + tokenList = splitBy(tokenList, RIGHT_SQUARE_BRACKET, RIGHT_SQUARE_BRACKET_REGX); + tokens.add(tokenList); } - - private ArrayList splitBy(final List tokens, final String delimiter, final String delimiterRegx) { - ArrayList newTokens = new ArrayList<>(); - for (String token: tokens) { - String[] splitTokens = token.split(delimiterRegx); - boolean fFirstToken = true; - for (String t: splitTokens) { - if (!fFirstToken) { - newTokens.add(delimiter); + + private ArrayList splitBy(final List tokens, final String delimiter, final String delimiterRegx) { + ArrayList newTokens = new ArrayList<>(); + for (Token token: tokens) { + if (token.isAtomic()) { + newTokens.add(token); + } else { + String[] splitTokens = token.split(delimiterRegx); + boolean fFirstToken = true; + for (String t: splitTokens) { + if (!fFirstToken) { + newTokens.add(new Token(delimiter, true)); + } + if (t.length() > 0) { + newTokens.add(new Token(t)); + } + fFirstToken = false; } - if (t.length() > 0) { - newTokens.add(t); + while (token.endsWith(delimiter)) { + newTokens.add(new Token(delimiter, true)); + token = token.substring(0, token.length() - 1); } - fFirstToken = false; } - while (token.endsWith(delimiter)) { - newTokens.add(delimiter); - token = token.substring(0, token.length() - 1); + } + return newTokens; + } + + private ArrayList splitByDoubleQuotation(String line) { + ArrayList newTokens = new ArrayList<>(); + String[] tokens = line.split(DOUBLE_QUOT); + boolean fFirstToken = true; + for (int i = 0; i < tokens.length; i++) { + String token = tokens[i]; + if (!fFirstToken) { + newTokens.add(new Token(DOUBLE_QUOT, true)); } + if (!fFirstToken || token.length() > 0) { + if (i % 2 == 0) { + for (String t: token.split("[ \t]")) { + newTokens.add(new Token(t)); + } + } else { + // string literal + newTokens.add(new Token(token, true)); + } + } + fFirstToken = false; + } + if (line.endsWith(DOUBLE_QUOT)) { + newTokens.add(new Token(DOUBLE_QUOT, true)); } return newTokens; } @@ -470,7 +849,7 @@ n = 0; if (line >= tokens.size()) return null; } - String token = tokens.get(line).get(n); + String token = tokens.get(line).get(n).getTokenStr(); n++; return token; } @@ -482,7 +861,7 @@ n = 0; if (line >= tokens.size()) return null; } - return tokens.get(line).get(n); + return tokens.get(line).get(n).getTokenStr(); } public boolean hasNext() { @@ -507,4 +886,42 @@ return text; } } + + public static class Token { + String token; + boolean isAtomic = false; + + public Token(String token) { + this.token = token; + } + + public Token(String token, boolean isAtomic) { + this.token = token; + this.isAtomic = isAtomic; + } + + public String getTokenStr() { + return token; + } + + public boolean isAtomic() { + return isAtomic; + } + + public String[] split(String delimiterRegx) { + return token.split(delimiterRegx); + } + + public boolean endsWith(String delimiter) { + return token.endsWith(delimiter); + } + + public int length() { + return token.length(); + } + + public Token substring(int beginIdx, int endIdx) { + return new Token(token.substring(beginIdx, endIdx)); + } + } } diff --git a/AlgebraicDataflowArchitectureModel/src/parser/ParserDTRAM.java b/AlgebraicDataflowArchitectureModel/src/parser/ParserDTRAM.java index 830bd5f..eae7ac7 100644 --- a/AlgebraicDataflowArchitectureModel/src/parser/ParserDTRAM.java +++ b/AlgebraicDataflowArchitectureModel/src/parser/ParserDTRAM.java @@ -14,10 +14,12 @@ import parser.exceptions.ExpectedAssignment; import parser.exceptions.ExpectedChannel; import parser.exceptions.ExpectedChannelName; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; import parser.exceptions.ExpectedEquals; import parser.exceptions.ExpectedFormulaChannel; import parser.exceptions.ExpectedGeometry; -import parser.exceptions.ExpectedInOrOutOrRefKeyword; +import parser.exceptions.ExpectedInOrOutOrRefOrSubKeyword; import parser.exceptions.ExpectedIoChannel; import parser.exceptions.ExpectedLeftCurlyBracket; import parser.exceptions.ExpectedModel; @@ -25,8 +27,11 @@ import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedResource; import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; +import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; public class ParserDTRAM extends Parser { @@ -61,9 +66,12 @@ /**-------------------------------------------------------------------------------- * * @param reader + * @throws WrongJsonExpression + * @throws ExpectedColon + * @throws ExpectedDoubleQuotation */ public DataTransferModel doParseModel() - throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry { + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefOrSubKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry, ExpectedRightCurlyBracket, WrongPathExpression, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { DataTransferModel model = getParsedModel(); return model; } @@ -73,7 +81,7 @@ * @param graph */ public void doParseGeometry(mxGraph graph) - throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry, ExpectedNode, ExpectedResource, ExpectedFormulaChannel, ExpectedIoChannel{ + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefOrSubKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry, ExpectedNode, ExpectedResource, ExpectedFormulaChannel, ExpectedIoChannel{ parseGeometry(graph); } @@ -83,9 +91,12 @@ /**-------------------------------------------------------------------------------- * * @param stream + * @throws WrongJsonExpression + * @throws ExpectedColon + * @throws ExpectedDoubleQuotation */ private DataTransferModel getParsedModel() - throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry { + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefOrSubKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry, ExpectedRightCurlyBracket, WrongPathExpression, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { if (!stream.hasNext()) throw new NullPointerException(); @@ -110,11 +121,11 @@ * @param graph */ private void parseGeometry(mxGraph graph) - throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment,ExpectedModel, ExpectedGeometry, ExpectedNode, ExpectedResource, ExpectedFormulaChannel, ExpectedIoChannel { + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefOrSubKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment,ExpectedModel, ExpectedGeometry, ExpectedNode, ExpectedResource, ExpectedFormulaChannel, ExpectedIoChannel { - if (!isMatchKeyword(stream.next(), GEOMETRY_GROUP)) throw new ExpectedGeometry(stream.getLine()); + if (!doesMatchToKeyword(stream.next(), GEOMETRY_GROUP)) throw new ExpectedGeometry(stream.getLine()); - if (!isMatchKeyword(stream.next(), LEFT_CURLY_BRACKET)) throw new ExpectedLeftCurlyBracket(stream.getLine()); + if (!doesMatchToKeyword(stream.next(), LEFT_CURLY_BRACKET)) throw new ExpectedLeftCurlyBracket(stream.getLine()); String node = stream.next(); while (node.equals(GEOMETORY_NODE)) { @@ -128,22 +139,22 @@ String name = stream.next(); - if (!isMatchKeyword(stream.next(), COLON)) throw new ExpectedAssignment(stream.getLine()); + if (!doesMatchToKeyword(stream.next(), COLON)) throw new ExpectedAssignment(stream.getLine()); String x = stream.next(); int xC = Integer.parseInt(x); // C = Coordinate(x,y,w,h) - if (!isMatchKeyword(stream.next(), COMMA))throw new ExpectedAssignment(stream.getLine()); + if (!doesMatchToKeyword(stream.next(), COMMA))throw new ExpectedAssignment(stream.getLine()); String y = stream.next(); int yC = Integer.parseInt(y); - if (!isMatchKeyword(stream.next(), COMMA))throw new ExpectedAssignment(stream.getLine()); + if (!doesMatchToKeyword(stream.next(), COMMA))throw new ExpectedAssignment(stream.getLine()); String w = stream.next(); int wC = Integer.parseInt(w); - if (!isMatchKeyword(stream.next(), COMMA))throw new ExpectedAssignment(stream.getLine()); + if (!doesMatchToKeyword(stream.next(), COMMA))throw new ExpectedAssignment(stream.getLine()); String h = stream.next(); int hC = Integer.parseInt(h); diff --git a/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedColon.java b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedColon.java new file mode 100644 index 0000000..426aaf1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedColon.java @@ -0,0 +1,8 @@ +package parser.exceptions; + +public class ExpectedColon extends ParseException { + + public ExpectedColon(int line) { + super(line); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedDoubleQuotation.java b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedDoubleQuotation.java new file mode 100644 index 0000000..434bec3 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedDoubleQuotation.java @@ -0,0 +1,8 @@ +package parser.exceptions; + +public class ExpectedDoubleQuotation extends ParseException { + + public ExpectedDoubleQuotation(int line) { + super(line); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedInOrOutOrRefKeyword.java b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedInOrOutOrRefKeyword.java deleted file mode 100644 index a44a604..0000000 --- a/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedInOrOutOrRefKeyword.java +++ /dev/null @@ -1,9 +0,0 @@ -package parser.exceptions; - -public class ExpectedInOrOutOrRefKeyword extends ParseException { - - public ExpectedInOrOutOrRefKeyword(int line) { - super(line); - } - -} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedInOrOutOrRefOrSubKeyword.java b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedInOrOutOrRefOrSubKeyword.java new file mode 100644 index 0000000..8d99767 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedInOrOutOrRefOrSubKeyword.java @@ -0,0 +1,9 @@ +package parser.exceptions; + +public class ExpectedInOrOutOrRefOrSubKeyword extends ParseException { + + public ExpectedInOrOutOrRefOrSubKeyword(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedRightCurlyBracket.java b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedRightCurlyBracket.java new file mode 100644 index 0000000..df87cb3 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/ExpectedRightCurlyBracket.java @@ -0,0 +1,9 @@ +package parser.exceptions; + +public class ExpectedRightCurlyBracket extends ParseException { + + public ExpectedRightCurlyBracket(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/exceptions/WrongJsonExpression.java b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/WrongJsonExpression.java new file mode 100644 index 0000000..6a84d6f --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/WrongJsonExpression.java @@ -0,0 +1,9 @@ +package parser.exceptions; + +public class WrongJsonExpression extends ParseException { + + public WrongJsonExpression(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/exceptions/WrongPathExpression.java b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/WrongPathExpression.java new file mode 100644 index 0000000..7f580a5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/WrongPathExpression.java @@ -0,0 +1,9 @@ +package parser.exceptions; + +public class WrongPathExpression extends ParseException { + + public WrongPathExpression(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/ChannelState.java b/AlgebraicDataflowArchitectureModel/src/simulator/ChannelState.java new file mode 100644 index 0000000..4178d73 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/ChannelState.java @@ -0,0 +1,167 @@ +package simulator; + +import java.util.Map; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.dataConstraintModel.Selector; +import models.dataFlowModel.DataTransferChannel; + +/** + * State of a channel, which represents the map from the values of the depended channel selectors to those of the depending channel selectors + * + * @author Nitta + * + */ +public class ChannelState implements Cloneable { + private DataTransferChannel channel; + private ReferenceStructure referenceStructure; + + public ChannelState(DataTransferChannel channel) { + this.channel = channel; + } + + public DataTransferChannel getChannel() { + return channel; + } + + public Map getDependingParamAndValues(List channelValues) { + if (referenceStructure == null) { + return new HashMap<>(); + } + return referenceStructure.getDependingParamAndValues(channelValues); + } + + public List> getDependedChannelSelectorValues(Expression dependingVariable, Expression itsValue) { + if (referenceStructure == null) { + return null; + } + Map dependingVarToVal = new HashMap<>(); + dependingVarToVal.put(dependingVariable, itsValue); + return referenceStructure.getDependedChannelSelectorValues(dependingVarToVal); + } + + public List> getDependedChannelSelectorValues(Map dependingVarToVal) { + if (referenceStructure == null) { + return null; + } + return referenceStructure.getDependedChannelSelectorValues(dependingVarToVal); + } + + /** + * Add a value of a depending channel selector + * + * @param channelValues the values of depended channel selectors + * @param dependingVariable a depending channel selector + * @param itsValue its new value + */ + public void addDependingParamAndValue(List channelValues, Expression dependingVariable, Expression itsValue) { + if (referenceStructure == null) { + referenceStructure = new ReferenceStructure(); + } + referenceStructure.addDependingParamAndValue(channelValues, dependingVariable, itsValue); + } + + public Object clone() { + ChannelState newChannelState = new ChannelState(channel); + if (referenceStructure != null) newChannelState.referenceStructure = (ReferenceStructure) referenceStructure.clone(); + return newChannelState; + } + + private static class ReferenceStructure implements Cloneable { + private Map dependingParamAndValues = null; + private Map referenceStructure; + + public Map getDependentParamAndValues() { + return dependingParamAndValues; + } + + public Map getDependingParamAndValues(List channelValues) { + ReferenceStructure subStructure = this; + for (Constant chVal: channelValues) { + if (subStructure.getDependentParamAndValues() == null) { + subStructure = subStructure.getReferenceStructure(chVal); + } else { + return new HashMap<>(); + } + } + return subStructure.getDependentParamAndValues(); + } + + public List> getDependedChannelSelectorValues(Map dependingVarToVal) { + List> channelValuesList = new ArrayList<>(); + if (dependingParamAndValues != null) { + boolean doesMatch = true; + for (Expression dependingVariable: dependingVarToVal.keySet()) { + if (dependingParamAndValues.keySet().contains(dependingVariable)) { + if (!dependingParamAndValues.get(dependingVariable).equals(dependingVarToVal.get(dependingVariable))) { + doesMatch = false; + } + } + } + if (doesMatch) { + List> chValsList = new ArrayList<>(); + chValsList.add(new ArrayList<>()); + return chValsList; + } else { + return null; + } + } else { + for (Constant chVal: referenceStructure.keySet()) { + List> chValsList = referenceStructure.get(chVal).getDependedChannelSelectorValues(dependingVarToVal); + if (chValsList != null) { + for (List chVals: chValsList) { + chVals.add(0, chVal); + channelValuesList.add(chVals); + } + } + } + } + return channelValuesList; + } + + public void addDependingParamAndValue(Expression dependingVariable, Expression itsValue) { + if (dependingParamAndValues == null) { + dependingParamAndValues = new HashMap<>(); + } + dependingParamAndValues.put(dependingVariable, itsValue); + } + + public void addDependingParamAndValue(List channelValues, Expression dependingVariable, Expression itsValue) { + ReferenceStructure subStructure = this; + for (Constant chVal: channelValues) { + if (subStructure.referenceStructure == null) { + subStructure.referenceStructure = new HashMap<>(); + } + ReferenceStructure nextStructure = subStructure.referenceStructure.get(chVal); + if (nextStructure == null) { + nextStructure = new ReferenceStructure(); + subStructure.referenceStructure.put(chVal, nextStructure); + } + subStructure = nextStructure; + } + subStructure.addDependingParamAndValue(dependingVariable, itsValue); + } + + public ReferenceStructure getReferenceStructure(Constant channelParam) { + return referenceStructure.get(channelParam); + } + + public Object clone() { + ReferenceStructure newReferenceStructure = new ReferenceStructure(); + if (dependingParamAndValues != null) { + newReferenceStructure.dependingParamAndValues = new HashMap<>(dependingParamAndValues); + } + if (referenceStructure != null) { + newReferenceStructure.referenceStructure = new HashMap<>(); + for (Map.Entry refEnt: referenceStructure.entrySet()) { + newReferenceStructure.referenceStructure.put(refEnt.getKey(), (ReferenceStructure) refEnt.getValue().clone()); + } + } + return newReferenceStructure; + } + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/Event.java b/AlgebraicDataflowArchitectureModel/src/simulator/Event.java new file mode 100644 index 0000000..9cc7e6a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/Event.java @@ -0,0 +1,674 @@ +package simulator; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.InvalidMessage; +import models.algebra.Position; +import models.algebra.Term; +import models.algebra.UnificationFailed; +import models.algebra.Variable; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; +import models.dataFlowModel.DataTransferChannel; +import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; +import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; + +/** + * Event occurred at a channel + * + * @author Nitta + * + */ +public class Event { + private DataTransferChannel channel; + private Expression message; + private boolean isInput = false; + private ResourcePath inputResourcePath = null; + private Resource inputResource = null; + + private List> channelSelectorAndValues = new ArrayList<>(); + private Map dependingParameters = new HashMap<>(); + private Set outputResources = new HashSet<>(); + private Set childEvents = new HashSet<>(); + private Map>>> channelSelectorToInputOrReferenceResourcePathParam = new HashMap<>(); + private Map>>> channelSelectorToOutputResourcePathParam = new HashMap<>(); + + /** + * Constructor for an input event channel + * + * @param channel an input event channel + * @param message an message for the channel + * @param outputResPath an output side resource path of the channel + * @param outputResource an output side resource of the channel + */ + public Event(DataTransferChannel channel, Expression message, ResourcePath outputResPath, Resource outputResource) { + this.channel = channel; + this.message = message; + this.isInput = true; + this.outputResources.add(outputResource); + connectChannelSelectorAndPathParameters(); + + // Extract the values of the channel selectors from the output resource. + List channelSelectors = channel.getAllSelectors(); + for (Selector sel: channelSelectors) { + Map.Entry> paramIdxAndPos = channelSelectorToOutputResourcePathParam.get(sel).get(outputResPath); + Resource ancestor = outputResource; + int idx = outputResPath.getPathParams().size(); + while (ancestor != null) { + if (ancestor.getResourceHierarchy().getNumParameters() > 0) { + idx--; + if (idx == paramIdxAndPos.getKey()) break; + } + ancestor = ancestor.getParent(); + } + if (ancestor!= null) channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, ancestor.getParameter())); + } + } + + /** + * Constructor for a non-event channel + * + * @param channel a non-event channel + * @param inputResPath an input side resource path of the channel + * @param inputResource an input side resource of the channel + */ + public Event(DataTransferChannel channel, ResourcePath inputResPath, Resource inputResource) { + this.channel = channel; + this.isInput = false; + this.inputResourcePath = inputResPath; + this.inputResource = inputResource; + connectChannelSelectorAndPathParameters(); + + // Extract the values of the channel selectors from the input resource. + List channelSelectors = channel.getAllSelectors(); + for (Selector sel: channelSelectors) { + if (inputResPath != null) { + Map.Entry> paramIdxAndPos = channelSelectorToInputOrReferenceResourcePathParam.get(sel).get(inputResPath); + if (paramIdxAndPos != null) { + Resource ancestor = inputResource; + int idx = inputResPath.getPathParams().size(); + while (ancestor != null) { + if (ancestor.getResourceHierarchy().getNumParameters() > 0) { + idx--; + if (idx == paramIdxAndPos.getKey()) break; + } + ancestor = ancestor.getParent(); + } + channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, ancestor.getParameter())); + } + } + } + } + + /** + * Constructor for a non-event channel + * + * @param channel a non-event channel + * @param inputResPath an input side resource path of the channel + * @param inputResource an input side resource of the channel + * @param channelSelectorValues the values of depended channel selectors + * @param dependingVarToVal the values of depending channel selectors + */ + public Event(DataTransferChannel channel, ResourcePath inputResPath, Resource inputResource, List channelSelectorValues, Map dependingVarToVal) { + this.channel = channel; + this.isInput = false; + this.inputResourcePath = inputResPath; + this.inputResource = inputResource; + connectChannelSelectorAndPathParameters(); + + // Extract the values of the channel selectors from channelSelectorValues. + List channelSelectors = channel.getAllSelectors(); + for (int i = 0; i < channelSelectors.size(); i++) { + Selector sel = channelSelectors.get(i); + channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, channelSelectorValues.get(i))); + } + this.dependingParameters = dependingVarToVal; + } + + private void connectChannelSelectorAndPathParameters() { + List channelSelectors = channel.getAllSelectors(); + for (Selector sel: channelSelectors) { + Set inputAndReferenceResPaths = new HashSet<>(channel.getInputResources()); + inputAndReferenceResPaths.addAll(channel.getReferenceResources()); + for (ResourcePath resPath: inputAndReferenceResPaths) { + for (int paramIdx = 0; paramIdx < resPath.getPathParams().size(); paramIdx++) { + Expression pathParam = resPath.getPathParams().get(paramIdx); + if (pathParam.contains(sel.getExpression())) { + for (Map.Entry posAndVar: pathParam.getVariables().entrySet()) { + Position p = posAndVar.getKey(); + Variable v = posAndVar.getValue(); + if (v.equals(sel.getExpression())) { + Map>> pathToIdxAndPos = channelSelectorToInputOrReferenceResourcePathParam.get(sel); + if (pathToIdxAndPos == null) { + pathToIdxAndPos = new HashMap<>(); + channelSelectorToInputOrReferenceResourcePathParam.put(sel, pathToIdxAndPos); + } + Map.Entry> idxAndPos = pathToIdxAndPos.get(resPath); + if (idxAndPos == null) { + idxAndPos = new AbstractMap.SimpleEntry<>(paramIdx, new HashSet<>()); + pathToIdxAndPos.put(resPath, idxAndPos); + } + idxAndPos.getValue().add(p); + } + } + } + } + } + for (ResourcePath resPath: channel.getOutputResources()) { + for (int paramIdx = 0; paramIdx < resPath.getPathParams().size(); paramIdx++) { + Expression pathParam = resPath.getPathParams().get(paramIdx); + if (pathParam.contains(sel.getExpression())) { + for (Map.Entry posAndVar: pathParam.getVariables().entrySet()) { + Position p = posAndVar.getKey(); + Variable v = posAndVar.getValue(); + if (v.equals(sel.getExpression())) { + Map>> pathToIdxAndPos = channelSelectorToOutputResourcePathParam.get(sel); + if (pathToIdxAndPos == null) { + pathToIdxAndPos = new HashMap<>(); + channelSelectorToOutputResourcePathParam.put(sel, pathToIdxAndPos); + } + Map.Entry> idxAndPos = pathToIdxAndPos.get(resPath); + if (idxAndPos == null) { + idxAndPos = new AbstractMap.SimpleEntry<>(paramIdx, new HashSet<>()); + pathToIdxAndPos.put(resPath, idxAndPos); + } + idxAndPos.getValue().add(p); + } + } + } + } + } + } + } + + public DataTransferChannel getChannel() { + return channel; + } + + public Expression getMessage() { + return message; + } + + public void setMessage(Expression message) { + this.message = message; + } + + public boolean isInput() { + return isInput; + } + + public List> getChannelSelectorAndValues() { + return channelSelectorAndValues; + } + + public List getChannelSelectorValues() { + List channelValues = new ArrayList<>(); + for (Map.Entry chEnt: channelSelectorAndValues) { + channelValues.add(chEnt.getValue()); + } + return channelValues; + } + + public void updateChannelSelectorValues(List channelSelectorValues) { + for (int i = 0; i < channelSelectorValues.size(); i++) { + Map.Entry chEnt = channelSelectorAndValues.get(i); + chEnt.setValue(channelSelectorValues.get(i)); + } + } + + public Map getDependingParameters() { + return dependingParameters; + } + + public void addChild(Event child) { + childEvents.add(child); + } + + public Set getChildren() { + return childEvents; + } + + /** + * Construct channel message, collect descendant events of this event and update the values of the depending channel selectors + * + * @param resourceStateValueProvider a resourceStateValueProvider to provide current and next resource states + * @return calculated message constraint by this event + */ + public Expression constructMessageAndDescendantEvents(IResourceStateValueProvider resourceStateValueProvider, boolean doesUpdateDependingParameters) { + + try { + Map> substitutedPositionsInMessageFromChannels = new HashMap<>(); + return constructMessageAndDesdendantEvents(resourceStateValueProvider, substitutedPositionsInMessageFromChannels, doesUpdateDependingParameters); + } catch (ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed e) { + e.printStackTrace(); + } + return null; + } + + private Expression constructMessageAndDesdendantEvents(IResourceStateValueProvider resourceStateValueProvider, + Map> substitutedPositionsInMessageFromChannels, boolean doesUpdateDependingParameters) + throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork, UnificationFailed { + Expression unifiedMessage = null; + Expression messageConstraint = null; + if (message != null) { + unifiedMessage = (Term) message.clone(); + } + IResourceStateAccessor resouceStateAccessor = new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourceIdentifier resId = getInputResourceIdentifier(target.getResource()); + return resourceStateValueProvider.getCurrentStateValueOf(resId); + } + + @Override + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourceIdentifier resId = getInputResourceIdentifier(target.getResource()); + return resourceStateValueProvider.getNextStateValueOf(resId); + } + + @Override + public Expression getDirectStateAccessorFor(ResourcePath target, ResourcePath from) { + ResourceIdentifier resId = getInputResourceIdentifier(target); + return resourceStateValueProvider.getCurrentStateValueOf(resId); + } + }; + + // 1. Calculate message constraints from leaf channel members on the 'channel member dependency graph'. + Map> dependency = channel.getMemberDependency(); + if (dependency.size() == 0) { + // No channel member dependency. + for (ChannelMember channelMember: channel.getInputChannelMembers()) { + // Calculate message constraint from an input state transition + messageConstraint = channel.calcMessageConstraintForInputMember(channelMember, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + if (unifiedMessage == null) { + unifiedMessage = messageConstraint; + } else { + unifiedMessage = unifiedMessage.unify(messageConstraint); + if (unifiedMessage == null) { + throw new UnificationFailed(); + } + } + } + for (ChannelMember channelMember: channel.getReferenceChannelMembers()) { + // Calculate message constraint from a reference state transition + messageConstraint = channel.calcMessageConstraintForReferenceMember(channelMember, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + if (unifiedMessage == null) { + unifiedMessage = messageConstraint; + } else { + unifiedMessage = unifiedMessage.unify(messageConstraint); + if (unifiedMessage == null) { + throw new UnificationFailed(); + } + } + } + } else { + Set toResolve = new HashSet<>(); + Set resolved = new HashSet<>(); + for (Set depended: dependency.values()) { + toResolve.addAll(depended); + } + for (ChannelMember depending: dependency.keySet()) { + toResolve.remove(depending); + } + if ((messageConstraint = getMessage()) instanceof Term) { + unifiedMessage = messageConstraint; + } + for (ChannelMember leafMember: toResolve) { + if (channel.getInputChannelMembers().contains(leafMember)) { + // Calculate message constraint from an input state transition + messageConstraint = channel.calcMessageConstraintForInputMember(leafMember, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + } else if (channel.getReferenceChannelMembers().contains(leafMember)) { + // Calculate message constraint from a reference state transition + messageConstraint = channel.calcMessageConstraintForReferenceMember(leafMember, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + } + if (unifiedMessage == null) { + unifiedMessage = messageConstraint; + } else { + unifiedMessage = unifiedMessage.unify(messageConstraint); + if (unifiedMessage == null) { + throw new UnificationFailed(); + } + } + } + resolved.addAll(toResolve); + toResolve.clear(); + + // 2. Calculate message constraints from remaining members on the channel member dependency graph. + for (;;) { + // Identify the channel members to resolve next. + for (Map.Entry> dependEnt: dependency.entrySet()) { + ChannelMember dependingMem = dependEnt.getKey(); + Set dependedMems = dependEnt.getValue(); + if (!resolved.contains(dependingMem) && resolved.containsAll(dependedMems)) { + toResolve.add(dependingMem); + } + } + if (toResolve.size() == 0) break; + for (ChannelMember dependingMem: toResolve) { + // Fill the path parameters of the resource path of a depending channel member. + if (doesUpdateDependingParameters) { + Set dependingVarPosInMessage = new HashSet<>(); + ResourcePath filledResPath = channel.fillOutsideResourcePath(dependingMem.getResource(), unifiedMessage, dependingMem.getStateTransition().getMessageExpression(), dependingVarPosInMessage); + ResourcePath unfilledResPath = dependingMem.getResource(); + for (int i = 0; i < unfilledResPath.getPathParamsAndConstraints().size(); i++) { + Expression var = unfilledResPath.getPathParamsAndConstraints().get(i).getKey(); + Expression val = filledResPath.getPathParamsAndConstraints().get(i).getKey(); + Expression constraint = unfilledResPath.getPathParamsAndConstraints().get(i).getValue(); + if (constraint != null && !constraint.equals(val)) { + // The value of the path parameter does not satisfy the constraint defined for the parameter. + return null; // Not to fire this event. + } + if (!channel.getAllSelectorVariables().contains(var)) { + // Update a depending channel parameter + updateDependingParameter(var, val); + } + } + } + + // Calculate message constraint + if (channel.getInputChannelMembers().contains(dependingMem)) { + // Calculate message constraint from an input state transition + messageConstraint = channel.calcMessageConstraintForInputMember(dependingMem, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + } else if (channel.getReferenceChannelMembers().contains(dependingMem)) { + // Calculate message constraint from a reference state transition + messageConstraint = channel.calcMessageConstraintForReferenceMember(dependingMem, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + } + if (unifiedMessage == null) { + unifiedMessage = messageConstraint; + } else { + unifiedMessage = unifiedMessage.unify(messageConstraint); + if (unifiedMessage == null) { + throw new UnificationFailed(); + } + } + } + resolved.addAll(toResolve); + toResolve.clear(); + } + // For the channel members that are depended by and depend on no other member. + for (ChannelMember remainingMem: channel.getChannelMembers()) { + if (!resolved.contains(remainingMem)) { + resolved.add(remainingMem); + // Calculate message constraint + messageConstraint = null; + if (channel.getInputChannelMembers().contains(remainingMem)) { + // Calculate message constraint from an input state transition + messageConstraint = channel.calcMessageConstraintForInputMember(remainingMem, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + } else if (channel.getReferenceChannelMembers().contains(remainingMem)) { + // Calculate message constraint from a reference state transition + messageConstraint = channel.calcMessageConstraintForReferenceMember(remainingMem, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + } + if (messageConstraint != null) { + if (unifiedMessage == null) { + unifiedMessage = messageConstraint; + } else { + unifiedMessage = unifiedMessage.unify(messageConstraint); + if (unifiedMessage == null) { + throw new UnificationFailed(); + } + } + } + } + } + } + if (inputResource == null) return unifiedMessage; + + // 3. Propagate parent event message to collect child events and calculate message constraints from child channels. + Resource baseResource = inputResource; + while (baseResource.getResourceHierarchy().getNumParameters() == 0) { + if (baseResource.getParent() == null) break; + baseResource = baseResource.getParent(); + } + Expression parentEventMessage = (Expression) unifiedMessage.clone(); + for (Channel childChannel: channel.getChildren()) { + // Search the deepest input or reference side resource path in each child channel that matches the channel parameters. + ChannelMember inOrRef = null; + Set channelMembers = new HashSet<>(((DataTransferChannel) childChannel).getInputChannelMembers()); + channelMembers.addAll(((DataTransferChannel) childChannel).getReferenceChannelMembers()); + for (ChannelMember cm: channelMembers) { + if (!cm.isOutside()) { + ResourcePath resPath = cm.getResource(); + if (resPath.getPathParams().containsAll(childChannel.getAllSelectorVariables())) { + inOrRef = cm; + break; + } + } + } + if (inOrRef != null) { + // Collect events for all resources under this event's input resource that matches the deepest input side resource path. + for (Resource res: baseResource.getDescendants(inOrRef.getResource().getResourceHierarchy())) { + Event childEvent = new Event((DataTransferChannel) childChannel, inOrRef.getResource(), res); + childEvent.setMessage(parentEventMessage); + messageConstraint = childEvent.constructMessageAndDesdendantEvents(resourceStateValueProvider, substitutedPositionsInMessageFromChannels, true); + if (messageConstraint != null) { + childEvent.setMessage(messageConstraint); + if (unifiedMessage == null) { + unifiedMessage = messageConstraint; + } else { + unifiedMessage = unifiedMessage.unify(messageConstraint); + if (unifiedMessage == null) { + throw new UnificationFailed(); + } + } + childEvents.add(childEvent); + } + } + } else { + // Search the deepest output side resource path in each child channel that matches the channel parameters. + ChannelMember out = null; + for (ChannelMember cm: ((DataTransferChannel) childChannel).getOutputChannelMembers()) { + if (!cm.isOutside()) { + ResourcePath resPath = cm.getResource(); + if (resPath.getPathParams().containsAll(childChannel.getAllSelectorVariables())) { + out = cm; + break; + } + } + } + if (out != null) { + // Collect events for all resources under this event's input resource that matches the deepest output side resource path. + for (Resource res: baseResource.getDescendants(out.getResource().getResourceHierarchy())) { + Event childEvent = new Event((DataTransferChannel) childChannel, parentEventMessage, out.getResource(), res); + childEvent.constructMessageAndDesdendantEvents(resourceStateValueProvider, substitutedPositionsInMessageFromChannels, true); + childEvents.add(childEvent); + } + } + } + } + + return unifiedMessage; + } + + public void updateDependingParameter(Expression variable, Expression value) { + dependingParameters.put(variable, value); + } + + public ResourcePath getInputResourcePath() { + return inputResourcePath; + } + + public Resource getInputResource() { + return inputResource; + } + + public Set getOutputResources() { + return outputResources; + } + + public ResourceIdentifier getResourceIdentifier(ResourcePath resPath) { + ResourceIdentifier resId = ResourceIdentifier.createFrom(resPath); + for (Map.Entry chParamEnt: channelSelectorAndValues) { + Selector sel = chParamEnt.getKey(); + Map>> inputPathToIdxAndPos = channelSelectorToInputOrReferenceResourcePathParam.get(sel); + if (inputPathToIdxAndPos != null) { + Map.Entry> pathParamEnt = inputPathToIdxAndPos.get(resPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Variable) { + resId.setPathParam(paramIdx, chParamEnt.getValue()); + } + } + } + } + } + for (Map.Entry chParamEnt: channelSelectorAndValues) { + Selector sel = chParamEnt.getKey(); + Map>> outputPathToIdxAndPos = channelSelectorToOutputResourcePathParam.get(sel); + if (outputPathToIdxAndPos != null) { + Map.Entry> pathParamEnt = outputPathToIdxAndPos.get(resPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Variable) { + resId.setPathParam(paramIdx, chParamEnt.getValue()); + } + } + } + } + } + for (Expression var: dependingParameters.keySet()) { + int paramIdx = resId.getPathParams().indexOf(var); + if (paramIdx >= 0) { + resId.setPathParam(paramIdx, (Constant) dependingParameters.get(var)); + } + } + for (Map.Entry chParamEnt: channelSelectorAndValues) { + Selector sel = chParamEnt.getKey(); + Map>> inputPathToIdxAndPos = channelSelectorToInputOrReferenceResourcePathParam.get(sel); + if (inputPathToIdxAndPos != null) { + Map.Entry> pathParamEnt = inputPathToIdxAndPos.get(resPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Term && sel.getExpression() instanceof Variable) { + pathParamExp = ((Term) pathParamExp).substitute((Variable) sel.getExpression(), chParamEnt.getValue()); + resId.setPathParam(paramIdx, ((Term) pathParamExp).reduce()); + } + } + } + } + } + for (Map.Entry chParamEnt: channelSelectorAndValues) { + Selector sel = chParamEnt.getKey(); + Map>> outputPathToIdxAndPos = channelSelectorToOutputResourcePathParam.get(sel); + if (outputPathToIdxAndPos != null) { + Map.Entry> pathParamEnt = outputPathToIdxAndPos.get(resPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Term && sel.getExpression() instanceof Variable) { + pathParamExp = ((Term) pathParamExp).substitute((Variable) sel.getExpression(), chParamEnt.getValue()); + resId.setPathParam(paramIdx, ((Term) pathParamExp).reduce()); + } + } + } + } + } + return resId; + } + + public ResourceIdentifier getInputResourceIdentifier(ResourcePath inputResPath) { + ResourceIdentifier resId = ResourceIdentifier.createFrom(inputResPath); + for (Map.Entry chParamEnt: channelSelectorAndValues) { + Selector sel = chParamEnt.getKey(); + if (channelSelectorToInputOrReferenceResourcePathParam.get(sel) != null) { + Map.Entry> pathParamEnt = channelSelectorToInputOrReferenceResourcePathParam.get(sel).get(inputResPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Variable) { + resId.setPathParam(paramIdx, chParamEnt.getValue()); + } + } + } + } + } + for (Expression var: dependingParameters.keySet()) { + int paramIdx = resId.getPathParams().indexOf(var); + if (paramIdx >= 0) { + resId.setPathParam(paramIdx, (Constant) dependingParameters.get(var)); + } + } + for (Map.Entry chParamEnt: channelSelectorAndValues) { + Selector sel = chParamEnt.getKey(); + if (channelSelectorToInputOrReferenceResourcePathParam.get(sel) != null) { + Map.Entry> pathParamEnt = channelSelectorToInputOrReferenceResourcePathParam.get(sel).get(inputResPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Term && sel.getExpression() instanceof Variable) { + pathParamExp = ((Term) pathParamExp).substitute((Variable) sel.getExpression(), chParamEnt.getValue()); + resId.setPathParam(paramIdx, ((Term) pathParamExp).reduce()); + } + } + } + } + } + return resId; + } + + public ResourceIdentifier getOutputResourceIdentifier(ResourcePath outputResPath) { + ResourceIdentifier resId = ResourceIdentifier.createFrom(outputResPath); + for (Map.Entry chParamEnt: channelSelectorAndValues) { + Selector sel = chParamEnt.getKey(); + if (channelSelectorToOutputResourcePathParam.get(sel) != null) { + Map.Entry> pathParamEnt = channelSelectorToOutputResourcePathParam.get(sel).get(outputResPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Variable) { + resId.setPathParam(paramIdx, chParamEnt.getValue()); + } + } + } + } + } + for (Expression var: dependingParameters.keySet()) { + int paramIdx = resId.getPathParams().indexOf(var); + if (paramIdx >= 0) { + resId.setPathParam(paramIdx, dependingParameters.get(var)); + } + } + for (Map.Entry chParamEnt: channelSelectorAndValues) { + Selector sel = chParamEnt.getKey(); + if (channelSelectorToOutputResourcePathParam.get(sel) != null) { + Map.Entry> pathParamEnt = channelSelectorToOutputResourcePathParam.get(sel).get(outputResPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Term && sel.getExpression() instanceof Variable) { + pathParamExp = ((Term) pathParamExp).substitute((Variable) sel.getExpression(), chParamEnt.getValue()); + resId.setPathParam(paramIdx, ((Term) pathParamExp).reduce()); + } + } + } + } + } + return resId; + } + + + public interface IResourceStateValueProvider { + Expression getCurrentStateValueOf(ResourceIdentifier resId); + Expression getNextStateValueOf(ResourceIdentifier resId); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/Resource.java b/AlgebraicDataflowArchitectureModel/src/simulator/Resource.java new file mode 100644 index 0000000..8cd943f --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/Resource.java @@ -0,0 +1,215 @@ +package simulator; + +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Type; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ResourceHierarchy; +import simulator.states.*; + +/** + * A runtime instance of a resource + * @author Nitta + * + */ +public class Resource { + private Resource parent = null; + private Map children = null; + private ResourceHierarchy resourceHierarchy = null; + private ResourceState state = null; + private Constant parameter = null; + + public Resource(Resource resource) { + this.resourceHierarchy = resource.resourceHierarchy; + this.parent = resource.parent; + this.state = (ResourceState) resource.state.clone(); + this.parameter = resource.parameter; + } + + public Resource(ResourceHierarchy resourceHierarchy) { + this.resourceHierarchy = resourceHierarchy; + Type resType = resourceHierarchy.getResourceStateType(); + if (resourceHierarchy.getChildren().size() > 0 + || DataConstraintModel.typeList.isAncestorOf(resType) + || DataConstraintModel.typeMap.isAncestorOf(resType) + || DataConstraintModel.typeJson.isAncestorOf(resType)) { + if (resType != null && DataConstraintModel.typeList.isAncestorOf(resType)) { + // List resource + state = new ListResourceState(); + } else if (resType != null && DataConstraintModel.typeMap.isAncestorOf(resType)) { + // Map resource + state = new MapResourceState(); + } else { + // Json resource + if (resType == null) { + resType = DataConstraintModel.typeJson; + resourceHierarchy.setResourceStateType(resType); + } + state = new JsonResourceState(); + children = new LinkedHashMap<>(); + for (ResourceHierarchy child: resourceHierarchy.getChildren()) { + Resource cRes = new Resource(child, this); + ((JsonResourceState) state).addChildState(child.getResourceName(), cRes.getState()); + children.put(child.getResourceName(), cRes); + } + } + } else { + Expression initValue = resourceHierarchy.getInitialValue(); + if (initValue != null && initValue instanceof Constant) { + state = new PrimitiveResourceState((Constant) resourceHierarchy.getInitialValue()); + } else { + state = new PrimitiveResourceState(null); + } + } + } + + public Resource(ResourceHierarchy resourceHierarchy, Resource parent) { + this(resourceHierarchy); + this.parent = parent; + } + + public Resource(ResourceHierarchy resourceHierarchy, Resource parent, ResourceState state) { + this.resourceHierarchy = resourceHierarchy; + this.parent = parent; + this.state = state; + } + + public Resource(ResourceHierarchy resourceHierarchy, Resource parent, Constant parameter, ResourceState state) { + this.resourceHierarchy = resourceHierarchy; + this.parent = parent; + this.parameter = parameter; + this.state = state; + } + + public Resource getParent() { + return parent; + } + + public void setParent(Resource parent) { + this.parent = parent; + } + + public ResourceHierarchy getResourceHierarchy() { + return resourceHierarchy; + } + + public ResourceIdentifier getResourceIdentifier() { + ResourceIdentifier resId = null; + if (parent != null) { + ResourceIdentifier parentResId = parent.getResourceIdentifier(); + if (resourceHierarchy.getNumParameters() == 0) { + resId = new ResourceIdentifier(parentResId, resourceHierarchy.getResourceName(), resourceHierarchy); + } else { + resId = new ResourceIdentifier(parentResId, parameter, resourceHierarchy); + } + } else { + resId = new ResourceIdentifier(resourceHierarchy.getResourceName(), resourceHierarchy); + } + return resId; + } + + public ResourceState getState() { + return state; + } + + public void changeState(ResourceState state) { + this.state = state; + } + + public Constant getParameter() { + return parameter; + } + + public Collection getChildren() { + Map childrenMap = getChildrenMap(); + if (childrenMap == null) return null; + return childrenMap.values(); + } + + public Map getChildrenMap() { + Map children = null; + if (resourceHierarchy.getChildren().size() > 0) { + children = new LinkedHashMap<>(); + ResourceHierarchy childRes = resourceHierarchy.getChildren().iterator().next(); + if (childRes.getNumParameters() > 0) { + // List or Map type. + if (state instanceof CompositeResourceState) { + // If the list or map is not nil. + Map childStates = ((CompositeResourceState) state).getChildStates(); + for (Map.Entry childEnt: childStates.entrySet()) { + String childParam = childEnt.getKey(); + ResourceState childState = childEnt.getValue(); + Type thisType = resourceHierarchy.getResourceStateType(); + if (DataConstraintModel.typeList.isAncestorOf(thisType)) { + children.put(childParam, new Resource(childRes, this, new Constant(childParam, DataConstraintModel.typeInt), childState)); + } else if (DataConstraintModel.typeMap.isAncestorOf(thisType)) { + children.put(childParam, new Resource(childRes, this, new Constant(childParam, DataConstraintModel.typeString), childState)); + } + } + } + } else { + // Json type. + Map childStates = ((CompositeResourceState) state).getChildStates(); + if (this.children == null || this.children.size() < childStates.size()) { + for (Map.Entry childEnt: childStates.entrySet()) { + String childParam = childEnt.getKey(); + ResourceState childState = childEnt.getValue(); + Type thisType = resourceHierarchy.getResourceStateType(); + for (ResourceHierarchy c: resourceHierarchy.getChildren()) { + if (c.getResourceName().equals(childParam.replace("\"", ""))) { + childRes = c; + break; + } + } + if (DataConstraintModel.typeJson.isAncestorOf(thisType)) { + children.put(childParam, new Resource(childRes, this, new Constant(childParam, DataConstraintModel.typeString), childState)); + } + } + this.children = children; + } + return this.children; + } + } + return children; + } + + public Set getDescendants(ResourceHierarchy res) { + if (this.getResourceHierarchy().equals(res)) { + Set descendants = new HashSet<>(); + descendants.add(this); + return descendants; + } + if (!res.toString().startsWith(this.getResourceHierarchy().toString())) return new HashSet<>(); + Set descendants = new HashSet<>(); + for (Resource child: getChildren()) { + descendants.addAll(child.getDescendants(res)); + } + return descendants; + } + + public Resource getDescendant(ResourceIdentifier resId) { + if (this.getResourceIdentifier().equals(resId)) return this; + if (!resId.startsWith(this.getResourceIdentifier())) return null; + for (Resource child: getChildren()) { + Resource res = child.getDescendant(resId); + if (res != null) return res; + } + return null; + } + + public Resource getDescendant(String resId) { + if (this.getResourceIdentifier().toString().equals(resId)) return this; + if (!resId.startsWith(this.getResourceIdentifier().toString())) return null; + for (Resource child: getChildren()) { + Resource res = child.getDescendant(resId); + if (res != null) return res; + } + return null; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/ResourceIdentifier.java b/AlgebraicDataflowArchitectureModel/src/simulator/ResourceIdentifier.java new file mode 100644 index 0000000..13b2c92 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/ResourceIdentifier.java @@ -0,0 +1,137 @@ +package simulator; + +import java.util.HashMap; +import java.util.Map; +import java.util.AbstractMap; +import java.util.AbstractMap.SimpleEntry; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.dataConstraintModel.ResourceHierarchy; +import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; + +public class ResourceIdentifier extends ResourcePath { + + public ResourceIdentifier(String fullResourceName, ResourceHierarchy resourceHierarchy) { + super(fullResourceName, resourceHierarchy); + } + + public ResourceIdentifier(ResourceIdentifier parentResId, String leafResourceName, ResourceHierarchy resourceHierarchy) { + super(parentResId, leafResourceName, resourceHierarchy); + } + + public ResourceIdentifier(ResourceIdentifier parentResId, Expression exp, ResourceHierarchy resourceHierarchy) { + super(parentResId, exp, resourceHierarchy); + } + + public void setPathParam(int paramIdx, Expression param) { + if (paramIdx < pathParams.size()) { + pathParams.set(paramIdx, new AbstractMap.SimpleEntry<>(param, null)); + if (parent != null) { + ((ResourceIdentifier) parent).setPathParam(paramIdx, param); + } + } + } + + public boolean equals(ResourceIdentifier another) { + if (!this.getResourceHierarchy().toString().equals(another.getResourceHierarchy().toString())) return false; + ResourceIdentifier resId = this; + while (resId != null && another != null) { + if (resId.getResourceHierarchy().getNumParameters() == 0) { + if (!another.getResourceHierarchy().getResourceName().equals(resId.getResourceHierarchy().getResourceName())) { + return false; + } + } else { + if (!another.getLastParam().equals(resId.getLastParam())) { + return false; + } + } + resId = (ResourceIdentifier) resId.getParent(); + another = (ResourceIdentifier) another.getParent(); + } + return true; + } + + public boolean startsWith(ResourceIdentifier another) { + if (this.length() > another.length()) { + return ((ResourceIdentifier) parent).startsWith(another); + } + return this.equals(another); + } + + public int length() { + if (parent == null) { + return 1; + } + return ((ResourceIdentifier) parent).length() + 1; + } + + public String toString() { + String resId = ""; + if (parent != null) { + resId += parent.toString() + "."; + } + if (!this.endsWithParam()) { + resId += getLeafResourceName(); + } else { + if (getLastParam() instanceof Constant) { + resId += (String) ((Constant) getLastParam()).getValue(); + } else { + resId += getLastParam().toString(); + } + } + return resId; + } + + public boolean isInstanceOf(ResourcePath resPath) { + ResourcePath resId = this; + while (resId != null && resPath != null) { + if (resId.getResourceHierarchy().getNumParameters() == 0) { + if (resPath.getResourceHierarchy().getNumParameters() != 0 || !resPath.getResourceHierarchy().getResourceName().equals(resId.getResourceHierarchy().getResourceName())) { + return false; + } + } else if (resId.getResourceHierarchy().getNumParameters() != resPath.getResourceHierarchy().getNumParameters()) { + return false; + } + resId = resId.getParent(); + resPath = resPath.getParent(); + } + return true; + } + + public Map extractParameters(ResourcePath resPath) { + ResourcePath resId = this; + Map paramMap = new HashMap<>(); + while (resId != null && resPath != null) { + if (resId.getResourceHierarchy().getNumParameters() > 0) { + paramMap.put(resPath.getLastParam(), (Constant) resId.getLastParam()); + } else { + if (!resPath.getName().equals(resId.getName())) { + return null; + } + } + resId = resId.getParent(); + resPath = resPath.getParent(); + } + return paramMap; + } + + public static ResourceIdentifier createFrom(ResourcePath resPath) { + ResourceIdentifier parent = null; + if (resPath.getParent() != null) { + parent = createFrom(resPath.getParent()); + } + ResourceHierarchy res = resPath.getResourceHierarchy(); + if (res.getNumParameters() == 0) { + if (parent == null) { + return new ResourceIdentifier(resPath.getLeafResourceName(), res); + } else { + return new ResourceIdentifier(parent, resPath.getLeafResourceName(), res); + } + } else { + return new ResourceIdentifier(parent, (Expression) resPath.getLastParam().clone(), res); + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java b/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java new file mode 100644 index 0000000..f178c68 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java @@ -0,0 +1,605 @@ +package simulator; + +import java.util.AbstractMap; +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.InvalidMessage; +import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.Term; +import models.algebra.UnificationFailed; +import models.algebra.ValueUndefined; +import models.algebra.Variable; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ResourceHierarchy; +import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; +import models.dataFlowModel.DataTransferModel; +import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; +import models.dataFlowModel.DataTransferChannel; +import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; +import simulator.Event.IResourceStateValueProvider; +import simulator.interfaces.INativeInitializer; +import simulator.interfaces.INativeReceiver; + +/** + * Simulator to run a model + * @author Nitta + * + */ +public class Simulator { + private DataTransferModel model; + private SystemState curState; + private List systemReceivers = new ArrayList<>(); + private List systemInitializers = new ArrayList<>(); + private Map> nativeReceivers = new HashMap<>(); + private Map nativeChannelReceivers = new HashMap<>(); + + public Simulator(DataTransferModel model) { + this.model = model; + init(); + } + + public DataTransferModel getModel() { + return model; + } + + public SystemState init() { + curState = new SystemState(); + for (ResourceHierarchy res: model.getResourceHierarchies()) { + if (res.getParent() == null) { + // root resource + Resource resource = new Resource(res); + curState.addResource(resource); + Expression initialValue = res.getInitialValue(); + if (initialValue != null) { + if (initialValue instanceof Term) { + initialValue = ((Term) initialValue).reduce(); + } + curState.updateResourceState(resource.getResourceIdentifier(), null, null, initialValue); + } else if (res.getResourceStateType() != null) { + initialValue = DataConstraintModel.getDefaultValueExpression(res.getResourceStateType()); + if (initialValue != null) { + curState.updateResourceState(resource.getResourceIdentifier(), null, null, initialValue); + } + } + } + } + for (Channel channel: model.getChannels()) { + curState.addChannel((DataTransferChannel) channel); + } + for (INativeInitializer initializer: systemInitializers) { + initializer.onInitFromModel(curState); + } + return curState; + } + + public SystemState getCurState() { + return curState; + } + + /** + * Change the state of the system for a given input event. + * + * @param inputEvent an input event + * @return the next system state + * @throws ParameterizedIdentifierIsFutureWork + * @throws ResolvingMultipleDefinitionIsFutureWork + * @throws InvalidMessage + * @throws UnificationFailed + * @throws ValueUndefined + */ + public SystemState transition(Event inputEvent) + throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { + SystemState nextSystemState = new SystemState(curState); + Expression message = inputEvent.constructMessageAndDescendantEvents(new ResourceStateValueProvider(curState, nextSystemState), true); + if (message != null) { + inputEvent.setMessage(message); + } + nextSystemState.addEvent(inputEvent); + + fireEvent(inputEvent, curState, nextSystemState); + + curState = nextSystemState; + for (INativeReceiver receiver: systemReceivers) { + receiver.onReceiveFromModel(inputEvent, nextSystemState); + } + return nextSystemState; + } + + public void addSystemReceiver(INativeReceiver receiver) { + systemReceivers.add(receiver); + } + + public void addSystemInitializer(INativeInitializer initializer) { + systemInitializers.add(initializer); + } + + public void addNativeReceiver(INativeReceiver receiver, DataTransferChannel channel) { + nativeChannelReceivers.put(channel, receiver); + } + + public void addNativeReceiver(INativeReceiver receiver, DataTransferChannel channel, Resource resource) { + Map receivers = nativeReceivers.get(channel); + if (receivers == null) { + receivers = new HashMap<>(); + nativeReceivers.put(channel, receivers); + } + receivers.put(resource.getResourceIdentifier(), receiver); + } + + public void removeSystemReceiver(INativeReceiver receiver) { + systemReceivers.remove(receiver); + } + + public void removeSystemInitializer(INativeInitializer initializer) { + systemInitializers.remove(initializer); + } + + public void removeNativeReceiver(DataTransferChannel channel) { + nativeChannelReceivers.remove(channel); + } + + public void removeNativeReceiver(DataTransferChannel channel, Resource resource) { + Map receivers = nativeReceivers.get(channel); + if (receivers != null) { + receivers.remove(resource.getResourceIdentifier()); + if (receivers.size() == 0) { + nativeReceivers.remove(channel); + } + } + } + + /** + * Fire an given event and construct the next system state from the current system state. + * + * @param event an event + * @param curSystemState the current state of the system + * @param nextSystemState the next state of the system to be constructed + * @throws ParameterizedIdentifierIsFutureWork + * @throws ResolvingMultipleDefinitionIsFutureWork + * @throws InvalidMessage + * @throws UnificationFailed + * @throws ValueUndefined + */ + private void fireEvent(final Event event, final SystemState curSystemState, final SystemState nextSystemState) + throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { + final ChannelMember[] outTarget = new ChannelMember[1]; + final Variable[] outResVar = new Variable[1]; + IResourceStateAccessor resouceStateAccessor = new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + if (target == outTarget[0]) return outResVar[0]; // the current state of each output resource is not to be replaced with its value. + ResourceIdentifier resId = event.getResourceIdentifier(target.getResource()); + Resource res = curSystemState.getResource(resId); + if (res == null) return null; + return res.getState().getValue(); + } + + @Override + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourceIdentifier resId = event.getResourceIdentifier(target.getResource()); + Resource res = nextSystemState.getResource(resId); + if (res == null) return null; + return res.getState().getValue(); + } + + @Override + public Expression getDirectStateAccessorFor(ResourcePath target, ResourcePath from) { + ResourceIdentifier resId = event.getResourceIdentifier(target); + Resource res = curSystemState.getResource(resId); + if (res == null) return null; + return res.getState().getValue(); + } + }; + + // First, fire the all child events. + for (Event childEvent: event.getChildren()) { + fireEvent(childEvent, curSystemState, nextSystemState); + } + + // Fire this event. + DataTransferChannel channel = event.getChannel(); + if (channel.getOutputResources().size() > 0) { + // For each output resource, calculate the next state. + for (ChannelMember out: channel.getOutputChannelMembers()) { + // Calculate the next state expression. + Expression nextResState = null; + outTarget[0] = out; + outResVar[0] = new Variable(channel.getChannelName() + "$" + out.getResource().toString() + "$this"); // A special variable to represent the current state of each output resource. + if (event.getMessage() instanceof Variable) { + nextResState = channel.deriveUpdateExpressionOf(out, resouceStateAccessor).getKey(); + } else { + nextResState = channel.deriveUpdateExpressionOf(out, (Term) event.getMessage(), resouceStateAccessor); + } + // Substitute each channel selector in the expression to a value. + for (Map.Entry selestorAndVal: event.getChannelSelectorAndValues()) { + Expression selExp = selestorAndVal.getKey().getExpression(); + if (nextResState instanceof Term && selExp instanceof Variable) { + nextResState = ((Term) nextResState).substitute((Variable) selExp, selestorAndVal.getValue()); + } + } + // Update the resource state. + ResourceIdentifier outResId = event.getOutputResourceIdentifier(out.getResource()); + Expression curResState = null; + if (curSystemState.getResource(outResId) != null) { + curResState = curSystemState.getResource(outResId).getState().getValue(); + } + List updatedOutResIds = nextSystemState.updateResourceState(outResId, outResVar[0], curResState, nextResState); + if (updatedOutResIds != null) { + if (out.getResource().getResourceHierarchy().isNative()) { + // For a native output resource, neither ancestor nor descendants are changed. + for (Event nextEvent: getNextEvents(outResId, curSystemState, nextSystemState)) { + fireEvent(nextEvent, curSystemState, nextSystemState); + } + } else { + // When a normal resource is updated. + Set ancestors = new HashSet<>(); + for (ResourceIdentifier updatedOutResId: updatedOutResIds) { + while (updatedOutResId != null && !ancestors.contains(updatedOutResId)) { // In addition to the target state, its ancestors' states are also changed. + ancestors.add(updatedOutResId); + for (Event nextEvent: getNextEvents(updatedOutResId, curSystemState, nextSystemState)) { + fireEvent(nextEvent, curSystemState, nextSystemState); + } + updatedOutResId = (ResourceIdentifier) updatedOutResId.getParent(); + } + } + } + } + } + } else if (channel.isNative()) { + // A native output event channel + INativeReceiver receiver = nativeChannelReceivers.get(channel); // receiver for the channel + if (receiver != null) receiver.onReceiveFromModel(event, nextSystemState); + if (nativeReceivers.get(channel) != null) { + receiver = nativeReceivers.get(channel).get(event.getInputResource().getResourceIdentifier()); // receiver for the channel and resource + if (receiver != null) receiver.onReceiveFromModel(event, nextSystemState); + } + } + } + + private Set getNextEvents(ResourceIdentifier inResId, SystemState curSystemState, SystemState nextSystemState) { + IResourceStateValueProvider resourceStateValueProvider = new ResourceStateValueProvider(curSystemState, nextSystemState); + Set nextEvents = new HashSet<>(); + for (Channel ch: model.getChannels()) { + DataTransferChannel channel = (DataTransferChannel) ch; + ChannelState nextChannelState = nextSystemState.getChannelState(channel); + if (nextChannelState == null) { + nextChannelState = new ChannelState(channel); + nextSystemState.updateChannelState(channel, nextChannelState); + } + Map> dependency = channel.getMemberDependency(); + Map> invDependency = new HashMap<>(); + for (ChannelMember dependingMem: dependency.keySet()) { + for (ChannelMember dependedMem: dependency.get(dependingMem)) { + Set dependings = invDependency.get(dependedMem); + if (dependings == null) { + dependings = new HashSet<>(); + invDependency.put(dependedMem, dependings); + } + dependings.add(dependingMem); + } + } + for (ResourcePath inResPath: channel.getInputResources()) { + if (inResId.isInstanceOf(inResPath)) { + // Update the channel state and resource identifiers by the update of the input resource. + boolean isInputResourceDepended = false; + for (ChannelMember dependedMem: invDependency.keySet()) { + if (inResPath == dependedMem.getResource()) { + // 1) If some depending resources are to be updated by the update of an 'depended' input resource. + if (doesSatifsyPathConstraints(inResPath, inResId)) { + Event nextEvent = new Event(channel, inResPath, nextSystemState.getResource(inResId)); + Expression message = nextEvent.constructMessageAndDescendantEvents(resourceStateValueProvider, true); + if (message != null) { + nextEvent.setMessage(message); + nextSystemState.updateChannelState(channel, nextChannelState); + List channelSelValues = nextEvent.getChannelSelectorValues(); + for (Map.Entry paramEnt: nextEvent.getDependingParameters().entrySet()) { + nextChannelState.addDependingParamAndValue(channelSelValues, paramEnt.getKey(), paramEnt.getValue()); + } + nextEvents.add(nextEvent); + } + } + isInputResourceDepended = true; + } + } + boolean isInputResourceDepending = false; + for (ChannelMember dependingMem: dependency.keySet()) { + if (inResPath == dependingMem.getResource()) { + isInputResourceDepending = true; + } + } + if (!isInputResourceDepended && !isInputResourceDepending) { + if (doesSatifsyPathConstraints(inResPath, inResId)) { + Event nextEvent = new Event(channel, inResPath, nextSystemState.getResource(inResId)); + Expression message = nextEvent.constructMessageAndDescendantEvents(resourceStateValueProvider, true); + if (message != null) { + nextEvent.setMessage(message); + nextEvents.add(nextEvent); + } + } + } + for (ChannelMember dependingMem: dependency.keySet()) { + if (inResPath == dependingMem.getResource()) { + // 2) If a 'depending' resource is directly updated. + ResourcePath filledResPath = inResId; + ResourcePath unfilledResPath = inResPath; + // Extract the values of path parameters from the updated resource identifier. + Map selectorVarToVal = new HashMap<>(); + Map dependingVarToVal = new HashMap<>(); + boolean doesSatisfyConstraint = true; + for (int i = 0; i < unfilledResPath.getPathParamsAndConstraints().size(); i++) { + Expression var = unfilledResPath.getPathParamsAndConstraints().get(i).getKey(); + Expression val = filledResPath.getPathParamsAndConstraints().get(i).getKey(); + Expression constraint = unfilledResPath.getPathParamsAndConstraints().get(i).getValue(); + if (constraint != null && !constraint.equals(val)) { + // The value of the path parameter does not satisfy the constraint defined for the parameter. + doesSatisfyConstraint = false; + break; + } + if (channel.getAllSelectorVariables().contains(var)) { + selectorVarToVal.put(var, val); + } else { + dependingVarToVal.put(var, val); + } + } + if (doesSatisfyConstraint) { + List> dependedChannelSelectorValues = nextChannelState.getDependedChannelSelectorValues(dependingVarToVal); + if (dependedChannelSelectorValues != null) { + for (List channelSelectorValues: dependedChannelSelectorValues) { + // Guess every tuple of channel selector values that may affects the updated resource. + boolean doesMatch = true; + for (Expression var: selectorVarToVal.keySet()) { + for (int i = 0; i < channel.getAllSelectors().size(); i++) { + if (channel.getAllSelectors().get(i).getExpression().equals(var)) { + if (!channelSelectorValues.get(i).equals(selectorVarToVal.get(var))) { + // If the value of a selector in the updated resource path does not matches a guessed channel selector value. + doesMatch = false; + } + } + } + } + if (doesMatch) { + Event nextEvent = new Event(channel, inResPath, nextSystemState.getResource(inResId), channelSelectorValues, dependingVarToVal); + Expression message = nextEvent.constructMessageAndDescendantEvents(resourceStateValueProvider, false); + if (message != null) { + nextEvent.setMessage(message); + nextEvents.add(nextEvent); + } + } + } + } + } + } + } + } + } + // 3) If a resource in a descendant channel is directly updated. + ResourcePath inResPath = null; + for (ResourcePath path: channel.getInputResources()) { + if (path.getPathParams().containsAll(channel.getAllSelectorVariables())) { + inResPath = path; + } + } + if (inResPath != null) { + for (Map.Entry, Event> childEventEnt: collectDescendantEvents(channel, channel, inResId, nextSystemState, resourceStateValueProvider)) { + Event childEvent = childEventEnt.getValue(); + nextEvents.add(childEvent); + } + } + } + return nextEvents; + } + + private List, Event>> collectDescendantEvents(DataTransferChannel rootChannel, DataTransferChannel channel, ResourceIdentifier inResId, + SystemState nextSystemState, IResourceStateValueProvider resourceStateValueProvider) { + List, Event>> childEvents = new ArrayList<>(); + ChannelState nextChannelState = nextSystemState.getChannelState(rootChannel); + for (Channel childCh: channel.getChildren()) { + DataTransferChannel childChannel = (DataTransferChannel) childCh; + Map> dependency = childChannel.getMemberDependency(); + Map> invDependency = new HashMap<>(); + for (ChannelMember dependingMem: dependency.keySet()) { + for (ChannelMember dependedMem: dependency.get(dependingMem)) { + Set dependings = invDependency.get(dependedMem); + if (dependings == null) { + dependings = new HashSet<>(); + invDependency.put(dependedMem, dependings); + } + dependings.add(dependingMem); + } + } + for (ResourcePath childInResPath: childChannel.getInputResources()) { + if (inResId.isInstanceOf(childInResPath)) { + boolean isInputResourceDepended = false; + for (ChannelMember dependedMem: invDependency.keySet()) { + if (childInResPath == dependedMem.getResource()) { + // 1) If some depending resources are to be updated by the update of an 'depended' input resource. + if (doesSatifsyPathConstraints(childInResPath, inResId)) { + Event childEvent = new Event(childChannel, childInResPath, nextSystemState.getResource(inResId)); + Expression message = childEvent.constructMessageAndDescendantEvents(resourceStateValueProvider, true); + if (message != null) { + childEvent.setMessage(message); + List childChannelSelValues = childEvent.getChannelSelectorValues(); + for (Map.Entry paramEnt: childEvent.getDependingParameters().entrySet()) { + nextChannelState.addDependingParamAndValue(childChannelSelValues, paramEnt.getKey(), paramEnt.getValue()); + } + if (childChannelSelValues.size() >= childChannel.getSelectors().size()) { + List channelSelectorValues = new ArrayList<>(childChannelSelValues); + for (int i = 0; i < childChannel.getSelectors().size(); i++) { + channelSelectorValues.remove(childChannelSelValues.size() - 1 - i); + } + childEvents.add(new AbstractMap.SimpleEntry<>(channelSelectorValues, childEvent)); + } + } + } + isInputResourceDepended = true; + } + } + boolean isInputResourceDepending = false; + for (ChannelMember dependingMem: dependency.keySet()) { + if (childInResPath == dependingMem.getResource()) { + isInputResourceDepending = true; + } + } + if (!isInputResourceDepended && !isInputResourceDepending) { + if (doesSatifsyPathConstraints(childInResPath, inResId)) { + Event childEvent = new Event(childChannel, childInResPath, nextSystemState.getResource(inResId)); + Expression message = childEvent.constructMessageAndDescendantEvents(resourceStateValueProvider, true); + if (message != null) { + childEvent.setMessage(message); + List childChannelSelValues = childEvent.getChannelSelectorValues(); + for (Map.Entry paramEnt: childEvent.getDependingParameters().entrySet()) { + nextChannelState.addDependingParamAndValue(childChannelSelValues, paramEnt.getKey(), paramEnt.getValue()); + } + if (childChannelSelValues.size() >= childChannel.getSelectors().size()) { + List channelSelectorValues = new ArrayList<>(childChannelSelValues); + for (int i = 0; i < childChannel.getSelectors().size(); i++) { + channelSelectorValues.remove(childChannelSelValues.size() - 1 - i); + } + childEvents.add(new AbstractMap.SimpleEntry<>(channelSelectorValues, childEvent)); + } + } + } + } + for (ChannelMember dependingMem: dependency.keySet()) { + if (childInResPath == dependingMem.getResource()) { + // 2) If a 'depending' resource is directly updated. + ResourcePath filledResPath = inResId; + ResourcePath unfilledResPath = childInResPath; + // Extract the values of path parameters from the updated resource identifier. + Map selectorVarToVal = new HashMap<>(); + Map dependingVarToVal = new HashMap<>(); + boolean doesSatisfyConstraint = true; + for (int i = 0; i < unfilledResPath.getPathParamsAndConstraints().size(); i++) { + Expression var = unfilledResPath.getPathParamsAndConstraints().get(i).getKey(); + Expression val = filledResPath.getPathParamsAndConstraints().get(i).getKey(); + Expression constraint = unfilledResPath.getPathParamsAndConstraints().get(i).getValue(); + if (constraint != null && !constraint.equals(val)) { + // The value of the path parameter does not satisfy the constraint defined for the parameter. + doesSatisfyConstraint = false; + break; + } + if (channel.getAllSelectorVariables().contains(var)) { + selectorVarToVal.put(var, val); + } else { + dependingVarToVal.put(var, val); + } + } + if (doesSatisfyConstraint) { + List> dependedChannelSelectorValues = nextChannelState.getDependedChannelSelectorValues(dependingVarToVal); + if (dependedChannelSelectorValues != null) { + for (List childChannelSelectorValues: dependedChannelSelectorValues) { + // Guess every tuple of channel selector values that may affects the updated resource. + boolean doesMatch = true; + for (Expression var: selectorVarToVal.keySet()) { + for (int i = 0; i < channel.getAllSelectors().size(); i++) { + if (channel.getAllSelectors().get(i).getExpression().equals(var)) { + if (!childChannelSelectorValues.get(i).equals(selectorVarToVal.get(var))) { + // If the value of a selector in the updated resource path does not matches a guessed channel selector value. + doesMatch = false; + } + } + } + } + if (doesMatch) { + Event childEvent = new Event(childChannel, childInResPath, nextSystemState.getResource(inResId), childChannelSelectorValues, dependingVarToVal); + Expression message = childEvent.constructMessageAndDescendantEvents(resourceStateValueProvider, false); + if (message != null) { + childEvent.setMessage(message); + if (childChannelSelectorValues.size() >= childChannel.getSelectors().size()) { + List channelSelectorValues = new ArrayList<>(childChannelSelectorValues); + for (int i = 0; i < childChannel.getSelectors().size(); i++) { + channelSelectorValues.remove(childChannelSelectorValues.size() - 1 - i); + } + childEvents.add(new AbstractMap.SimpleEntry<>(channelSelectorValues, childEvent)); + } + } + } + } + } + } + } + } + } + } + // 3) If a resource in a descendant channel is directly updated. + childEvents.addAll(collectDescendantEvents(rootChannel, childChannel, inResId, nextSystemState, resourceStateValueProvider)); + } + List, Event>> events = new ArrayList<>(); + ResourcePath inResPath = null; + for (ResourcePath path: channel.getInputResources()) { + if (path.getPathParams().containsAll(channel.getAllSelectorVariables())) { + inResPath = path; + } + } + for (Map.Entry, Event> childEventEnt: childEvents) { + List channelSelectorValues = childEventEnt.getKey(); + Event childEvent = childEventEnt.getValue(); + Map dependingVarToVal = nextChannelState.getDependingParamAndValues(channelSelectorValues); + Event event = new Event((DataTransferChannel) channel, inResPath, nextSystemState.getResource(inResId), channelSelectorValues, dependingVarToVal); + event.addChild(childEvent); + if (channelSelectorValues.size() >= channel.getSelectors().size()) { + List parentChannelSelectorValues = new ArrayList<>(channelSelectorValues); + for (int i = 0; i < channel.getSelectors().size(); i++) { + parentChannelSelectorValues.remove(channelSelectorValues.size() - 1 - i); + } + events.add(new AbstractMap.SimpleEntry<>(parentChannelSelectorValues, event)); + } + } + return events; + } + + private boolean doesSatifsyPathConstraints(ResourcePath resPath, ResourceIdentifier resId) { + for (int i = 0; i < resPath.getPathParamsAndConstraints().size(); i++) { + Expression val = resId.getPathParamsAndConstraints().get(i).getKey(); + Expression constraint = resPath.getPathParamsAndConstraints().get(i).getValue(); + if (constraint != null) { + String valStr = val.toString(); + if (val instanceof Constant) { + valStr = (String) ((Constant) val).getValue(); + } + String constStr = constraint.toString(); + if (constraint instanceof Constant) { + constStr = (String) ((Constant) constraint).getValue(); + } + if (!constStr.equals(valStr)) { + // The value of the path parameter does not satisfy the constraint defined for the parameter. + return false; // Not to fire this event. + } + } + } + return true; + } + + private static class ResourceStateValueProvider implements IResourceStateValueProvider { + SystemState curSystemState; + SystemState nextSystemState; + + public ResourceStateValueProvider(SystemState curSystemState, SystemState nextSystemState) { + this.curSystemState = curSystemState; + this.nextSystemState = nextSystemState; + } + + @Override + public Expression getCurrentStateValueOf(ResourceIdentifier resId) { + if (curSystemState.getResource(resId) == null) return null; + return curSystemState.getResource(resId).getState().getValue(); + } + + @Override + public Expression getNextStateValueOf(ResourceIdentifier resId) { + if (nextSystemState.getResource(resId) == null) return null; + return nextSystemState.getResource(resId).getState().getValue(); + } + }; +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/SystemState.java b/AlgebraicDataflowArchitectureModel/src/simulator/SystemState.java new file mode 100644 index 0000000..3fb236f --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/SystemState.java @@ -0,0 +1,1066 @@ +package simulator; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.algebra.Type; +import models.algebra.Variable; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonTerm; +import models.dataConstraintModel.ListTerm; +import models.dataConstraintModel.MapTerm; +import models.dataConstraintModel.ResourceHierarchy; +import models.dataFlowModel.DataTransferChannel; +import simulator.states.CompositeResourceState; +import simulator.states.JsonResourceState; +import simulator.states.ListResourceState; +import simulator.states.MapResourceState; +import simulator.states.PrimitiveResourceState; +import simulator.states.ResourceState; + +/** + * The whole state of a running model + * @author Nitta + * + */ +public class SystemState { + private Set rootResources = new HashSet<>(); + private Map channelStates = new HashMap<>(); + private List events = new ArrayList<>(); + + public SystemState() { + } + + public SystemState(SystemState prevState) { + for (Resource resource: prevState.getRootResources()) { + rootResources.add(new Resource(resource)); + } + for (Map.Entry channelEnt: prevState.getChannelStates().entrySet()) { + if (channelEnt.getValue() != null) { + channelStates.put(channelEnt.getKey(), (ChannelState) channelEnt.getValue().clone()); + } else { + channelStates.put(channelEnt.getKey(), null); + } + } + } + + public Set getRootResources() { + return rootResources; + } + + public void addResource(Resource rootResource) { + rootResources.add(rootResource); + } + + public Resource getResource(ResourceIdentifier resourceIdentifier) { + for (Resource root: rootResources) { + Resource descendant = root.getDescendant(resourceIdentifier); + if (descendant != null) return descendant; + } + return null; + } + + public Resource getResource(String resourceIdentifier) { + for (Resource root: rootResources) { + Resource descendant = root.getDescendant(resourceIdentifier); + if (descendant != null) return descendant; + } + return null; + } + + /** + * update the state of a specified resource + * + * @param resourceIdentifier a resource identifier to identify the resource + * @param curResVar a variable to represent the current state of the resource (may be replaced with resCurStateVal) + * @param resCurStateVal the value of the current state of the resource + * @param resNextStateVal the value of the new state of the resource (may contain curResVar) + * @return the identifier of the deepest resource created by this update. + */ + public List updateResourceState(ResourceIdentifier resourceIdentifier, Variable curResVar, Expression resCurStateVal, Expression resNextStateVal) { + Type resType = resourceIdentifier.getResourceStateType(); + if (resNextStateVal instanceof Term) { + Term termValue = (Term) resNextStateVal; + if (termValue.getSymbol().equals(DataConstraintModel.cond)) { + // If resNextStateVal is a conditional term, then calculates it here. + Expression condExp = termValue.getChild(0); + if (condExp instanceof Term) { + condExp = ((Term) condExp).substitute(curResVar, resCurStateVal); + condExp = ((Term) condExp).reduce(); + } + List condArgs = new ArrayList<>(); + condArgs.add(condExp); + condArgs.add(termValue.getChild(1)); + condArgs.add(termValue.getChild(2)); + resNextStateVal = DataConstraintModel.cond.calculate(condArgs); + if (resNextStateVal != null) { + return updateResourceState(resourceIdentifier, curResVar, resCurStateVal, resNextStateVal); + } + return null; + } + } + if (resType != null && DataConstraintModel.typeList.isAncestorOf(resType)) { + if (resNextStateVal instanceof Constant) { + } else if (resNextStateVal instanceof ListTerm) { + ListTerm listValue = (ListTerm) resNextStateVal; + Resource res = getResource(resourceIdentifier); + ResourceState state = res.getState(); + if (state instanceof ListResourceState) { + List createdResources = new ArrayList<>(); + ((ListResourceState) state).clearChildStates(); + for (int i = 0; i < listValue.size(); i++) { + Expression childExp = new Constant(Integer.toString(i), DataConstraintModel.typeInt); + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (listValue.get(i) instanceof Variable) { + childResType = ((Variable) listValue.get(i)).getType(); + } else if (listValue.get(i) instanceof Term) { + childResType = ((Term) listValue.get(i)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childExp, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, listValue.get(i)); + ((ListResourceState) state).addChildState(childInfo.getKey()); + createdResources.addAll(childInfo.getValue()); + } + return createdResources; + } + return null; + } else if (resNextStateVal instanceof Term) { + Term listValue = (Term) resNextStateVal; + if (listValue.getSymbol().equals(DataConstraintModel.append)) { + List createdResources = new ArrayList<>(); + Resource res = getResource(resourceIdentifier); + ResourceState state = res.getState(); + if (listValue.getChild(0) instanceof Term) { + if (listValue.getChild(0) instanceof Constant && ((Constant) listValue.getChild(0)).getSymbol().equals(DataConstraintModel.nil)) { + // If the child list is nil. + ResourceState parentState = res.getParent().getState(); + ResourceState newState = new ListResourceState(); + if (parentState instanceof CompositeResourceState) { + ((CompositeResourceState) parentState).replaceChildState(state, newState); + } + state = newState; + res.changeState(state); + } else { + Expression childList = ((Term) listValue.getChild(0)).reduce(); + if (childList instanceof ListTerm) { + // If the child list is a list literal. + List childInfo = updateResourceState(resourceIdentifier, curResVar, resCurStateVal, childList); // one more recursion. + if (childInfo != null) createdResources.addAll(childInfo); + } else if (childList instanceof Term) { + // There may or may not be the current state of the resource (curResVar) under the child. + List childInfo = updateResourceState(resourceIdentifier, curResVar, resCurStateVal, listValue.getChild(0)); + if (childInfo != null) createdResources.addAll(childInfo); + } + } + } + Expression childExp = null; + if (state instanceof ListResourceState) { + childExp = new Constant(Integer.toString(((ListResourceState) state).getChildStates().size()), DataConstraintModel.typeInt); + } else if (state instanceof PrimitiveResourceState && ((PrimitiveResourceState) state).getValue().getSymbol().equals(DataConstraintModel.nil)) { + // If the value of state is nil. + childExp = new Constant("0", DataConstraintModel.typeInt); + ResourceState parentState = res.getParent().getState(); + ResourceState newState = new ListResourceState(); + if (parentState instanceof CompositeResourceState) { + ((CompositeResourceState) parentState).replaceChildState(state, newState); + } + state = newState; + res.changeState(state); + } + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (listValue.getChild(1) instanceof Variable) { + childResType = ((Variable) listValue.getChild(1)).getType(); + } else if (listValue.getChild(1) instanceof Term) { + childResType = ((Term) listValue.getChild(1)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childExp, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, listValue.getChild(1)); + ((ListResourceState) state).addChildState(childInfo.getKey()); + createdResources.addAll(childInfo.getValue()); + return createdResources; + } else if (listValue.getSymbol().equals(DataConstraintModel.set)) { + Expression childIdxExp = listValue.getChild(1); + if (childIdxExp instanceof Term) { + childIdxExp = ((Term) childIdxExp).substitute(curResVar, resCurStateVal); + childIdxExp = ((Term) childIdxExp).reduce(); + } + if (childIdxExp instanceof Constant) { + List createdResources = new ArrayList<>(); + Resource res = getResource(resourceIdentifier); + ResourceState state = res.getState(); + if (listValue.getChild(0) instanceof Term) { + if (listValue.getChild(0) instanceof Constant && ((Constant) listValue.getChild(0)).getSymbol().equals(DataConstraintModel.nil)) { + // If the child list is nil. + ResourceState parentState = res.getParent().getState(); + ResourceState newState = new ListResourceState(); + if (parentState instanceof CompositeResourceState) { + ((CompositeResourceState) parentState).replaceChildState(state, newState); + } + state = newState; + res.changeState(state); + } else { + Expression childList = ((Term) listValue.getChild(0)).reduce(); + if (childList instanceof ListTerm) { + // If the child list is a list literal. + List childInfo = updateResourceState(resourceIdentifier, curResVar, resCurStateVal, childList); // one more recursion. + if (childInfo != null) createdResources.addAll(childInfo); + } else if (childList instanceof Term) { + // There may or may not be the current state of the resource (curResVar) under the child. + List childInfo = updateResourceState(resourceIdentifier, curResVar, resCurStateVal, listValue.getChild(0)); + if (childInfo != null) createdResources.addAll(childInfo); + } + } + } + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (listValue.getChild(2) instanceof Variable) { + childResType = ((Variable) listValue.getChild(2)).getType(); + } else if (listValue.getChild(2) instanceof Term) { + childResType = ((Term) listValue.getChild(2)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childIdxExp, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, listValue.getChild(2)); + ((ListResourceState) state).replaceChildState(Integer.parseInt(childIdxExp.toString()), childInfo.getKey()); + createdResources.addAll(childInfo.getValue()); + return createdResources; + } + } else if (listValue.getSymbol().equals(DataConstraintModel.remove)) { + Expression childIdxExp = listValue.getChild(1); + if (childIdxExp instanceof Term) { + childIdxExp = ((Term) childIdxExp).substitute(curResVar, resCurStateVal); + childIdxExp = ((Term) childIdxExp).reduce(); + } + if (childIdxExp instanceof Constant) { + List createdResources = new ArrayList<>(); + Resource res = getResource(resourceIdentifier); + ResourceState state = res.getState(); + if (listValue.getChild(0) instanceof Term) { + if (listValue.getChild(0) instanceof Constant && ((Constant) listValue.getChild(0)).getSymbol().equals(DataConstraintModel.nil)) { + // If the child list is nil. + ResourceState parentState = res.getParent().getState(); + ResourceState newState = new ListResourceState(); + if (parentState instanceof CompositeResourceState) { + ((CompositeResourceState) parentState).replaceChildState(state, newState); + } + state = newState; + res.changeState(state); + } else { + Expression childList = ((Term) listValue.getChild(0)).reduce(); + if (childList instanceof ListTerm) { + // If the child list is a list literal. + List childInfo = updateResourceState(resourceIdentifier, curResVar, resCurStateVal, childList); // one more recursion. + if (childInfo != null) createdResources.addAll(childInfo); + } else if (childList instanceof Term) { + // There may or may not be the current state of the resource (curResVar) under the child. + List childInfo = updateResourceState(resourceIdentifier, curResVar, resCurStateVal, listValue.getChild(0)); + if (childInfo != null) createdResources.addAll(childInfo); + } + } + } + ((ListResourceState) state).removeChildState(Integer.parseInt(childIdxExp.toString())); + createdResources.add(resourceIdentifier); + return createdResources; + } + } + } + } else if (resType != null && DataConstraintModel.typeMap.isAncestorOf(resType)) { + if (resNextStateVal instanceof Constant) { + } else if (resNextStateVal instanceof JsonTerm) { + JsonTerm mapValue = (JsonTerm) resNextStateVal; + Resource res = getResource(resourceIdentifier); + ResourceState state = res.getState(); + if (state instanceof MapResourceState) { + List createdResources = new ArrayList<>(); + ((MapResourceState) state).clearChildStates(); + for (String key: mapValue.keySet()) { + Expression childExp = new Constant(key, DataConstraintModel.typeString); + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (mapValue.get(key) instanceof Variable) { + childResType = ((Variable) mapValue.get(key)).getType(); + } else if (mapValue.get(key) instanceof Term) { + childResType = ((Term) mapValue.get(key)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childExp, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, mapValue.get(key)); + ((MapResourceState) state).addChildState(key, childInfo.getKey()); + createdResources.addAll(childInfo.getValue()); + } + return createdResources; + } + return null; + } else if (resNextStateVal instanceof MapTerm) { + MapTerm mapValue = (MapTerm) resNextStateVal; + Resource res = getResource(resourceIdentifier); + ResourceState state = res.getState(); + if (state instanceof MapResourceState) { + ((MapResourceState) state).clearChildStates(); + List createdResources = new ArrayList<>(); + for (String key: mapValue.keySet()) { + Expression childExp = new Constant(key, DataConstraintModel.typeString); + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (mapValue.get(key) instanceof Variable) { + childResType = ((Variable) mapValue.get(key)).getType(); + } else if (mapValue.get(key) instanceof Term) { + childResType = ((Term) mapValue.get(key)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childExp, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, mapValue.get(key)); + ((MapResourceState) state).addChildState(key, childInfo.getKey()); + createdResources.addAll(childInfo.getValue()); + } + return createdResources; + } + return null; + } else if (resNextStateVal instanceof Term) { + Term mapValue = (Term) resNextStateVal; + if (mapValue.getSymbol().equals(DataConstraintModel.insert)) { + List createdResources = new ArrayList<>(); + Expression childKeyExp = mapValue.getChild(1); + if (childKeyExp instanceof Term) { + childKeyExp = ((Term) childKeyExp).substitute(curResVar, resCurStateVal); + childKeyExp = ((Term) childKeyExp).reduce(); + } + if (childKeyExp instanceof Constant) { + Resource res = getResource(resourceIdentifier); + ResourceState state = res.getState(); + if (mapValue.getChild(0) instanceof Term) { + if (mapValue.getChild(0) instanceof Constant && ((Constant) mapValue.getChild(0)).getSymbol().equals(DataConstraintModel.nil)) { + // If the child map is nil. + ResourceState parentState = res.getParent().getState(); + ResourceState newState = new MapResourceState(); + if (parentState instanceof CompositeResourceState) { + ((CompositeResourceState) parentState).replaceChildState(state, newState); + } + state = newState; + res.changeState(state); + } else { + Expression childMap = ((Term) mapValue.getChild(0)).reduce(); + if (childMap instanceof MapTerm) { + // If the child map is a map literal. + List childInfo = updateResourceState(resourceIdentifier, curResVar, resCurStateVal, childMap); // one more recursion + if (childInfo != null) createdResources.addAll(childInfo); + } else if (childMap instanceof Term) { + // There may or may not be the current state of the resource (curResVar) under the child. + List childInfo = updateResourceState(resourceIdentifier, curResVar, resCurStateVal, mapValue.getChild(0)); + if (childInfo != null) createdResources.addAll(childInfo); + } + } + } + if (state instanceof PrimitiveResourceState && ((PrimitiveResourceState) state).getValue().getSymbol().equals(DataConstraintModel.nil)) { + // If the value of state is nil. + ResourceState parentState = res.getParent().getState(); + ResourceState newState = new MapResourceState(); + if (parentState instanceof CompositeResourceState) { + ((CompositeResourceState) parentState).replaceChildState(state, newState); + } + state = newState; + res.changeState(state); + } + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (mapValue.getChild(2) instanceof Variable) { + childResType = ((Variable) mapValue.getChild(2)).getType(); + } else if (mapValue.getChild(2) instanceof Term) { + childResType = ((Term) mapValue.getChild(2)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childKeyExp, childResourceHierarchy); + String childId = (String) ((Constant) childKeyExp).getValue(); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, mapValue.getChild(2)); + ((MapResourceState) state).addChildState(childId, childInfo.getKey()); + createdResources.addAll(childInfo.getValue()); + return createdResources; + } + } else if (mapValue.getSymbol().equals(DataConstraintModel.delete)) { + Expression childKeyExp = mapValue.getChild(1); + if (childKeyExp instanceof Term) { + childKeyExp = ((Term) childKeyExp).substitute(curResVar, resCurStateVal); + childKeyExp = ((Term) childKeyExp).reduce(); + } + if (childKeyExp instanceof Constant) { + List createdResources = new ArrayList<>(); + Resource res = getResource(resourceIdentifier); + ResourceState state = res.getState(); + if (mapValue.getChild(0) instanceof Term) { + if (mapValue.getChild(0) instanceof Constant && ((Constant) mapValue.getChild(0)).getSymbol().equals(DataConstraintModel.nil)) { + // If the child map is nil. + ResourceState parentState = res.getParent().getState(); + ResourceState newState = new MapResourceState(); + if (parentState instanceof CompositeResourceState) { + ((CompositeResourceState) parentState).replaceChildState(state, newState); + } + state = newState; + res.changeState(state); + } else { + Expression childMap = ((Term) mapValue.getChild(0)).reduce(); + if (childMap instanceof MapTerm) { + // If the child map is a map literal. + List childInfo = updateResourceState(resourceIdentifier, curResVar, resCurStateVal, childMap); // one more recursion + if (childInfo != null) createdResources.addAll(childInfo); + } else if (childMap instanceof Term) { + // There may or may not be the current state of the resource (curResVar) under the child. + List childInfo = updateResourceState(resourceIdentifier, curResVar, resCurStateVal, mapValue.getChild(0)); + if (childInfo != null) createdResources.addAll(childInfo); + } + } + } + String childId = (String) ((Constant) childKeyExp).getValue(); + ((MapResourceState) state).removeChildState(childId); + createdResources.add(resourceIdentifier); + return createdResources; + } + } + } + } else if (resType != null && DataConstraintModel.typeJson.isAncestorOf(resType)) { + if (resNextStateVal instanceof Constant) { + } else if (resNextStateVal instanceof JsonTerm) { + JsonTerm jsonValue = (JsonTerm) resNextStateVal; + Resource res = getResource(resourceIdentifier); + ResourceState state = res.getState(); + if (state instanceof JsonResourceState) { + List createdResources = new ArrayList<>(); + for (String key: jsonValue.keySet()) { + ResourceHierarchy childResourceHierarchy = null; + for (ResourceHierarchy childRes: resourceIdentifier.getResourceHierarchy().getChildren()) { + if (childRes.getResourceName().equals(key)) { + childResourceHierarchy = childRes; + break; + } + } + if (childResourceHierarchy == null) { + Type childResType = null; + if (jsonValue.get(key) instanceof Variable) { + childResType = ((Variable) jsonValue.get(key)).getType(); + } else if (jsonValue.get(key) instanceof Term) { + childResType = ((Term) jsonValue.get(key)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), key, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, key, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, jsonValue.get(key)); + ResourceState childState = childInfo.getKey(); + if (res.getChildrenMap() != null && res.getChildrenMap().get(key) != null) { + res.getChildrenMap().get(key).changeState(childState); + } + ((JsonResourceState) state).addChildState(key, childState); + createdResources.addAll(childInfo.getValue()); + } + return createdResources; + } + return null; + } else if (resNextStateVal instanceof Term) { + Term jsonValue = (Term) resNextStateVal; + Resource res = getResource(resourceIdentifier); + ResourceState state = res.getState(); + List createdResources = new ArrayList<>(); + while (jsonValue.getSymbol().equals(DataConstraintModel.addMember)) { + Expression childKeyExp = jsonValue.getChild(1); + if (childKeyExp instanceof Constant) { + String memberName = (String) ((Constant) childKeyExp).getValue(); + ResourceHierarchy childResourceHierarchy = null; + for (ResourceHierarchy childRes: resourceIdentifier.getResourceHierarchy().getChildren()) { + if (childRes.getResourceName().equals(memberName)) { + childResourceHierarchy = childRes; + break; + } + } + if (childResourceHierarchy == null) { + Type childResType = null; + if (jsonValue.getChild(2) instanceof Variable) { + childResType = ((Variable) jsonValue.getChild(2)).getType(); + } else if (jsonValue.getChild(2) instanceof Term) { + childResType = ((Term) jsonValue.getChild(2)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), memberName, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, memberName, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, jsonValue.getChild(2)); + ((JsonResourceState) state).addChildState(memberName, childInfo.getKey()); + createdResources.addAll(childInfo.getValue()); + } + if (!(jsonValue.getChild(0) instanceof Term)) break; + jsonValue = (Term) jsonValue.getChild(0); + } + return createdResources; + } + } else { + if (curResVar != null && resCurStateVal != null) { + if (resNextStateVal instanceof Term) { + resNextStateVal = ((Term) resNextStateVal).substitute(curResVar, resCurStateVal); + resNextStateVal = ((Term) resNextStateVal).reduce(); + } + } + if (resNextStateVal instanceof Constant) { + Resource res = getResource(resourceIdentifier); + ResourceState state = null; + if (res != null) { + state = res.getState(); + ((PrimitiveResourceState) state).setValue((Constant) resNextStateVal); + } else { + ResourceIdentifier parentResId = (ResourceIdentifier) resourceIdentifier.getParent(); + Type parentResType = parentResId.getResourceStateType(); + if (parentResType != null && DataConstraintModel.typeList.isAncestorOf(parentResType)) { + } else if (parentResType != null && DataConstraintModel.typeMap.isAncestorOf(parentResType)) { + JsonResourceState parentState = (JsonResourceState) getResource(parentResId).getState(); + parentState.addChildState((String) ((Constant) resourceIdentifier.getLastParam()).getValue(), new PrimitiveResourceState((Constant) resNextStateVal)); + } else if (parentResType != null && DataConstraintModel.typeJson.isAncestorOf(parentResType)) { + JsonResourceState parentState = (JsonResourceState) getResource(parentResId).getState(); + parentState.addChildState(resourceIdentifier.getLeafResourceName(), new PrimitiveResourceState((Constant) resNextStateVal)); + } + } + List updatedResources = new ArrayList<>(); + updatedResources.add(resourceIdentifier); + return updatedResources; + } + } + return null; + } + + public Map.Entry> createResourceState(ResourceIdentifier resourceIdentifier, Variable curResVar, Expression resCurStateVal, Expression resStateValue) { + Type resType = resourceIdentifier.getResourceStateType(); + if (resType == null && resStateValue instanceof Term) { + resType = ((Term) resStateValue).getType(); + resStateValue = ((Term) resStateValue).reduce(); + } + if (resType != null) { + if (DataConstraintModel.typeList.isAncestorOf(resType)) { + if (resStateValue instanceof Constant) { + } else if (resStateValue instanceof ListTerm) { + ListTerm listValue = (ListTerm) resStateValue; + ListResourceState state = new ListResourceState(); + Map.Entry> createInfo = new AbstractMap.SimpleEntry<>(state, new ArrayList<>()); + for (int i = 0; i < listValue.size(); i++) { + Expression childExp = new Constant(Integer.toString(i), DataConstraintModel.typeInt); + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (listValue.get(i) instanceof Variable) { + childResType = ((Variable) listValue.get(i)).getType(); + } else if (listValue.get(i) instanceof Term) { + childResType = ((Term) listValue.get(i)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childExp, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, listValue.get(i)); + state.addChildState(childInfo.getKey()); + createInfo.getValue().addAll(childInfo.getValue()); + createInfo = new AbstractMap.SimpleEntry<>(state, createInfo.getValue()); + } + return createInfo; + } else if (resStateValue instanceof Term) { + Term listValue = (Term) resStateValue; + if (listValue.getSymbol().equals(DataConstraintModel.append)) { + List createdResources = new ArrayList<>(); + ListResourceState state = new ListResourceState(); + if (listValue.getChild(0) instanceof Term) { + if (listValue.getChild(0) instanceof Constant && ((Constant) listValue.getChild(0)).getSymbol().equals(DataConstraintModel.nil)) { + // If the child list is nil. + } else { + Expression childList = ((Term) listValue.getChild(0)); + childList = ((Term) childList).substitute(curResVar, resStateValue); + childList = ((Term) childList).reduce(); + if (childList instanceof ListTerm) { + // If the child list is a list literal. + Map.Entry> childInfo = createResourceState(resourceIdentifier, curResVar, resCurStateVal, childList); // one more recursion. + state = (ListResourceState) childInfo.getKey(); + if (childInfo != null) createdResources.addAll(childInfo.getValue()); + } else if (childList instanceof Term) { + // If the child list is a list term. + Map.Entry> childInfo = createResourceState(resourceIdentifier, curResVar, resCurStateVal, listValue.getChild(0)); + state = (ListResourceState) childInfo.getKey(); + if (childInfo != null) createdResources.addAll(childInfo.getValue()); + } + } + } + Expression childExp = new Constant(Integer.toString(((ListResourceState) state).getChildStates().size()), DataConstraintModel.typeInt); + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (listValue.getChild(1) instanceof Variable) { + childResType = ((Variable) listValue.getChild(1)).getType(); + } else if (listValue.getChild(1) instanceof Term) { + childResType = ((Term) listValue.getChild(1)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childExp, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, listValue.getChild(1)); + state.addChildState(childInfo.getKey()); + createdResources.addAll(childInfo.getValue()); + return new AbstractMap.SimpleEntry<>(state, createdResources); + } else if (listValue.getSymbol().equals(DataConstraintModel.set)) { + Expression childIdxExp = listValue.getChild(1); + if (childIdxExp instanceof Term) { + childIdxExp = ((Term) childIdxExp).substitute(curResVar, resCurStateVal); + childIdxExp = ((Term) childIdxExp).reduce(); + } + if (childIdxExp instanceof Constant) { + List createdResources = new ArrayList<>(); + ListResourceState state = new ListResourceState(); + if (listValue.getChild(0) instanceof Term) { + if (listValue.getChild(0) instanceof Constant && ((Constant) listValue.getChild(0)).getSymbol().equals(DataConstraintModel.nil)) { + // If the child list is nil. + } else { + Expression childList = ((Term) listValue.getChild(0)); + childList = ((Term) childList).substitute(curResVar, resStateValue); + childList = ((Term) childList).reduce(); + if (childList instanceof ListTerm) { + // If the child list is a list literal. + Map.Entry> childInfo = createResourceState(resourceIdentifier, curResVar, resCurStateVal, childList); // one more recursion. + state = (ListResourceState) childInfo.getKey(); + if (childInfo != null) createdResources.addAll(childInfo.getValue()); + } else if (childList instanceof Term) { + // If the child list is a list term. + Map.Entry> childInfo = createResourceState(resourceIdentifier, curResVar, resCurStateVal, listValue.getChild(0)); + state = (ListResourceState) childInfo.getKey(); + if (childInfo != null) createdResources.addAll(childInfo.getValue()); + } + } + } + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (listValue.getChild(2) instanceof Variable) { + childResType = ((Variable) listValue.getChild(2)).getType(); + } else if (listValue.getChild(2) instanceof Term) { + childResType = ((Term) listValue.getChild(2)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childIdxExp, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, listValue.getChild(2)); + state.replaceChildState(Integer.parseInt(childIdxExp.toString()), childInfo.getKey()); + createdResources.addAll(childInfo.getValue()); + return new AbstractMap.SimpleEntry<>(state, createdResources); + } + } else if (listValue.getSymbol().equals(DataConstraintModel.remove)) { + Expression childIdxExp = listValue.getChild(1); + if (childIdxExp instanceof Term) { + childIdxExp = ((Term) childIdxExp).substitute(curResVar, resCurStateVal); + childIdxExp = ((Term) childIdxExp).reduce(); + } + if (childIdxExp instanceof Constant) { + List createdResources = new ArrayList<>(); + ListResourceState state = new ListResourceState(); + if (listValue.getChild(0) instanceof Term) { + if (listValue.getChild(0) instanceof Constant && ((Constant) listValue.getChild(0)).getSymbol().equals(DataConstraintModel.nil)) { + // If the child list is nil. + } else { + Expression childList = ((Term) listValue.getChild(0)); + childList = ((Term) childList).substitute(curResVar, resStateValue); + childList = ((Term) childList).reduce(); + if (childList instanceof ListTerm) { + // If the child list is a list literal. + Map.Entry> childInfo = createResourceState(resourceIdentifier, curResVar, resCurStateVal, childList); // one more recursion. + state = (ListResourceState) childInfo.getKey(); + if (childInfo != null) createdResources.addAll(childInfo.getValue()); + } else if (childList instanceof Term) { + // If the child list is a list term. + Map.Entry> childInfo = createResourceState(resourceIdentifier, curResVar, resCurStateVal, listValue.getChild(0)); + state = (ListResourceState) childInfo.getKey(); + if (childInfo != null) createdResources.addAll(childInfo.getValue()); + } + } + } + ((ListResourceState) state).removeChildState(Integer.parseInt(childIdxExp.toString())); + return new AbstractMap.SimpleEntry<>(state, createdResources); + } + } else { + listValue = listValue.substitute(curResVar, resCurStateVal); + Expression listExp = listValue.reduce(); + if (listExp instanceof ListTerm) { + ListTerm listVal = (ListTerm) listExp; + ListResourceState state = new ListResourceState(); + Map.Entry> createInfo = new AbstractMap.SimpleEntry<>(state, new ArrayList<>()); + for (int i = 0; i < listVal.size(); i++) { + Expression childExp = new Constant(Integer.toString(i), DataConstraintModel.typeInt); + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (listVal.get(i) instanceof Variable) { + childResType = ((Variable) listVal.get(i)).getType(); + } else if (listVal.get(i) instanceof Term) { + childResType = ((Term) listVal.get(i)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childExp, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, listVal.get(i)); + state.addChildState(childInfo.getKey()); + createInfo.getValue().addAll(childInfo.getValue()); + createInfo = new AbstractMap.SimpleEntry<>(state, createInfo.getValue()); + } + return createInfo; + } + } + } + } else if (DataConstraintModel.typeMap.isAncestorOf(resType)) { + if (resStateValue instanceof Constant) { + } else if (resStateValue instanceof JsonTerm) { + JsonTerm mapValue = (JsonTerm) resStateValue; + MapResourceState state = new MapResourceState(); + Map.Entry> createInfo = new AbstractMap.SimpleEntry<>(state, new ArrayList<>()); + for (String key: mapValue.keySet()) { + Expression childExp = new Constant(key, DataConstraintModel.typeString); + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (mapValue.get(key) instanceof Variable) { + childResType = ((Variable) mapValue.get(key)).getType(); + } else if (mapValue.get(key) instanceof Term) { + childResType = ((Term) mapValue.get(key)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childExp, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, mapValue.get(key)); + state.addChildState(key, childInfo.getKey()); + createInfo.getValue().addAll(childInfo.getValue()); + createInfo = new AbstractMap.SimpleEntry<>(state, createInfo.getValue()); + } + return createInfo; + } else if (resStateValue instanceof MapTerm) { + MapTerm mapValue = (MapTerm) resStateValue; + MapResourceState state = new MapResourceState(); + Map.Entry> createInfo = new AbstractMap.SimpleEntry<>(state, new ArrayList<>()); + for (String key: mapValue.keySet()) { + Expression childExp = new Constant(key, DataConstraintModel.typeString); + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (mapValue.get(key) instanceof Variable) { + childResType = ((Variable) mapValue.get(key)).getType(); + } else if (mapValue.get(key) instanceof Term) { + childResType = ((Term) mapValue.get(key)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childExp, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, mapValue.get(key)); + state.addChildState(key, childInfo.getKey()); + createInfo.getValue().addAll(childInfo.getValue()); + createInfo = new AbstractMap.SimpleEntry<>(state, createInfo.getValue()); + } + return createInfo; + } else if (resStateValue instanceof Term) { + Term mapValue = (Term) resStateValue; + if (mapValue.getSymbol().equals(DataConstraintModel.insert)) { + Expression childKeyExp = mapValue.getChild(1); + if (childKeyExp instanceof Term) { + childKeyExp = ((Term) childKeyExp).substitute(curResVar, resCurStateVal); + childKeyExp = ((Term) childKeyExp).reduce(); + } + if (childKeyExp instanceof Constant) { + List createdResources = new ArrayList<>(); + MapResourceState state = new MapResourceState(); + if (mapValue.getChild(0) instanceof Term) { + if (mapValue.getChild(0) instanceof Constant && ((Constant) mapValue.getChild(0)).getSymbol().equals(DataConstraintModel.nil)) { + // If the child map is nil. + } else { + Expression childMap = ((Term) mapValue.getChild(0)); + childMap = ((Term) childMap).substitute(curResVar, resStateValue); + childMap = ((Term) childMap).reduce(); + if (childMap instanceof MapTerm) { + // If the child map is a map literal. + Map.Entry> childInfo = createResourceState(resourceIdentifier, curResVar, resCurStateVal, childMap); // one more recursion. + state = (MapResourceState) childInfo.getKey(); + if (childInfo != null) createdResources.addAll(childInfo.getValue()); + } else if (childMap instanceof Term) { + // If the child map is a map term. + Map.Entry> childInfo = createResourceState(resourceIdentifier, curResVar, resCurStateVal, mapValue.getChild(0)); + state = (MapResourceState) childInfo.getKey(); + if (childInfo != null) createdResources.addAll(childInfo.getValue()); + } + } + } + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (mapValue.getChild(2) instanceof Variable) { + childResType = ((Variable) mapValue.getChild(2)).getType(); + } else if (mapValue.getChild(2) instanceof Term) { + childResType = ((Term) mapValue.getChild(2)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childKeyExp, childResourceHierarchy); + String childId = (String) ((Constant) childKeyExp).getValue(); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, mapValue.getChild(2)); + state.addChildState(childId, childInfo.getKey()); + createdResources.addAll(childInfo.getValue()); + return new AbstractMap.SimpleEntry<>(state, createdResources); + } + } else if (mapValue.getSymbol().equals(DataConstraintModel.delete)) { + Expression childKeyExp = mapValue.getChild(1); + if (childKeyExp instanceof Term) { + childKeyExp = ((Term) childKeyExp).substitute(curResVar, resCurStateVal); + childKeyExp = ((Term) childKeyExp).reduce(); + } + if (childKeyExp instanceof Constant) { + List createdResources = new ArrayList<>(); + MapResourceState state = new MapResourceState(); + if (mapValue.getChild(0) instanceof Term) { + if (mapValue.getChild(0) instanceof Constant && ((Constant) mapValue.getChild(0)).getSymbol().equals(DataConstraintModel.nil)) { + // If the child map is nil. + } else { + Expression childMap = ((Term) mapValue.getChild(0)); + childMap = ((Term) childMap).substitute(curResVar, resStateValue); + childMap = ((Term) childMap).reduce(); + if (childMap instanceof MapTerm) { + // If the child map is a map literal. + Map.Entry> childInfo = createResourceState(resourceIdentifier, curResVar, resCurStateVal, childMap); // one more recursion. + state = (MapResourceState) childInfo.getKey(); + if (childInfo != null) createdResources.addAll(childInfo.getValue()); + } else if (childMap instanceof Term) { + // If the child map is a map term. + Map.Entry> childInfo = createResourceState(resourceIdentifier, curResVar, resCurStateVal, mapValue.getChild(0)); + state = (MapResourceState) childInfo.getKey(); + if (childInfo != null) createdResources.addAll(childInfo.getValue()); + } + } + } + String childId = (String) ((Constant) childKeyExp).getValue(); + ((MapResourceState) state).removeChildState(childId); + return new AbstractMap.SimpleEntry<>(state, createdResources); + } + } else { + mapValue = mapValue.substitute(curResVar, resCurStateVal); + Expression mapExp = mapValue.reduce(); + if (mapExp instanceof MapTerm) { + MapTerm mapVal = (MapTerm) mapExp; + MapResourceState state = new MapResourceState(); + Map.Entry> createInfo = new AbstractMap.SimpleEntry<>(null, new ArrayList<>()); + for (String key: mapVal.keySet()) { + Expression childExp = new Constant(key, DataConstraintModel.typeString); + ResourceHierarchy childResourceHierarchy = null; + if (resourceIdentifier.getResourceHierarchy().getChildren() != null && resourceIdentifier.getResourceHierarchy().getChildren().size() > 0) { + childResourceHierarchy = resourceIdentifier.getResourceHierarchy().getChildren().iterator().next(); + } else { + Type childResType = null; + if (mapVal.get(key) instanceof Variable) { + childResType = ((Variable) mapVal.get(key)).getType(); + } else if (mapVal.get(key) instanceof Term) { + childResType = ((Term) mapVal.get(key)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), 1, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, childExp, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, mapVal.get(key)); + state.addChildState(key, childInfo.getKey()); + createInfo.getValue().addAll(childInfo.getValue()); + createInfo = new AbstractMap.SimpleEntry<>(state, createInfo.getValue()); + } + return createInfo; + } + } + } + } else if (DataConstraintModel.typeJson.isAncestorOf(resType)) { + if (resStateValue instanceof Constant) { + } else if (resStateValue instanceof JsonTerm) { + JsonTerm jsonValue = (JsonTerm) resStateValue; + JsonResourceState state = new JsonResourceState(); + Map.Entry> createInfo = new AbstractMap.SimpleEntry<>(null, new ArrayList<>()); + for (String key: jsonValue.keySet()) { + ResourceHierarchy childResourceHierarchy = null; + for (ResourceHierarchy childRes: resourceIdentifier.getResourceHierarchy().getChildren()) { + if (childRes.getResourceName().equals(key)) { + childResourceHierarchy = childRes; + break; + } + } + if (childResourceHierarchy == null) { + Type childResType = null; + if (jsonValue.get(key) instanceof Variable) { + childResType = ((Variable) jsonValue.get(key)).getType(); + } else if (jsonValue.get(key) instanceof Term) { + childResType = ((Term) jsonValue.get(key)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), key, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, key, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, jsonValue.get(key)); + ResourceState childState = childInfo.getKey(); + Resource res = getResource(resourceIdentifier); + if (res != null && res.getChildrenMap() != null && res.getChildrenMap().get(key) != null) { + res.getChildrenMap().get(key).changeState(childState); + } + state.addChildState(key, childState); + createInfo.getValue().addAll(childInfo.getValue()); + createInfo = new AbstractMap.SimpleEntry<>(state, createInfo.getValue()); + } + return createInfo; + } else if (resStateValue instanceof Term) { + Term jsonValue = (Term) resStateValue; + JsonResourceState state = new JsonResourceState(); + Map.Entry> createInfo = new AbstractMap.SimpleEntry<>(null, new ArrayList<>()); + if (jsonValue.getSymbol().equals(DataConstraintModel.addMember)) { + while (jsonValue.getSymbol().equals(DataConstraintModel.addMember)) { + Expression childExp = jsonValue.getChild(1); + if (childExp instanceof Constant) { + String memberName = (String) ((Constant) childExp).getValue(); + ResourceHierarchy childResourceHierarchy = null; + for (ResourceHierarchy childRes: resourceIdentifier.getResourceHierarchy().getChildren()) { + if (childRes.getResourceName().equals(memberName)) { + childResourceHierarchy = childRes; + break; + } + } + if (childResourceHierarchy == null) { + Type childResType = null; + if (jsonValue.getChild(2) instanceof Variable) { + childResType = ((Variable) jsonValue.getChild(2)).getType(); + } else if (jsonValue.getChild(2) instanceof Term) { + childResType = ((Term) jsonValue.getChild(2)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), memberName, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, memberName, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, jsonValue.getChild(2)); + state.addChildState(memberName, childInfo.getKey()); + createInfo.getValue().addAll(childInfo.getValue()); + createInfo = new AbstractMap.SimpleEntry<>(state, createInfo.getValue()); + } + if (!(jsonValue.getChild(0) instanceof Term)) break; + jsonValue = (Term) jsonValue.getChild(0); + } + } else { + jsonValue = jsonValue.substitute(curResVar, resCurStateVal); + Expression jsonExp = jsonValue.reduce(); + if (jsonExp instanceof JsonTerm) { + JsonTerm jsonVal = (JsonTerm) jsonExp; + for (String key: jsonVal.keySet()) { + ResourceHierarchy childResourceHierarchy = null; + for (ResourceHierarchy childRes: resourceIdentifier.getResourceHierarchy().getChildren()) { + if (childRes.getResourceName().equals(key)) { + childResourceHierarchy = childRes; + break; + } + } + if (childResourceHierarchy == null) { + Type childResType = null; + if (jsonVal.get(key) instanceof Variable) { + childResType = ((Variable) jsonVal.get(key)).getType(); + } else if (jsonVal.get(key) instanceof Term) { + childResType = ((Term) jsonVal.get(key)).getType(); + } + childResourceHierarchy = new ResourceHierarchy(resourceIdentifier.getResourceHierarchy(), key, childResType); + } + ResourceIdentifier childResourceIdentifier = new ResourceIdentifier(resourceIdentifier, key, childResourceHierarchy); + Map.Entry> childInfo = createResourceState(childResourceIdentifier, curResVar, resCurStateVal, jsonVal.get(key)); + ResourceState childState = childInfo.getKey(); + Resource res = getResource(resourceIdentifier); + if (res != null && res.getChildrenMap() != null && res.getChildrenMap().get(key) != null) { + res.getChildrenMap().get(key).changeState(childState); + } + state.addChildState(key, childState); + createInfo.getValue().addAll(childInfo.getValue()); + createInfo = new AbstractMap.SimpleEntry<>(state, createInfo.getValue()); + } + } + } + return createInfo; + } + } + } + if (curResVar != null && resCurStateVal != null) { + if (resStateValue instanceof Term) { + resStateValue = ((Term) resStateValue).substitute(curResVar, resCurStateVal); + resStateValue = ((Term) resStateValue).reduce(); + } + } + if (resStateValue instanceof Constant) { + Resource res = getResource(resourceIdentifier); + ResourceState state = null; + if (res != null) { + state = res.getState(); + ((PrimitiveResourceState) state).setValue((Constant) resStateValue); + } else { + state = new PrimitiveResourceState((Constant) resStateValue); + } + List updatedResources = new ArrayList<>(); + updatedResources.add(resourceIdentifier); + return new AbstractMap.SimpleEntry<>(state, updatedResources); + } + return null; + } + + public Map getChannelStates() { + return channelStates; + } + + public ChannelState getChannelState(DataTransferChannel channel) { + return channelStates.get(channel); + } + + public void addChannel(DataTransferChannel channel) { + channelStates.put(channel, null); + } + + public void updateChannelState(DataTransferChannel channel, ChannelState channelState) { + channelStates.put(channel, channelState); + } + + public List getEvents() { + return events; + } + + public void addEvent(Event event) { + events.add(event); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/INativeInitializer.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/INativeInitializer.java new file mode 100644 index 0000000..fc73bdc --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/INativeInitializer.java @@ -0,0 +1,7 @@ +package simulator.interfaces; + +import simulator.SystemState; + +public interface INativeInitializer { + public void onInitFromModel(SystemState initialSystemState); +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/INativeReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/INativeReceiver.java new file mode 100644 index 0000000..296506a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/INativeReceiver.java @@ -0,0 +1,8 @@ +package simulator.interfaces; + +import simulator.Event; +import simulator.SystemState; + +public interface INativeReceiver { + public void onReceiveFromModel(Event event, SystemState nextSystemState); +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/NativeSender.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/NativeSender.java new file mode 100644 index 0000000..a286401 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/NativeSender.java @@ -0,0 +1,40 @@ +package simulator.interfaces; + +import java.util.HashSet; +import java.util.Set; + +import models.algebra.Expression; +import models.algebra.InvalidMessage; +import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.UnificationFailed; +import models.algebra.ValueUndefined; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ResourcePath; +import models.dataFlowModel.DataTransferChannel; +import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; +import simulator.Event; +import simulator.Resource; +import simulator.Simulator; + +abstract public class NativeSender { + protected Simulator simulator; + protected DataTransferChannel channel; + protected ResourcePath resourcePath; + protected Resource resource; + + public NativeSender(Simulator simulator, DataTransferChannel channel, ResourcePath resourcePath, Resource resource) { + this.simulator = simulator; + this.channel = channel; + this.resourcePath = resourcePath; + this.resource = resource; + } + + public void sendToModel(Expression message) { + try { + Event event = new Event(channel, message, resourcePath, resource); + simulator.transition(event); + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentHeightReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentHeightReceiver.java new file mode 100644 index 0000000..9d6aad1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentHeightReceiver.java @@ -0,0 +1,35 @@ +package simulator.interfaces.swing; + +import java.awt.Component; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.text.JTextComponent; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import simulator.Event; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; + +public class ComponentHeightReceiver implements INativeReceiver { + protected Component component; + + public ComponentHeightReceiver(Component component) { + this.component = component; + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + if (message instanceof Term) { + Expression height = ((Term) message).getChild(0); + if (height instanceof Constant) { + int curWidth = component.getSize().width; + component.setSize(curWidth, Integer.parseInt(height.toString())); + } + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentMouseSender.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentMouseSender.java new file mode 100644 index 0000000..f90d46b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentMouseSender.java @@ -0,0 +1,47 @@ +package simulator.interfaces.swing; + +import java.awt.Component; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ResourcePath; +import models.dataFlowModel.DataTransferChannel; +import simulator.Resource; +import simulator.Simulator; +import simulator.interfaces.NativeSender; + +public class ComponentMouseSender extends NativeSender implements MouseListener { + + public ComponentMouseSender(Simulator simulator, DataTransferChannel channel, ResourcePath resourcePath, Resource resource) { + super(simulator, channel, resourcePath, resource); + } + + public void mouseClicked(MouseEvent e) { + } + + public void mousePressed(MouseEvent e) { + Constant one = new Constant("1", DataConstraintModel.typeInt); + Expression message = channel.getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); + message = (Term) message.clone(); + ((Term) message).setChild(0, one); + sendToModel(message); + } + + public void mouseReleased(MouseEvent e) { + Constant zero = new Constant("0", DataConstraintModel.typeInt); + Expression message = channel.getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); + message = (Term) message.clone(); + ((Term) message).setChild(0, zero); + sendToModel(message); + } + + public void mouseEntered(MouseEvent e) { + } + + public void mouseExited(MouseEvent e) { + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextReceiver.java new file mode 100644 index 0000000..5ab8b63 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextReceiver.java @@ -0,0 +1,40 @@ +package simulator.interfaces.swing; + +import java.awt.Component; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.text.JTextComponent; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import simulator.Event; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; + +public class ComponentTextReceiver implements INativeReceiver { + protected Component component; + + public ComponentTextReceiver(Component component) { + this.component = component; + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + if (message instanceof Term) { + Expression text = ((Term) message).getChild(0); + if (text instanceof Constant) { + if (component instanceof JTextComponent) { + ((JTextComponent) component).setText((String) ((Constant) text).getValue()); + } else if (component instanceof JLabel) { + ((JLabel) component).setText((String) ((Constant) text).getValue()); + } else if (component instanceof JButton) { + ((JButton) component).setText((String) ((Constant) text).getValue()); + } + } + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextSender.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextSender.java new file mode 100644 index 0000000..c6580fd --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentTextSender.java @@ -0,0 +1,66 @@ +package simulator.interfaces.swing; + +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ResourcePath; +import models.dataFlowModel.DataTransferChannel; +import simulator.Resource; +import simulator.Simulator; +import simulator.interfaces.NativeSender; + +public class ComponentTextSender extends NativeSender implements DocumentListener { + + public ComponentTextSender(Simulator simulator, DataTransferChannel channel, ResourcePath resourcePath, Resource resource) { + super(simulator, channel, resourcePath, resource); + } + + @Override + public void insertUpdate(DocumentEvent e) { + Document d = e.getDocument(); + try { + Constant text = new Constant(d.getText(0, d.getLength()), DataConstraintModel.typeString); + Expression message = channel.getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); + message = (Term) message.clone(); + ((Term) message).setChild(0, text); + sendToModel(message); + } catch (BadLocationException e1) { + e1.printStackTrace(); + } + } + + @Override + public void removeUpdate(DocumentEvent e) { + Document d = e.getDocument(); + try { + Constant text = new Constant(d.getText(0, d.getLength()), DataConstraintModel.typeString); + Expression message = channel.getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); + message = (Term) message.clone(); + ((Term) message).setChild(0, text); + sendToModel(message); + } catch (BadLocationException e1) { + e1.printStackTrace(); + } + } + + @Override + public void changedUpdate(DocumentEvent e) { + Document d = e.getDocument(); + try { + Constant text = new Constant(d.getText(0, d.getLength()), DataConstraintModel.typeString); + Expression message = channel.getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); + message = (Term) message.clone(); + ((Term) message).setChild(0, text); + sendToModel(message); + } catch (BadLocationException e1) { + e1.printStackTrace(); + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentVisibilityReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentVisibilityReceiver.java new file mode 100644 index 0000000..447dae1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentVisibilityReceiver.java @@ -0,0 +1,35 @@ +package simulator.interfaces.swing; + +import java.awt.Component; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.DataConstraintModel; +import simulator.Event; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; + +public class ComponentVisibilityReceiver implements INativeReceiver { + protected Component component; + + public ComponentVisibilityReceiver(Component component) { + this.component = component; + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + if (message instanceof Term) { + Expression visible = ((Term) message).getChild(0); + if (visible instanceof Constant) { + if (((Constant) visible).getSymbol() == DataConstraintModel.true_) { + component.setVisible(true); + } else { + component.setVisible(false); + } + } + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentWidthReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentWidthReceiver.java new file mode 100644 index 0000000..76c0dda --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentWidthReceiver.java @@ -0,0 +1,35 @@ +package simulator.interfaces.swing; + +import java.awt.Component; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.text.JTextComponent; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import simulator.Event; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; + +public class ComponentWidthReceiver implements INativeReceiver { + protected Component component; + + public ComponentWidthReceiver(Component component) { + this.component = component; + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + if (message instanceof Term) { + Expression width = ((Term) message).getChild(0); + if (width instanceof Constant) { + int curHeight = component.getSize().height; + component.setSize(Integer.parseInt(width.toString()), curHeight); + } + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentXReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentXReceiver.java new file mode 100644 index 0000000..2867e97 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentXReceiver.java @@ -0,0 +1,35 @@ +package simulator.interfaces.swing; + +import java.awt.Component; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.text.JTextComponent; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import simulator.Event; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; + +public class ComponentXReceiver implements INativeReceiver { + protected Component component; + + public ComponentXReceiver(Component component) { + this.component = component; + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + if (message instanceof Term) { + Expression x = ((Term) message).getChild(0); + if (x instanceof Constant) { + int curY = component.getLocation().y; + component.setLocation(Integer.parseInt(x.toString()), curY); + } + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentYReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentYReceiver.java new file mode 100644 index 0000000..a964f6b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/ComponentYReceiver.java @@ -0,0 +1,35 @@ +package simulator.interfaces.swing; + +import java.awt.Component; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.text.JTextComponent; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import simulator.Event; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; + +public class ComponentYReceiver implements INativeReceiver { + protected Component component; + + public ComponentYReceiver(Component component) { + this.component = component; + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + if (message instanceof Term) { + Expression y = ((Term) message).getChild(0); + if (y instanceof Constant) { + int curX = component.getLocation().x; + component.setLocation(curX, Integer.parseInt(y.toString())); + } + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java new file mode 100644 index 0000000..bdd76dd --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java @@ -0,0 +1,551 @@ +package simulator.interfaces.swing; + +import java.awt.Component; +import java.awt.FlowLayout; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.table.DefaultTableModel; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.JsonTerm; +import models.dataConstraintModel.ListTerm; +import models.dataConstraintModel.MapTerm; +import models.dataConstraintModel.ResourcePath; +import models.dataFlowModel.DataTransferChannel; +import simulator.Event; +import simulator.Resource; +import simulator.Simulator; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; + +public class SwingPresenter implements INativeReceiver { + // Native channel names. + public final String screenUpdateChannelName = "ScreenUpdate"; + public final String setLayoutChannelName = "SetLayout"; + public final String setVisibleChannelName = "SetVisible"; + public final String setTextChannelName = "SetText"; + public final String setXChannelName = "SetX"; + public final String setYChannelName = "SetY"; + public final String setWidthChannelName = "SetWidth"; + public final String setHeightChannelName = "SetHeight"; + public final String mouseEventChannelName = "MouseEvent"; + public final String textEventChannelName = "TextEvent"; + public final String OnTableChangedChannelName = "OnTableChanged"; + + protected JPanel mainPanel; + protected Simulator simulator; + protected Map components; + + // Native channels. + protected DataTransferChannel screenUpdateChannel; + protected DataTransferChannel setLayoutChannel; + protected DataTransferChannel setVisibleChannel; + protected DataTransferChannel setTextChannel; + protected DataTransferChannel setXChannel; + protected DataTransferChannel setYChannel; + protected DataTransferChannel setWidthChannel; + protected DataTransferChannel setHeightChannel; + protected DataTransferChannel mouseEventChannel; + protected DataTransferChannel textEventChannel; + protected DataTransferChannel onTableChangedChannel; + + protected Map> channelAndResourcesForReceiving = new HashMap<>(); + + public SwingPresenter(JPanel mainPanel, Simulator simulator) { + this.mainPanel = mainPanel; + this.simulator = simulator; + components = new HashMap<>(); + screenUpdateChannel = (DataTransferChannel) simulator.getModel().getChannel(screenUpdateChannelName); + setLayoutChannel = (DataTransferChannel) simulator.getModel().getChannel(setLayoutChannelName); + setVisibleChannel = (DataTransferChannel) simulator.getModel().getChannel(setVisibleChannelName); + setTextChannel = (DataTransferChannel) simulator.getModel().getChannel(setTextChannelName); + setXChannel = (DataTransferChannel) simulator.getModel().getChannel(setXChannelName); + setYChannel = (DataTransferChannel) simulator.getModel().getChannel(setYChannelName); + setWidthChannel = (DataTransferChannel) simulator.getModel().getChannel(setWidthChannelName); + setHeightChannel = (DataTransferChannel) simulator.getModel().getChannel(setHeightChannelName); + mouseEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(mouseEventChannelName); + textEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(textEventChannelName); + onTableChangedChannel = (DataTransferChannel)simulator.getModel().getChannel(OnTableChangedChannelName); + simulator.addNativeReceiver(this, screenUpdateChannel); + simulator.addNativeReceiver(new SwingLayout(), setLayoutChannel); + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + if (message instanceof Term && ((Term) message).getChildren().size() >= 2) { + Expression curScExp = ((Term) message).getChild(0); + Expression nextScExp = ((Term) message).getChild(1); + if (curScExp instanceof JsonTerm && nextScExp instanceof JsonTerm) { + JsonTerm curSc = (JsonTerm) curScExp; + JsonTerm nextSc = (JsonTerm) nextScExp; + Expression newLayout = nextSc.get("layout"); + if (newLayout != null) { + if (newLayout.toString().equals("true")) { + mainPanel.setLayout(new FlowLayout()); + } else if (newLayout.toString().equals("false")) { + mainPanel.setLayout(null); + } + } + Expression oldWidgets = curSc.get("widgets"); + Expression newWidgets = nextSc.get("widgets"); + if (oldWidgets instanceof MapTerm && newWidgets instanceof MapTerm) { + Set oldWidSet = new HashSet<>(((MapTerm) oldWidgets).keySet()); + Set newWidSet = new HashSet<>(((MapTerm) newWidgets).keySet()); + oldWidSet.removeAll(((MapTerm) newWidgets).keySet()); + newWidSet.removeAll(((MapTerm) oldWidgets).keySet()); + if (!oldWidSet.isEmpty() || !newWidSet.isEmpty()) { + // If the set of screen components is changed. + + // Remove old components and their native receivers. + for (String oldWid: oldWidSet) { + mainPanel.remove(components.get(oldWid)); + } + + for (DataTransferChannel channel: channelAndResourcesForReceiving.keySet()) { + Map widToResource = channelAndResourcesForReceiving.get(channel); + for (String oldWid: oldWidSet) { + Resource resource = widToResource.remove(oldWid); + if (resource != null) { + simulator.removeNativeReceiver(channel, resource); + } + } + } + + // Add new swing components. + Resource screenResource = nextSystemState.getResource(event.getInputResource().getResourceIdentifier()); + Resource widgetsResource = screenResource.getChildrenMap().get("widgets"); + for (String newWid: newWidSet) { + Expression value = ((MapTerm) newWidgets).get(newWid); + if (value instanceof JsonTerm) { + JsonTerm widget = (JsonTerm) value; + Resource widgetResource = widgetsResource.getChildrenMap().get(newWid); + Expression type = widget.get("type"); + if (type instanceof Constant && ((String)((Constant) type).getValue()).equals("button")) { + // Add a button component. + Expression text = widget.get("text"); + Expression x = widget.get("x"); + Expression y = widget.get("y"); + Expression width = widget.get("width"); + Expression height = widget.get("height"); + JButton button = new JButton(((String)((Constant) text).getValue())); + if (x != null && y != null) { + button.setLocation(Integer.parseInt(x.toString()), Integer.parseInt(y.toString())); + } + if (width != null && height != null) { + button.setSize(Integer.parseInt(width.toString()), Integer.parseInt(height.toString())); + } + mainPanel.add(button); + components.put(newWid, button); + // Connect swing component and model. + ResourcePath resPath = mouseEventChannel.getOutputResources().iterator().next(); + button.addMouseListener(new ComponentMouseSender(simulator, mouseEventChannel, resPath, widgetResource)); // button => widgetResource + + ComponentVisibilityReceiver nativeVisibilityReceiver = new ComponentVisibilityReceiver(button); // widgetResource => button + simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource.getChildrenMap().get("visible")); + Map resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.put(newWid, widgetResource); + + ComponentTextReceiver nativeTextReceiver = new ComponentTextReceiver(button); // widgetResource => button + simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource.getChildrenMap().get("text")); + resources = channelAndResourcesForReceiving.get(setTextChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setTextChannel, resources); + } + resources.put(newWid, widgetResource); + + Resource widgetXResource = widgetResource.getChildrenMap().get("x"); + if (widgetXResource != null) { + ComponentXReceiver nativeXReceiver = new ComponentXReceiver(button); // widgetResource => button + simulator.addNativeReceiver(nativeXReceiver, setXChannel, widgetXResource); + resources = channelAndResourcesForReceiving.get(setXChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setXChannel, resources); + } + resources.put(newWid, widgetXResource); + } + + Resource widgetYResource = widgetResource.getChildrenMap().get("y"); + if (widgetYResource != null) { + ComponentYReceiver nativeYReceiver = new ComponentYReceiver(button); // widgetResource => button + simulator.addNativeReceiver(nativeYReceiver, setYChannel, widgetYResource); + resources = channelAndResourcesForReceiving.get(setYChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setYChannel, resources); + } + resources.put(newWid, widgetYResource); + } + + Resource widgetWidthResource = widgetResource.getChildrenMap().get("width"); + if (widgetWidthResource != null) { + ComponentWidthReceiver nativeWidthReceiver = new ComponentWidthReceiver(button); // widgetResource => button + simulator.addNativeReceiver(nativeWidthReceiver, setWidthChannel, widgetWidthResource); + resources = channelAndResourcesForReceiving.get(setWidthChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setWidthChannel, resources); + } + resources.put(newWid, widgetWidthResource); + } + + Resource widgetHeightResource = widgetResource.getChildrenMap().get("height"); + if (widgetHeightResource != null) { + ComponentHeightReceiver nativeHeightReceiver = new ComponentHeightReceiver(button); // widgetResource => button + simulator.addNativeReceiver(nativeHeightReceiver, setHeightChannel, widgetHeightResource); + resources = channelAndResourcesForReceiving.get(setHeightChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setHeightChannel, resources); + } + resources.put(newWid, widgetHeightResource); + } + } else if (type instanceof Constant && ((String)((Constant) type).getValue()).equals("label")) { + // Add a label component. + Expression text = widget.get("text"); + Expression x = widget.get("x"); + Expression y = widget.get("y"); + Expression width = widget.get("width"); + Expression height = widget.get("height"); + JLabel label = new JLabel(((String) ((Constant) text).getValue())); + if (x != null && y != null) { + label.setLocation(Integer.parseInt(x.toString()), Integer.parseInt(y.toString())); + } + if (width != null && height != null) { + label.setSize(Integer.parseInt(width.toString()), Integer.parseInt(height.toString())); + } + mainPanel.add(label); + components.put(newWid, label); + + // Connect swing component and model. + ComponentVisibilityReceiver nativeVisibilityReceiver = new ComponentVisibilityReceiver(label); // widgetResource => label + simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource.getChildrenMap().get("visible")); + Map resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.put(newWid, widgetResource); + + ComponentTextReceiver nativeTextReceiver = new ComponentTextReceiver(label); // widgetResource => label + simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource.getChildrenMap().get("text")); + resources = channelAndResourcesForReceiving.get(setTextChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setTextChannel, resources); + } + resources.put(newWid, widgetResource); + + Resource widgetXResource = widgetResource.getChildrenMap().get("x"); + if (widgetXResource != null) { + ComponentXReceiver nativeXReceiver = new ComponentXReceiver(label); // widgetResource => label + simulator.addNativeReceiver(nativeXReceiver, setXChannel, widgetXResource); + resources = channelAndResourcesForReceiving.get(setXChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setXChannel, resources); + } + resources.put(newWid, widgetXResource); + } + + Resource widgetYResource = widgetResource.getChildrenMap().get("y"); + if (widgetYResource != null) { + ComponentYReceiver nativeYReceiver = new ComponentYReceiver(label); // widgetResource => label + simulator.addNativeReceiver(nativeYReceiver, setYChannel, widgetYResource); + resources = channelAndResourcesForReceiving.get(setYChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setYChannel, resources); + } + resources.put(newWid, widgetYResource); + } + + Resource widgetWidthResource = widgetResource.getChildrenMap().get("width"); + if (widgetWidthResource != null) { + ComponentWidthReceiver nativeWidthReceiver = new ComponentWidthReceiver(label); // widgetResource => label + simulator.addNativeReceiver(nativeWidthReceiver, setWidthChannel, widgetWidthResource); + resources = channelAndResourcesForReceiving.get(setWidthChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setWidthChannel, resources); + } + resources.put(newWid, widgetWidthResource); + } + + Resource widgetHeightResource = widgetResource.getChildrenMap().get("height"); + if (widgetHeightResource != null) { + ComponentHeightReceiver nativeHeightReceiver = new ComponentHeightReceiver(label); // widgetResource => label + simulator.addNativeReceiver(nativeHeightReceiver, setHeightChannel, widgetHeightResource); + resources = channelAndResourcesForReceiving.get(setHeightChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setHeightChannel, resources); + } + resources.put(newWid, widgetHeightResource); + } + } else if (type instanceof Constant && ((String)((Constant) type).getValue()).equals("table")) { + // Add a label component. + Expression text = widget.get("text"); + Expression x = widget.get("x"); + Expression y = widget.get("y"); + Expression width = widget.get("width"); + Expression height = widget.get("height"); + MapTerm data = (MapTerm)widget.get("data"); + ListTerm columnsList = (ListTerm)widget.get("columns"); + Constant rowNumExp = (Constant)widget.get("rowNum"); + Constant rowHeightExp = (Constant)widget.get("rowHeight"); + Constant primaryKeyNameExp = (Constant) widget.get("primaryKeyName"); + boolean primaryKeyVisible = !primaryKeyNameExp.getValue().equals(""); + +// JLabel label = new JLabel(((String) ((Constant) text).getValue())); + int colNum = columnsList.size() + (primaryKeyVisible ? 1 : 0); + String[] columns = new String[colNum]; + String[][] tableDatas = new String[data.keySet().size()][colNum]; + if(primaryKeyVisible) { + columns[0] = (String)primaryKeyNameExp.getValue(); + for(int i = 1; i < colNum; i++) { + columns[i] = (String)((Constant)columnsList.get(i - 1)).getValue(); + } + } else { + for(int i = 0; i < colNum; i++) { + columns[i] = (String)((Constant)columnsList.get(i)).getValue(); + } + } + int dataCount = 0; + for(String dataKey : data.keySet()) { + JsonTerm rowData = (JsonTerm) data.get(dataKey); + if(primaryKeyVisible) { + tableDatas[dataCount][0] = dataKey; + for(int j = 1; j < columns.length; j++) { + Constant cellValue = (Constant) rowData.get(columns[j]); + if(cellValue == null) { + tableDatas[dataCount][j] = "error"; + } else { + tableDatas[dataCount][j] = (String)((Constant) rowData.get(columns[j])).getValue(); + } + } + } else { + for(int j = 0; j < columns.length; j++) { + Constant cellValue = (Constant) rowData.get(columns[j]); + if(cellValue == null) { + tableDatas[dataCount][j] = "error"; + } else { + tableDatas[dataCount][j] = (String)((Constant) rowData.get(columns[j])).getValue(); + } + } + } + dataCount++; + } + DefaultTableModel tableModel = new DefaultTableModel(tableDatas, columns); + JTable table = new JTable(tableModel) { + @Override + public boolean isCellEditable(int row, int col) { + return false; + } + }; + JScrollPane scroll = new JScrollPane(table); + + if (x != null && y != null) { + scroll.setLocation(Integer.parseInt(x.toString()), Integer.parseInt(y.toString())); + } + if (width != null && height != null) { + scroll.setSize(Integer.parseInt(width.toString()), Integer.parseInt(height.toString())); + } + mainPanel.add(scroll); + components.put(newWid, scroll); + + // Connect swing component and model. + ComponentVisibilityReceiver nativeVisibilityReceiver = new ComponentVisibilityReceiver(scroll); // widgetResource => label + simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource.getChildrenMap().get("visible")); + Map resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.put(newWid, widgetResource); + + Resource widgetXResource = widgetResource.getChildrenMap().get("x"); + if (widgetXResource != null) { + ComponentXReceiver nativeXReceiver = new ComponentXReceiver(scroll); // widgetResource => label + simulator.addNativeReceiver(nativeXReceiver, setXChannel, widgetXResource); + resources = channelAndResourcesForReceiving.get(setXChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setXChannel, resources); + } + resources.put(newWid, widgetXResource); + } + + Resource widgetYResource = widgetResource.getChildrenMap().get("y"); + if (widgetYResource != null) { + ComponentYReceiver nativeYReceiver = new ComponentYReceiver(scroll); // widgetResource => label + simulator.addNativeReceiver(nativeYReceiver, setYChannel, widgetYResource); + resources = channelAndResourcesForReceiving.get(setYChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setYChannel, resources); + } + resources.put(newWid, widgetYResource); + } + + Resource widgetWidthResource = widgetResource.getChildrenMap().get("width"); + if (widgetWidthResource != null) { + ComponentWidthReceiver nativeWidthReceiver = new ComponentWidthReceiver(scroll); // widgetResource => label + simulator.addNativeReceiver(nativeWidthReceiver, setWidthChannel, widgetWidthResource); + resources = channelAndResourcesForReceiving.get(setWidthChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setWidthChannel, resources); + } + resources.put(newWid, widgetWidthResource); + } + + Resource widgetHeightResource = widgetResource.getChildrenMap().get("height"); + if (widgetHeightResource != null) { + ComponentHeightReceiver nativeHeightReceiver = new ComponentHeightReceiver(scroll); // widgetResource => label + simulator.addNativeReceiver(nativeHeightReceiver, setHeightChannel, widgetHeightResource); + resources = channelAndResourcesForReceiving.get(setHeightChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setHeightChannel, resources); + } + resources.put(newWid, widgetHeightResource); + } + + Resource widgetDataResource = widgetResource.getChildrenMap().get("data"); + if(widgetDataResource != null ) { + TableDataReceiver tableDataReceiver = new TableDataReceiver(tableModel, columns, (String)((Constant) primaryKeyNameExp).getValue()); + simulator.addNativeReceiver(tableDataReceiver, onTableChangedChannel, widgetDataResource); + resources = channelAndResourcesForReceiving.get(onTableChangedChannel); + if(resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(onTableChangedChannel, resources); + } + resources.put(newWid, widgetDataResource); + } + + } else if (type instanceof Constant && ((String)((Constant) type).getValue()).equals("textInput")) { + // Add a text input component. + Expression x = widget.get("x"); + Expression y = widget.get("y"); + Expression width = widget.get("width"); + Expression height = widget.get("height"); + JTextField textField = new JTextField(10); + if (x != null && y != null) { + textField.setLocation(Integer.parseInt(x.toString()), Integer.parseInt(y.toString())); + } + if (width != null && height != null) { + textField.setSize(Integer.parseInt(width.toString()), Integer.parseInt(height.toString())); + } + mainPanel.add(textField); + components.put(newWid, textField); + // Connect swing component and model. + ResourcePath resPath = textEventChannel.getOutputResources().iterator().next(); + textField.getDocument().addDocumentListener(new ComponentTextSender(simulator, textEventChannel, resPath, widgetResource)); // textField => widgetResource + + ComponentVisibilityReceiver nativeReceiver = new ComponentVisibilityReceiver(textField); // widgetResource => textField + simulator.addNativeReceiver(nativeReceiver, setVisibleChannel, widgetResource.getChildrenMap().get("visible")); + Map resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.put(newWid, widgetResource); + + Resource widgetXResource = widgetResource.getChildrenMap().get("x"); + if (widgetXResource != null) { + ComponentXReceiver nativeXReceiver = new ComponentXReceiver(textField); // widgetResource => textField + simulator.addNativeReceiver(nativeXReceiver, setXChannel, widgetXResource); + resources = channelAndResourcesForReceiving.get(setXChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setXChannel, resources); + } + resources.put(newWid, widgetXResource); + } + + Resource widgetYResource = widgetResource.getChildrenMap().get("y"); + if (widgetYResource != null) { + ComponentYReceiver nativeYReceiver = new ComponentYReceiver(textField); // widgetResource => textField + simulator.addNativeReceiver(nativeYReceiver, setYChannel, widgetYResource); + resources = channelAndResourcesForReceiving.get(setYChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setYChannel, resources); + } + resources.put(newWid, widgetYResource); + } + + Resource widgetWidthResource = widgetResource.getChildrenMap().get("width"); + if (widgetWidthResource != null) { + ComponentWidthReceiver nativeWidthReceiver = new ComponentWidthReceiver(textField); // widgetResource => textField + simulator.addNativeReceiver(nativeWidthReceiver, setWidthChannel, widgetWidthResource); + resources = channelAndResourcesForReceiving.get(setWidthChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setWidthChannel, resources); + } + resources.put(newWid, widgetWidthResource); + } + + Resource widgetHeightResource = widgetResource.getChildrenMap().get("height"); + if (widgetHeightResource != null) { + ComponentHeightReceiver nativeHeightReceiver = new ComponentHeightReceiver(textField); // widgetResource => textField + simulator.addNativeReceiver(nativeHeightReceiver, setHeightChannel, widgetHeightResource); + resources = channelAndResourcesForReceiving.get(setHeightChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setHeightChannel, resources); + } + resources.put(newWid, widgetHeightResource); + } + } + } + } + mainPanel.invalidate(); + mainPanel.validate(); + mainPanel.repaint(); + } + } + } + } + } + + public class SwingLayout implements INativeReceiver { + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + if (message instanceof Term && ((Term) message).getChildren().size() >= 1) { + Expression newLayout = ((Term) message).getChild(0); + if (newLayout instanceof Constant) { + if (newLayout.toString().equals("true")) { + mainPanel.setLayout(new FlowLayout()); + } else if (newLayout.toString().equals("false")) { + mainPanel.setLayout(null); + } + } + } + } + + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/TableDataReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/TableDataReceiver.java new file mode 100644 index 0000000..f2ad1c0 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/TableDataReceiver.java @@ -0,0 +1,54 @@ +package simulator.interfaces.swing; +import javax.swing.table.DefaultTableModel; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.JsonTerm; +import models.dataConstraintModel.MapTerm; +import simulator.Event; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; + +public class TableDataReceiver implements INativeReceiver{ + + protected DefaultTableModel tableModel; + protected String[] columns; + protected String primaryKeyName; + protected boolean primaryKeyVisible; + + public TableDataReceiver(DefaultTableModel table, String[] columns, String primaryKeyName) { + this.tableModel = table; + this.columns = columns; + this.primaryKeyName = primaryKeyName; + this.primaryKeyVisible = !primaryKeyName.equals(""); + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + System.out.println(message); + if(message instanceof Term) { + MapTerm data = (MapTerm)((Term) message).getChild(0); + int colNum = columns.length + (primaryKeyVisible ? 1 : 0); + String[][] tableDatas = new String[data.keySet().size()][colNum]; + int dataCount = 0; + for(String dataKey : data.keySet()) { + JsonTerm rowData = (JsonTerm) data.get(dataKey); + if(primaryKeyVisible) { + tableDatas[dataCount][0] = dataKey; + for(int j = 1; j < columns.length; j++) { + tableDatas[dataCount][j] = (String)((Constant) rowData.get(columns[j])).getValue(); + } + } else { + for(int j = 0; j < columns.length; j++) { + tableDatas[dataCount][j] = (String)((Constant) rowData.get(columns[j])).getValue(); + } + } + dataCount++; + } + tableModel.setDataVector(tableDatas, columns); + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/timers/TimerEventSender.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/timers/TimerEventSender.java new file mode 100644 index 0000000..1dce61c --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/timers/TimerEventSender.java @@ -0,0 +1,24 @@ +package simulator.interfaces.timers; + +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.ResourcePath; +import models.dataFlowModel.DataTransferChannel; +import simulator.Resource; +import simulator.Simulator; +import simulator.interfaces.NativeSender; + +public class TimerEventSender extends NativeSender implements Runnable { + + public TimerEventSender(Simulator simulator, DataTransferChannel channel, ResourcePath resourcePath, Resource resource) { + super(simulator, channel, resourcePath, resource); + } + + @Override + public void run() { + Expression message = channel.getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); + message = (Expression) message.clone(); + sendToModel(message); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/timers/TimerService.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/timers/TimerService.java new file mode 100644 index 0000000..1ef8061 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/timers/TimerService.java @@ -0,0 +1,139 @@ +package simulator.interfaces.timers; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ScheduledThreadPoolExecutor; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.JsonTerm; +import models.dataConstraintModel.MapTerm; +import models.dataConstraintModel.ResourcePath; +import models.dataFlowModel.DataTransferChannel; +import simulator.Event; +import simulator.Resource; +import simulator.Simulator; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; + +public class TimerService implements INativeReceiver { + public final String timersUpdatedChannelName = "TimersUpdated"; + public final String timerEventChannelName = "TimerEvent"; + + protected final Simulator simulator; + protected final Map timers; + protected DataTransferChannel timersUpdatedChannel; + protected DataTransferChannel timerEventChannel; + + public TimerService(Simulator simulator) { + this.simulator = simulator; + timers = new HashMap<>(); + timersUpdatedChannel = (DataTransferChannel) simulator.getModel().getChannel(timersUpdatedChannelName); + timerEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(timerEventChannelName); + simulator.addNativeReceiver(this, timersUpdatedChannel); + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + if (message instanceof Term && ((Term) message).getChildren().size() >= 2) { + Expression curTimersExp = ((Term) message).getChild(0); + Expression nextTimersExp = ((Term) message).getChild(1); + if (curTimersExp instanceof MapTerm && nextTimersExp instanceof MapTerm) { + MapTerm curTimers = (MapTerm) curTimersExp; + MapTerm nextTimers = (MapTerm) nextTimersExp; + Set oldTidSet = new HashSet<>(curTimers.keySet()); + Set newTidSet = new HashSet<>(nextTimers.keySet()); + oldTidSet.removeAll(nextTimers.keySet()); + newTidSet.removeAll(curTimers.keySet()); + if (!oldTidSet.isEmpty() || !newTidSet.isEmpty()) { + // If the set of timers is changed. + + // Remove old timers and their native receivers. + for (String tid: oldTidSet) { + ScheduledThreadPoolExecutor timer = timers.get(tid); + timer.shutdown(); + timers.remove(tid); + } + + // Add new timers. + Resource timersResource = nextSystemState.getResource(event.getInputResource().getResourceIdentifier()); + for (String tid: newTidSet) { + Expression value = nextTimers.get(tid); + if (value instanceof JsonTerm) { + JsonTerm timerValue = (JsonTerm) value; + Resource timerResource = timersResource.getChildrenMap().get(tid); + // Add a timer. + Expression intervalExp = timerValue.get("interval"); + long interval = Long.parseLong(((Constant) intervalExp).toString()); + ScheduledThreadPoolExecutor timer = new ScheduledThreadPoolExecutor(0); + timers.put(tid, timer); + + // Connect Java timer and model. + ResourcePath resPath = timerEventChannel.getOutputResources().iterator().next(); + TimerEventSender sender = new TimerEventSender(simulator, timerEventChannel, resPath, timerResource); // timer => timerResource + timer.scheduleAtFixedRate(sender, 0, interval, TimeUnit.MILLISECONDS); + } + } + } + } + } + } + + public class TimerStart implements INativeReceiver { + public final String timerStartChannelName = "TimerStart"; + protected DataTransferChannel timerStartChannel; + protected DataTransferChannel timerEventChannel; + + public TimerStart() { + timerStartChannel = (DataTransferChannel) simulator.getModel().getChannel(timerStartChannelName); + timerEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(timerEventChannelName); + simulator.addNativeReceiver(this, timerStartChannel); + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + if (message instanceof Term && ((Term) message).getChildren().size() >= 1) { + Expression tidExp = event.getInputResource().getResourceIdentifier().getLastParam(); + Expression intervalExp = ((Term) message).getChild(0); + if (tidExp instanceof Constant && intervalExp instanceof Constant) { + String tid = ((Constant) tidExp).toString(); + long interval = Long.parseLong(((Constant) intervalExp).toString()); + ScheduledThreadPoolExecutor timer = timers.get(tid); + TimerEventSender sender = new TimerEventSender(simulator, timerEventChannel, event.getInputResourcePath(), event.getInputResource()); + timer.scheduleAtFixedRate(sender, 0, interval, TimeUnit.MILLISECONDS); + } + } + } + } + + public class TimerClear implements INativeReceiver { + public final String timerClearChannelName = "TimerClear"; + protected DataTransferChannel timerClearChannel; + + public TimerClear() { + timerClearChannel = (DataTransferChannel) simulator.getModel().getChannel(timerClearChannelName); + simulator.addNativeReceiver(this, timerClearChannel); + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + if (message instanceof Term && ((Term) message).getChildren().size() >= 1) { + Expression tidExp = event.getInputResource().getResourceIdentifier().getLastParam(); + if (tidExp instanceof Constant) { + String tid = ((Constant) tidExp).toString(); + ScheduledThreadPoolExecutor timer = timers.get(tid); + timer.shutdown(); + timers.remove(tid); + } + } + } + + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/CompositeResourceState.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/CompositeResourceState.java new file mode 100644 index 0000000..b445d14 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/CompositeResourceState.java @@ -0,0 +1,14 @@ +package simulator.states; + +import java.util.Map; + +public abstract class CompositeResourceState extends ResourceState { + @Override + boolean hasChildren() { + return true; + } + + public abstract Map getChildStates(); + public abstract void clearChildStates(); + public abstract void replaceChildState(ResourceState state, ResourceState newState); +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/JsonResourceState.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/JsonResourceState.java new file mode 100644 index 0000000..6ba7256 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/JsonResourceState.java @@ -0,0 +1,58 @@ +package simulator.states; + +import java.util.HashMap; +import java.util.Map; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonTerm; + +public class JsonResourceState extends CompositeResourceState { + private Map children = new HashMap<>(); + + @Override + public Expression getValue() { + JsonTerm value = new JsonTerm(); + value.setType(DataConstraintModel.typeJson); + for (Map.Entry childEnt: children.entrySet()) { + value.addMember(childEnt.getKey(), childEnt.getValue().getValue()); + } + return value; + } + + @Override + public Map getChildStates() { + return children; + } + + public void addChildState(String param, ResourceState childState) { + children.put(param, childState); + } + + public void removeChildState(String param) { + children.remove(param); + } + + public void clearChildStates() { + children.clear(); + } + + @Override + public void replaceChildState(ResourceState state, ResourceState newState) { + for (Map.Entry childEnt: children.entrySet()) { + if (childEnt.getValue().equals(state)) { + children.put(childEnt.getKey(), newState); + } + } + } + + public Object clone() { + JsonResourceState newJsonResourceState = new JsonResourceState(); + for (String key: children.keySet()) { + newJsonResourceState.children.put(key, (ResourceState) children.get(key).clone()); + } + return newJsonResourceState; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/ListResourceState.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/ListResourceState.java new file mode 100644 index 0000000..d45f9d2 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/ListResourceState.java @@ -0,0 +1,67 @@ +package simulator.states; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ListTerm; + +public class ListResourceState extends CompositeResourceState { + private List children = new ArrayList<>(); + + @Override + public Expression getValue() { + ListTerm value = new ListTerm(); + for (ResourceState child: children) { + value.append(child.getValue()); + } + return value; + } + + @Override + public Map getChildStates() { + Map childParams = new TreeMap<>(); + for (int i = 0; i < children.size(); i++) { + childParams.put(Integer.toString(i), children.get(i)); + } + return childParams; + } + + public void addChildState(ResourceState childState) { + children.add(childState); + } + + public void removeChildState(int idx) { + children.remove(idx); + } + + public void clearChildStates() { + children.clear(); + } + + @Override + public void replaceChildState(ResourceState state, ResourceState newState) { + for (int i = 0; i < children.size(); i++) { + if (children.get(i).equals(state)) { + children.set(i, newState); + } + } + } + + public void replaceChildState(int idx, ResourceState newState) { + children.set(idx, newState); + } + + public Object clone() { + ListResourceState newListResourceState = new ListResourceState(); + for (ResourceState state: children) { + newListResourceState.children.add((ResourceState) state.clone()); + } + return newListResourceState; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/MapResourceState.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/MapResourceState.java new file mode 100644 index 0000000..6ceecf4 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/MapResourceState.java @@ -0,0 +1,58 @@ +package simulator.states; + +import java.util.HashMap; +import java.util.Map; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.MapTerm; + +public class MapResourceState extends CompositeResourceState { + private Map children = new HashMap<>(); + + @Override + public Expression getValue() { + MapTerm value = new MapTerm(); + value.setType(DataConstraintModel.typeMap); + for (Map.Entry childEnt: children.entrySet()) { + value.insert(childEnt.getKey(), childEnt.getValue().getValue()); + } + return value; + } + + @Override + public Map getChildStates() { + return children; + } + + public void addChildState(String param, ResourceState childState) { + children.put(param, childState); + } + + public void removeChildState(String param) { + children.remove(param); + } + + public void clearChildStates() { + children.clear(); + } + + @Override + public void replaceChildState(ResourceState state, ResourceState newState) { + for (Map.Entry childEnt: children.entrySet()) { + if (childEnt.getValue().equals(state)) { + children.put(childEnt.getKey(), newState); + } + } + } + + public Object clone() { + MapResourceState newMapResourceState = new MapResourceState(); + for (String key: children.keySet()) { + newMapResourceState.children.put(key, (ResourceState) children.get(key).clone()); + } + return newMapResourceState; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/PrimitiveResourceState.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/PrimitiveResourceState.java new file mode 100644 index 0000000..19db331 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/PrimitiveResourceState.java @@ -0,0 +1,32 @@ +package simulator.states; + +import models.algebra.Constant; +import models.dataConstraintModel.DataConstraintModel; + +public class PrimitiveResourceState extends ResourceState { + private Constant value; + + public PrimitiveResourceState(Constant initialValue) { + value = initialValue; + } + + @Override + public Constant getValue() { + if (value == null) return new Constant(DataConstraintModel.null_); + return value; + } + + public void setValue(Constant newValue) { + value = newValue; + } + + @Override + boolean hasChildren() { + return false; + } + + public Object clone() { + if (value == null) return new PrimitiveResourceState(null); + return new PrimitiveResourceState((Constant) value.clone()); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/ResourceState.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/ResourceState.java new file mode 100644 index 0000000..7eba6c7 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/ResourceState.java @@ -0,0 +1,5 @@ +package simulator.states; + +abstract public class ResourceState extends State { + abstract boolean hasChildren(); +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/State.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/State.java new file mode 100644 index 0000000..00883d9 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/State.java @@ -0,0 +1,13 @@ +package simulator.states; + +import models.algebra.Expression; + +/** + * A state of a resource + * @author Nitta + * + */ +abstract public class State implements Cloneable { + abstract public Expression getValue(); + abstract public Object clone(); +} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java b/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java new file mode 100644 index 0000000..74be013 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java @@ -0,0 +1,170 @@ +package tests; + +import code.ast.*; +import generators.JavaSpecific; +import models.algebra.Symbol; +import models.algebra.Term; +import models.dataConstraintModel.DataConstraintModel; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +public class ASTTest { + @Test + public void test() { + + JavaSpecific javaGen = new JavaSpecific(); + MethodDeclaration methodDeclaration = javaGen.newMethodDeclaration("Test", JavaSpecific.typeVoid); + Block methodBody = new Block(); + + VariableDeclarationStatement variableDeclarationStatement = new VariableDeclarationStatement(); + variableDeclarationStatement.setModifiers(List.of(Modifier.PRIVATE)); + variableDeclarationStatement.setFragments(List.of( + new VariableDeclaration(DataConstraintModel.typeInt, "x"), + new VariableDeclaration(DataConstraintModel.typeInt, "sum") + )); + methodBody.addStatement(variableDeclarationStatement); + + ForStatement forStatement = javaGen.getForStatementForList("j", "list"); + Block forBody = new Block(); + forBody.addStatement(new ExpressionStatement( + new InfixExpression(new Symbol("+=", 2, Symbol.Type.INFIX), new Variable("sum"), new Variable("j")) + )); + forStatement.setBody(forBody); + methodBody.addStatement(forStatement); + + EnhancedForStatement efStmt = javaGen.getForStatementForCollection(new VariableDeclaration(DataConstraintModel.typeString, "s"), "list"); + Block efBody = new Block(); + efBody.addStatement("System.out.println(s);"); + efStmt.setBody(efBody); + methodBody.addStatement(efStmt); + + Term moduloTerm = new Term(new Symbol("%", 2, Symbol.Type.INFIX)); + moduloTerm.addChild(new models.algebra.Variable("sum")); + moduloTerm.addChild(new models.algebra.Constant("2")); + + Term ifCondTerm = new Term(new Symbol("==", 2, Symbol.Type.INFIX)); + ifCondTerm.addChild(moduloTerm); + ifCondTerm.addChild(new models.algebra.Constant("0"));Block thenBlock = new Block(); + thenBlock.addStatement(new ExpressionStatement(new InfixExpression(new Symbol("+=", 2, Symbol.Type.INFIX), new Variable("sum"), new Constant("10")))); + + IfStatement ifStmt = javaGen.getIfStatement(ifCondTerm, thenBlock); + Block elseB = new Block(); + elseB.addStatement(new ExpressionStatement(new InfixExpression(new Symbol("+=", 2, Symbol.Type.INFIX), new Variable("sum"), new Constant("5")))); + ifStmt.setElseStatement(elseB); + Block whileBody = new Block(); + whileBody.addStatement(ifStmt); + WhileStatement whileStmt = new WhileStatement(); + whileStmt.setExpression(new InfixExpression(new Symbol("<", 2, Symbol.Type.INFIX), new Variable("sum"), new Constant("100"))); + whileStmt.setBody(whileBody); + methodBody.addStatement(whileStmt); + + methodBody.addStatement(javaGen.getReturnStatement("sum")); + + methodDeclaration.setBody(methodBody); + System.out.println("--- Generated Code"); + System.out.println(methodDeclaration.toString()); + +// +// MethodDeclaration methodDeclaration = new MethodDeclaration("Test", false); +// Block methodBody = new Block(); +// +// VariableDeclarationStatement variableDeclarationStatement = new VariableDeclarationStatement(); +// variableDeclarationStatement.setModifiers(List.of(new PlainStatement("private"))); +// +// variableDeclarationStatement.setFragments(List.of( +// new VariableDeclaration(new SimpleType("int"), "x"), +// new VariableDeclaration(new SimpleType("int"), "sum") +// )); +// methodBody.addStatement(variableDeclarationStatement); +// +// ForStatement forStatement = new ForStatement(); +// +// forStatement.setInitializers(Arrays.asList(new PlainStatement("int j = 0"))); +// +// InfixExpression condition = new InfixExpression( +// new Symbol("<", 2, Symbol.Type.INFIX), +// new Variable("j"), +// new Constant("5") +// ); +// forStatement.setExpression(condition); +// +// PostfixExpression increment = new PostfixExpression( +// new Variable("j"), +// PostfixExpression.Operator.INCREMENT +// ); +// forStatement.setUpdaters(Arrays.asList(new ExpressionStatement(increment))); +// +// Block forBody = new Block(); +// InfixExpression forAddition = new InfixExpression( +// new Symbol("+=", 2, Symbol.Type.INFIX), +// new Variable("sum"), +// new Variable("j") +// ); +// forBody.addStatement(new ExpressionStatement(forAddition)); +// forStatement.setBody(forBody); +// methodBody.addStatement(forStatement); +// +// EnhancedForStatement enhancedForStatement = new EnhancedForStatement(); +// enhancedForStatement.setParameter(new SimpleType("String"), "s"); +// enhancedForStatement.setExpression(new Variable("list")); +// +// Block enhancedForBody = new Block(); +// enhancedForBody.addStatement("System.out.println(s);"); +// enhancedForStatement.setBody(enhancedForBody); +// methodBody.addStatement(enhancedForStatement); +// +// WhileStatement whileStatement = new WhileStatement(); +// InfixExpression whileCondition = new InfixExpression( +// new Symbol("<", 2, Symbol.Type.INFIX), +// new Variable("sum"), +// new Constant("100") +// ); +// whileStatement.setExpression(whileCondition); +// +// Block whileBody = new Block(); +// IfStatement ifStatement = new IfStatement(); +// +// InfixExpression moduloExpression = new InfixExpression( +// new Symbol("%", 2, Symbol.Type.INFIX), +// new Variable("sum"), +// new Constant("2") +// ); +// InfixExpression ifCondition = new InfixExpression( +// new Symbol("==", 2, Symbol.Type.INFIX), +// moduloExpression, +// new Constant("0") +// ); +// ifStatement.setExpression(ifCondition); +// +// Block thenBlock = new Block(); +// thenBlock.addStatement(new ExpressionStatement(new InfixExpression( +// new Symbol("+=", 2, Symbol.Type.INFIX), +// new Variable("sum"), +// new Constant("10") +// ))); +// +// Block elseBlock = new Block(); +// elseBlock.addStatement(new ExpressionStatement(new InfixExpression( +// new Symbol("+=", 2, Symbol.Type.INFIX), +// new Variable("sum"), +// new Constant("5") +// ))); +// +// ifStatement.setThenStatement(thenBlock); +// ifStatement.setElseStatement(elseBlock); +// whileBody.addStatement(ifStatement); +// whileStatement.setBody(whileBody); +// methodBody.addStatement(whileStatement); +// +// ReturnStatement returnStatement = new ReturnStatement(); +// returnStatement.setExpression(new Variable("sum")); +// methodBody.addStatement(returnStatement); +// +// methodDeclaration.setBody(methodBody); +// +// System.out.println("--- Generated Code ---"); +// System.out.println(methodDeclaration.toString()); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/tests/CodeGeneratorTest.java b/AlgebraicDataflowArchitectureModel/src/tests/CodeGeneratorTest.java deleted file mode 100644 index a89ea3c..0000000 --- a/AlgebraicDataflowArchitectureModel/src/tests/CodeGeneratorTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package tests; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.util.ArrayList; - -import algorithms.*; -import code.ast.CompilationUnit; -import code.ast.TypeDeclaration; -import generators.DataTransferMethodAnalyzer; -import generators.JavaCodeGenerator; -import generators.JavaMethodBodyGenerator; -import models.dataFlowModel.*; -import parser.*; -import parser.exceptions.ExpectedAssignment; -import parser.exceptions.ExpectedChannel; -import parser.exceptions.ExpectedChannelName; -import parser.exceptions.ExpectedEquals; -import parser.exceptions.ExpectedInOrOutOrRefKeyword; -import parser.exceptions.ExpectedLeftCurlyBracket; -import parser.exceptions.ExpectedRHSExpression; -import parser.exceptions.ExpectedRightBracket; -import parser.exceptions.ExpectedStateTransition; -import parser.exceptions.WrongLHSExpression; -import parser.exceptions.WrongRHSExpression; - -public class CodeGeneratorTest { - public static void main(String[] args) { - File file = new File("models/POS.model"); - try { - Parser parser = new Parser(new BufferedReader(new FileReader(file))); - DataTransferModel model; - try { - model = parser.doParse(); - DataFlowGraph graph = DataTransferModelAnalyzer.createDataFlowGraphWithStateStoringAttribute(model); - DataTransferModelAnalyzer.annotateWithSelectableDataTransferAttiribute(graph); - DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); - ArrayList codetree = JavaMethodBodyGenerator.doGenerate(graph, model, JavaCodeGenerator.doGenerate(graph, model)); - System.out.println(codetree); - } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword - | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment e) { - e.printStackTrace(); - } - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } -} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/DataConstraintModelTest.java b/AlgebraicDataflowArchitectureModel/src/tests/DataConstraintModelTest.java index afe405a..b84e563 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/DataConstraintModelTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/DataConstraintModelTest.java @@ -4,6 +4,7 @@ import org.junit.Test; +import models.algebra.Variable; import models.dataConstraintModel.*; public class DataConstraintModelTest { @@ -12,47 +13,47 @@ public void test() { // Construct a data constraint architecture model. DataConstraintModel model = new DataConstraintModel(); - ResourcePath customer_off = new ResourcePath("customers.{customer_id}.off", 1); - ResourcePath customer_add = new ResourcePath("customers.{customer_id}.add", 1); - ResourcePath company_add = new ResourcePath("companies.{company_id}.add", 1); - Channel gin_1 = new Channel("gin_1"); // set customer's office - GroupSelector x1 = new GroupSelector(); + ResourcePath customers = new ResourcePath("customers"); // "customers" + ResourcePath customer = new ResourcePath(customers, new Variable("uid")); // "customers.{uid}" + ResourcePath customer_off = new ResourcePath(customer, "off"); // "customers.{uid}.off" + ResourcePath customer_add = new ResourcePath(customer, "add"); // "customers.{uid}.add" + ResourcePath companies = new ResourcePath("companies"); // "companies" + ResourcePath company = new ResourcePath(companies, new Variable("cid")); // "companies.{cid}" + ResourcePath company_add = new ResourcePath(company, "add"); // "companies.{cid}.add" + model.addResourcePath(customer_off); + model.addResourcePath(customer_add); + model.addResourcePath(company_add); + + Channel cio_setCustomerOff = new Channel("CIO_SetCustomerOff", new Variable("uid")); // set customer's office ChannelMember customer_off_1 = new ChannelMember(customer_off); - customer_off_1.addSelector(x1); - gin_1.addChannelMember(customer_off_1); - assertEquals(customer_off.getNumberOfParameters(), customer_off_1.getSelectors().size()); + cio_setCustomerOff.addChannelMember(customer_off_1); + assertEquals(customer_off.getPathParams().get(0), cio_setCustomerOff.getSelectors().iterator().next().getExpression()); - Channel gin_2 = new Channel("gin_2"); // set companie's address - GroupSelector x2 = new GroupSelector(); + Channel cio_setCompanyAdd = new Channel("CIO_SetCompanyAdd", new Variable("cid")); // set companie's address ChannelMember company_add_1 = new ChannelMember(company_add); - company_add_1.addSelector(x2); - gin_2.addChannelMember(company_add_1); - assertEquals(company_add.getNumberOfParameters(), company_add_1.getSelectors().size()); + cio_setCompanyAdd.addChannelMember(company_add_1); + assertEquals(company_add.getPathParams().get(0), cio_setCompanyAdd.getSelectors().iterator().next().getExpression()); - Channel g = new Channel("g"); // update customer's address - GroupSelector x3 = new GroupSelector(); - ChannelSelector y = new ChannelSelector(); + Channel c = new Channel("c", new Variable("uid")); // update customer's address ChannelMember customer_off_2 = new ChannelMember(customer_off); ChannelMember company_add_2 = new ChannelMember(company_add); ChannelMember customer_add_2 = new ChannelMember(customer_add); - customer_off_2.addSelector(x3); - company_add_2.addSelector(y); - customer_add_2.addSelector(x3); - g.addChannelMember(customer_off_2); - g.addChannelMember(customer_add_2); - g.addChannelMember(company_add_2); - assertEquals(customer_off.getNumberOfParameters(), customer_off_2.getSelectors().size()); - assertEquals(customer_add.getNumberOfParameters(), customer_add_2.getSelectors().size()); - assertEquals(company_add.getNumberOfParameters(), company_add_2.getSelectors().size()); + c.addChannelMember(customer_off_2); + c.addChannelMember(company_add_2); + c.addChannelMember(customer_add_2); + assertEquals(customer_off.getPathParams().get(0), c.getSelectors().iterator().next().getExpression()); + assertEquals(customer_add.getPathParams().get(0), c.getSelectors().iterator().next().getExpression()); + assertEquals(company_add.getPathParams().get(0), new Variable("cid")); - model.addIOChannel(gin_1); - model.addIOChannel(gin_2); - model.addChannel(g); + model.addInputChannel(cio_setCustomerOff); + model.addInputChannel(cio_setCompanyAdd); + model.addChannel(c); // Check the model. assertEquals(3, model.getResourcePaths().size()); - assertEquals(2, model.getIOChannels().size()); + assertEquals(7, model.getResourceHierarchies().size()); + assertEquals(2, model.getInputChannels().size()); assertEquals(1, model.getChannels().size()); } diff --git a/AlgebraicDataflowArchitectureModel/src/tests/DataFlowModelTest.java b/AlgebraicDataflowArchitectureModel/src/tests/DataFlowModelTest.java deleted file mode 100644 index 605b006..0000000 --- a/AlgebraicDataflowArchitectureModel/src/tests/DataFlowModelTest.java +++ /dev/null @@ -1,88 +0,0 @@ -package tests; - -import static org.junit.Assert.*; - -import org.junit.Test; - -import models.*; -import models.dataConstraintModel.*; -import models.dataFlowModel.*; - -public class DataFlowModelTest { - - @Test - public void test() { - // Construct a data-flow architecture model. - DataTransferModel model = new DataTransferModel(); - ResourcePath customer_off = new ResourcePath("customers.{x1}.off", 1); // an identifier template to specify a customer's office resource - ResourcePath company_add = new ResourcePath("companies.{x2}.add", 1); // an identifier template to specify a companie's address resource - ResourcePath customer_add = new ResourcePath("customers.{x1}.add", 1); // an identifier template to specify a customer's address resource - - // === gin_1 === - // - // customers.{x1}.off(c, set(x)) == x - // customers.{x1}.off(c, e) == c - // - DataTransferChannel gin_1 = new DataTransferChannel("gin_1"); // set customer's office (an input channel) - GroupSelector x1 = new GroupSelector(); - ChannelMember customer_off_1 = new ChannelMember(customer_off); - customer_off_1.addSelector(x1); // x1 is determined by the path parameter in customer's office template, and serves as a group selector in this channel - gin_1.addChannelMember(customer_off_1); - assertEquals(customer_off.getNumberOfParameters(), customer_off_1.getSelectors().size()); - - // === gin_2 === - // - // companies.{x2}.add(a, set(y)) == y - // companies.{x2}.add(a, e) == a - // - DataTransferChannel gin_2 = new DataTransferChannel("gin_2"); // set companie's address (an input channel) - GroupSelector x2 = new GroupSelector(); - ChannelMember company_add_1 = new ChannelMember(company_add); - company_add_1.addSelector(x2); // x2 is determined by the path parameter in companie's address template, and serves as a group selector in this channel - gin_2.addChannelMember(company_add_1); - assertEquals(company_add.getNumberOfParameters(), company_add_1.getSelectors().size()); - - // === g === - // - // customers.{x3}.off( c, update(y, z)) == y - // companies.{y}.add( a1, update(y, z)) == z - // customers.{x3}.add(a2, update(y, z)) == z - // - DataTransferChannel g = new DataTransferChannel("g"); // update customer's address - GroupSelector x3 = new GroupSelector(); - ChannelSelector y = new ChannelSelector(); - ChannelMember customer_off_2 = new ChannelMember(customer_off); - ChannelMember company_add_2 = new ChannelMember(company_add); - ChannelMember customer_add_2 = new ChannelMember(customer_add); - customer_off_2.addSelector(x3); // x3 is determined by the path parameter in customer's office template, and serves as a group selector in this channel - company_add_2.addSelector(y); // y is determined by the value of the customer's office resource, and serves as a channel selector in this channel - customer_add_2.addSelector(x3); // x3 determines the path parameter in customer's address template to update - g.addChannelMemberAsInput(customer_off_2); - g.addChannelMemberAsInput(customer_add_2); - g.addChannelMemberAsOutput(company_add_2); - assertEquals(customer_off.getNumberOfParameters(), customer_off_2.getSelectors().size()); - assertEquals(customer_add.getNumberOfParameters(), customer_add_2.getSelectors().size()); - assertEquals(company_add.getNumberOfParameters(), company_add_2.getSelectors().size()); - - // Construct a data-flow architecture model. - model.addIOChannel(gin_1); - model.addIOChannel(gin_2); - model.addChannel(g); - - // Check the model. - assertEquals(3, model.getResourcePaths().size()); - assertEquals(2, model.getIOChannels().size()); - assertEquals(1, model.getChannels().size()); - - // Extract the resource dependency graph. - DataFlowGraph resourceDependencyGraph = model.getDataFlowGraph(); - - // Check the graph. - assertEquals(3, resourceDependencyGraph.getNodes().size()); - assertEquals(2, resourceDependencyGraph.getEdges().size()); - for (Edge e: resourceDependencyGraph.getEdges()) { - System.out.println(e.getSource() + "-(" + e + ")->" + e.getDestination()); - } - } - -} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/DataStorageDecisionTest.java b/AlgebraicDataflowArchitectureModel/src/tests/DataStorageDecisionTest.java index 9d28936..9ba67ab 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/DataStorageDecisionTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/DataStorageDecisionTest.java @@ -1,9 +1,14 @@ package tests; +import static org.junit.Assert.*; + import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; +import java.util.HashMap; + +import org.junit.Test; import algorithms.*; import generators.DataTransferMethodAnalyzer; @@ -13,18 +18,30 @@ import parser.exceptions.ExpectedAssignment; import parser.exceptions.ExpectedChannel; import parser.exceptions.ExpectedChannelName; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; import parser.exceptions.ExpectedEquals; -import parser.exceptions.ExpectedInOrOutOrRefKeyword; +import parser.exceptions.ExpectedInOrOutOrRefOrSubKeyword; import parser.exceptions.ExpectedLeftCurlyBracket; import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; +import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; public class DataStorageDecisionTest { - public static void main(String[] args) { + + @Test + public void test() { File file = new File("models/POS2.model"); + HashMap exprectedDecision = new HashMap<>(); + exprectedDecision.put("history", true); + exprectedDecision.put("total", true); + exprectedDecision.put("points", false); + exprectedDecision.put("payment", true); try { Parser parser = new Parser(new BufferedReader(new FileReader(file))); DataTransferModel model = null; @@ -34,12 +51,16 @@ DataFlowGraph graph = DataTransferModelAnalyzer.createDataFlowGraphWithStateStoringAttribute(model); DataTransferModelAnalyzer.annotateWithSelectableDataTransferAttiribute(graph); DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); - for(Node n:graph.getNodes()) { - System.out.println(((ResourceNode) n).getResource().getResourceName() + ":" + ((StoreAttribute) ((ResourceNode) n).getAttribute()).isStored()); + for(Node resNode: graph.getResourceNodes()) { + String resName = ((ResourceNode) resNode).getResourceName(); + boolean decision = ((StoreAttribute) ((ResourceNode) resNode).getAttribute()).isStored(); + System.out.println(resName + ":" + decision); + assertNotNull(exprectedDecision.get(resName)); + assertEquals(decision, exprectedDecision.get(resName)); } - } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword + } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { e.printStackTrace(); } } catch (FileNotFoundException e) { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/DataStorageNecessityTest.java b/AlgebraicDataflowArchitectureModel/src/tests/DataStorageNecessityTest.java index 9a7c300..5d2c4d8 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/DataStorageNecessityTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/DataStorageNecessityTest.java @@ -1,9 +1,15 @@ package tests; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; +import java.util.HashMap; + +import org.junit.Test; import algorithms.DataTransferModelAnalyzer; import models.Node; @@ -12,18 +18,30 @@ import parser.exceptions.ExpectedAssignment; import parser.exceptions.ExpectedChannel; import parser.exceptions.ExpectedChannelName; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; import parser.exceptions.ExpectedEquals; -import parser.exceptions.ExpectedInOrOutOrRefKeyword; +import parser.exceptions.ExpectedInOrOutOrRefOrSubKeyword; import parser.exceptions.ExpectedLeftCurlyBracket; import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; +import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; public class DataStorageNecessityTest { - public static void main(String[] args) { + + @Test + public void test() { File file = new File("models/POS2.model"); + HashMap exprectedNecessity = new HashMap<>(); + exprectedNecessity.put("history", true); + exprectedNecessity.put("total", true); + exprectedNecessity.put("points", false); + exprectedNecessity.put("payment", false); try { Parser parser = new Parser(new BufferedReader(new FileReader(file))); DataTransferModel model; @@ -31,15 +49,21 @@ model = parser.doParse(); System.out.println(model); DataFlowGraph graph = DataTransferModelAnalyzer.createDataFlowGraphWithStateStoringAttribute(model); - for (Node n:graph.getNodes()) { - ResourceNode resource = (ResourceNode)n; - if((StoreAttribute)resource.getAttribute() != null) { - System.out.println(resource.toString() + ":" + ((StoreAttribute)resource.getAttribute()).isNeeded()); + for (Node n: graph.getNodes()) { + if (n instanceof ResourceNode) { + ResourceNode resource = (ResourceNode) n; + if((StoreAttribute) resource.getAttribute() != null) { + String resName = resource.getResourceName(); + boolean necessity = ((StoreAttribute) resource.getAttribute()).isNeeded(); + System.out.println(resName + ":" + necessity); + assertNotNull(exprectedNecessity.get(resName)); + assertEquals(necessity, exprectedNecessity.get(resName)); + } } } - } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword + } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { e.printStackTrace(); } } catch (FileNotFoundException e) { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/DataTransferModelTest.java b/AlgebraicDataflowArchitectureModel/src/tests/DataTransferModelTest.java new file mode 100644 index 0000000..0f4575b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/tests/DataTransferModelTest.java @@ -0,0 +1,88 @@ +package tests; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import models.*; +import models.algebra.Variable; +import models.dataConstraintModel.*; +import models.dataFlowModel.*; + +public class DataTransferModelTest { + + @Test + public void test() { + // Construct a data-flow architecture model. + DataTransferModel model = new DataTransferModel(); + + ResourcePath customers = new ResourcePath("customers"); // "customers" + ResourcePath customer = new ResourcePath(customers, new Variable("uid")); // "customers.{uid}" + ResourcePath customer_off = new ResourcePath(customer, "off"); // "customers.{uid}.off" + ResourcePath customer_add = new ResourcePath(customer, "add"); // "customers.{uid}.add" + ResourcePath companies = new ResourcePath("companies"); // "companies" + ResourcePath company = new ResourcePath(companies, new Variable("cid")); // "companies.{cid}" + ResourcePath company_add = new ResourcePath(company, "add"); // "companies.{cid}.add" + model.addResourcePath(customer_off); + model.addResourcePath(customer_add); + model.addResourcePath(company_add); + + // === cio_setCustomerOff(uid) === + // + // out customers.{uid}.off(c, set(x)) = x + // + DataTransferChannel cio_setCustomerOff = new DataTransferChannel("CIO_SetCustomerOff", new Variable("uid")); // set customer's office (an input channel) + ChannelMember customer_off_1 = new ChannelMember(customer_off); + cio_setCustomerOff.addChannelMemberAsOutput(customer_off_1); + assertEquals(customer_off.getPathParams().get(0), cio_setCustomerOff.getSelectors().iterator().next().getExpression()); + + // === cio_setCompanyAdd(cid) === + // + // out companies.{cid}.add(a, set(y)) = y + // + DataTransferChannel cio_setCompanyAdd = new DataTransferChannel("CIO_SetCompanyAdd", new Variable("cid")); // set companie's address (an input channel) + ChannelMember company_add_1 = new ChannelMember(company_add); + cio_setCompanyAdd.addChannelMemberAsOutput(company_add_1); + assertEquals(company_add.getPathParams().get(0), cio_setCompanyAdd.getSelectors().iterator().next().getExpression()); + + // === c === + // + // in customers.{uid}.off( c, update(cid, a2)) = cid + // in companies.{cid}.add( a, update(cid, a2)) = a2 + // out customers.{uid}.add(b, update(cid, a2)) = a2 + // + DataTransferChannel c = new DataTransferChannel("c", new Variable("uid")); // update customer's address + ChannelMember customer_off_2 = new ChannelMember(customer_off); + ChannelMember company_add_2 = new ChannelMember(company_add); + ChannelMember customer_add_2 = new ChannelMember(customer_add); + c.addChannelMemberAsInput(customer_off_2); + c.addChannelMemberAsInput(company_add_2); + c.addChannelMemberAsOutput(customer_add_2); + assertEquals(customer_off.getPathParams().get(0), c.getSelectors().iterator().next().getExpression()); + assertEquals(customer_add.getPathParams().get(0), c.getSelectors().iterator().next().getExpression()); + assertEquals(company_add.getPathParams().get(0), new Variable("cid")); + + // Construct a data-flow architecture model. + model.addInputChannel(cio_setCustomerOff); + model.addInputChannel(cio_setCompanyAdd); + model.addChannel(c); + + // Check the model. + assertEquals(3, model.getResourcePaths().size()); + assertEquals(7, model.getResourceHierarchies().size()); + assertEquals(2, model.getInputChannels().size()); + assertEquals(1, model.getChannels().size()); + + // Extract the resource dependency graph. + DataFlowGraph resourceDependencyGraph = model.getDataFlowGraph(); + + // Check the graph. + assertEquals(7, resourceDependencyGraph.getResourceNodes().size()); + assertEquals(3, resourceDependencyGraph.getChannelNodes().size()); + assertEquals(5, resourceDependencyGraph.getEdges().size()); + for (Edge e: resourceDependencyGraph.getEdges()) { + System.out.println(e.getSource() + "-(" + e + ")->" + e.getDestination()); + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/EdgeTransitionSelectableTest.java b/AlgebraicDataflowArchitectureModel/src/tests/EdgeTransitionSelectableTest.java index 847fb6f..b88f7c3 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/EdgeTransitionSelectableTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/EdgeTransitionSelectableTest.java @@ -12,13 +12,18 @@ import parser.exceptions.ExpectedAssignment; import parser.exceptions.ExpectedChannel; import parser.exceptions.ExpectedChannelName; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; import parser.exceptions.ExpectedEquals; -import parser.exceptions.ExpectedInOrOutOrRefKeyword; +import parser.exceptions.ExpectedInOrOutOrRefOrSubKeyword; import parser.exceptions.ExpectedLeftCurlyBracket; import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; +import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; public class EdgeTransitionSelectableTest { @@ -36,9 +41,9 @@ DataFlowEdge re = (DataFlowEdge) e; System.out.println(re.getSource() + "-" + re.getDestination() + ":" + ((PushPullAttribute)(re.getAttribute())).getOptions()); } - } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword + } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { e.printStackTrace(); } } catch (FileNotFoundException e) { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/FormulaChannelTest.java b/AlgebraicDataflowArchitectureModel/src/tests/FormulaChannelTest.java index a8f3503..6bf26f4 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/FormulaChannelTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/FormulaChannelTest.java @@ -5,6 +5,7 @@ import models.algebra.Symbol; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.visualModel.FormulaChannel; @@ -12,23 +13,23 @@ @Test public void test() { - ResourcePath id1 = new ResourcePath("r1", 0); - ResourcePath id2 = new ResourcePath("r2", 0); - ResourcePath id3 = new ResourcePath("r3", 0); + ResourcePath res1 = new ResourcePath("r1"); + ResourcePath res2 = new ResourcePath("r2"); + ResourcePath res3 = new ResourcePath("r3"); FormulaChannel ch1 = new FormulaChannel("ch1", DataConstraintModel.add); System.out.println(ch1.getFormula()); System.out.println(ch1.getFormulaTerm()); System.out.println(ch1.getSourceText()); - ch1.addChannelMemberAsInput(new ChannelMember(id1)); + ch1.addChannelMemberAsInput(new ChannelMember(res1)); System.out.println(ch1.getFormula()); System.out.println(ch1.getFormulaTerm()); System.out.println(ch1.getSourceText()); - ch1.addChannelMemberAsInput(new ChannelMember(id2)); + ch1.addChannelMemberAsInput(new ChannelMember(res2)); System.out.println(ch1.getFormula()); System.out.println(ch1.getFormulaTerm()); System.out.println(ch1.getSourceText()); - ch1.addChannelMemberAsOutput(new ChannelMember(id3)); + ch1.addChannelMemberAsOutput(new ChannelMember(res3)); System.out.println(ch1.getFormula()); System.out.println(ch1.getFormulaTerm()); System.out.println(ch1.getSourceText()); @@ -37,15 +38,15 @@ System.out.println(ch2.getFormula()); System.out.println(ch2.getFormulaTerm()); System.out.println(ch2.getSourceText()); - ch2.addChannelMemberAsOutput(new ChannelMember(id3)); + ch2.addChannelMemberAsOutput(new ChannelMember(res3)); System.out.println(ch2.getFormula()); System.out.println(ch2.getFormulaTerm()); System.out.println(ch2.getSourceText()); - ch2.addChannelMemberAsInput(new ChannelMember(id1)); + ch2.addChannelMemberAsInput(new ChannelMember(res1)); System.out.println(ch2.getFormula()); System.out.println(ch2.getFormulaTerm()); System.out.println(ch2.getSourceText()); - ch2.addChannelMemberAsInput(new ChannelMember(id2)); + ch2.addChannelMemberAsInput(new ChannelMember(res2)); System.out.println(ch2.getFormula()); System.out.println(ch2.getFormulaTerm()); System.out.println(ch2.getSourceText()); diff --git a/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java b/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java index bfa8957..44c9b6c 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java @@ -14,18 +14,24 @@ import models.algebra.Expression; import models.algebra.Position; +import models.algebra.Term; import models.algebra.Variable; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonType; import models.dataFlowModel.DataTransferModel; import parser.Parser; import parser.Parser.TokenStream; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.WrongJsonExpression; public class InverseTest { @Test public void test() { - String lhs = "y"; DataTransferModel model = new DataTransferModel(); try { + String lhs = "y"; String rhs = "(a * x + b) * c"; TokenStream stream = new Parser.TokenStream(); @@ -33,7 +39,7 @@ stream.addLine(rhs); Expression rhsExp = parser.parseTerm(stream, model); - System.out.println(lhs + " = " + rhsExp); + System.out.println("=== solve{" + lhs + " = " + rhsExp + "} for a, b, d, x ==="); HashMap rhsVars = rhsExp.getVariables(); assertEquals(4, rhsVars.size()); @@ -47,7 +53,66 @@ assertFalse(inv.contains(v)); System.out.println(rhsVars.get(vPos) + " = " + inv); } - } catch (ExpectedRightBracket e) { + + // Extract an element in a tuple + TokenStream stream2 = new Parser.TokenStream(); + Parser parser2 = new Parser(stream2); + stream2.addLine("fst(tuple(x, y))"); + Expression tupleExp = parser2.parseTerm(stream2, model); + stream2.addLine("snd(tuple(x, y))"); + Expression tupleExp2 = parser2.parseTerm(stream2, model); + Expression reduced = ((Term) tupleExp).reduce(); + Expression reduced2 = ((Term) tupleExp2).reduce(); + Variable x = new Variable("x"); + assertEquals(reduced, x); + assertEquals(reduced2, y); + System.out.println("=== simplify ==="); + System.out.println(tupleExp + " = " + reduced); + System.out.println(tupleExp2 + " = " + reduced2); + + // Solve {z = fst(x)} for x + TokenStream stream3 = new Parser.TokenStream(); + Parser parser3 = new Parser(stream3); + stream3.addLine("fst(x)"); + Expression rhsExp3 = parser3.parseTerm(stream3, model); + Variable z = new Variable("z"); + System.out.println("=== solve{" + z + " = " + rhsExp3 + "} for x ==="); + HashMap rhsVars3 = rhsExp3.getVariables(); + for (Position vPos: rhsVars3.keySet()) { + Variable v = rhsVars3.get(vPos); + Expression inv = rhsExp3.getInverseMap(z, vPos); // inverse map to get v back from the output value z + if (inv instanceof Term) { + inv = ((Term) inv).reduce(); + } + assertTrue(inv.contains(z)); + assertFalse(inv.contains(v)); + System.out.println(rhsVars3.get(vPos) + " = " + inv); + } + + // Solve {z = x.id} for x + TokenStream stream4 = new Parser.TokenStream(); + Parser parser4 = new Parser(stream4); + stream4.addLine("x.id"); + Expression rhsExp4 = parser4.parseTerm(stream4, model); + System.out.println("=== solve{" + z + " = " + rhsExp4 + "} for x ==="); + HashMap rhsVars4 = rhsExp4.getVariables(); + for (Position vPos: rhsVars4.keySet()) { + Variable v = rhsVars4.get(vPos); + if (x.getName().equals("x")) { + JsonType jsonType = new JsonType("Json", new code.ast.ParameterizedType(new code.ast.SimpleType("HashMap")), DataConstraintModel.typeJson); + jsonType.addMemberType("id", DataConstraintModel.typeInt); + jsonType.addMemberType("name", DataConstraintModel.typeString); + v.setType(jsonType); + } + Expression inv = rhsExp4.getInverseMap(z, vPos); // inverse map to get v back from the output value z + if (inv instanceof Term) { + inv = ((Term) inv).reduce(); + } + System.out.println(rhsVars4.get(vPos) + " = " + inv); + assertTrue(inv.contains(z)); + assertFalse(inv.contains(v)); + } + } catch (ExpectedRightBracket | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { e.printStackTrace(); } } diff --git a/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java b/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java new file mode 100644 index 0000000..556e065 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java @@ -0,0 +1,1577 @@ +package tests; + +import static org.junit.Assert.*; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.junit.Test; + +import algorithms.*; +import code.ast.Annotation; +import code.ast.CompilationUnit; +import code.ast.FieldDeclaration; +import code.ast.MethodDeclaration; +import code.ast.TypeDeclaration; +import code.ast.VariableDeclaration; +import generators.CodeGenerator; +import generators.CodeGeneratorFromDataFlowGraph; +import generators.DataTransferMethodAnalyzer; +import generators.JavaSpecific; +import generators.JerseySpecific; +import generators.TypeInference; +import models.Edge; +import models.dataFlowModel.*; +import parser.*; +import parser.exceptions.ExpectedAssignment; +import parser.exceptions.ExpectedChannel; +import parser.exceptions.ExpectedChannelName; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; +import parser.exceptions.ExpectedEquals; +import parser.exceptions.ExpectedInOrOutOrRefOrSubKeyword; +import parser.exceptions.ExpectedLeftCurlyBracket; +import parser.exceptions.ExpectedRHSExpression; +import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.ExpectedRightCurlyBracket; +import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; +import parser.exceptions.WrongLHSExpression; +import parser.exceptions.WrongPathExpression; +import parser.exceptions.WrongRHSExpression; + +public class JAXRSCodeGeneratorTest { + + @Test + public void test() { + testAccounts(); + testClock(); + testCustomerManagement(); + testGroupChat(); + testInventoryManagement(); + testOnlineBattleGame(); + testOnlineBattleGame2(); + testPOS(); + testSimpleTwitter(); + testVotingSystem(); + testWeatherObservationSystem(); + } + + private void testAccounts() { + try { + ArrayList generatedCode = generateCode("models/Accounts.model", null); + Map, // class annotations + Entry, // field name to type + Map, // class annotations + Entry, // arg types + Integer>>>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "List")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("List", + Map.entry(List.of(), + 1)))), + Map.entry("getAccount", Map.entry(Set.of(), + Map.entry("Account", + Map.entry(List.of("int"), + 1)))), + Map.entry("getNameValue", Map.entry(Set.of("@Path(\"/{uid}/name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("int"), + 1)))), + Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{uid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("int"), + 1)))), + Map.entry("changeName", Map.entry(Set.of("@Path(\"/{uid}/name\")","@PUT"), + Map.entry("void", + Map.entry(List.of("int","String"), + 1)))), + Map.entry("signup", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String"), + 1)))))))); + exprectedStructure.put("Account", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("name", "String")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getName", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 1)))), + Map.entry("changeName", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("int","String"), + 1)))), + Map.entry("Account", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String"), + 1)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testClock() { + try { + // check PULL-first + ArrayList generatedCode = generateCode("models/Clock.model", PushPullValue.PULL); + Map, // class annotations + Entry, // field name to type + Map, // class annotations + Entry, // arg types + Integer>>>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Hour", Map.entry(Set.of("@Path(\"/hour\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "int")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("int", + Map.entry(List.of(), + 1)))), + Map.entry("updateFromMin", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("int"), + 1)))))))); + exprectedStructure.put("Min", Map.entry(Set.of("@Path(\"/min\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "int"), + Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("int", + Map.entry(List.of(), + 1)))), + Map.entry("tick", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of(), + 3)))))))); + exprectedStructure.put("Min_ang", Map.entry(Set.of("@Path(\"/min_ang\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("double", + Map.entry(List.of(), + 2)))))))); + exprectedStructure.put("Hour_ang", Map.entry(Set.of("@Path(\"/hour_ang\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("double", + Map.entry(List.of(), + 2)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + + // check PUSH-first + generatedCode = generateCode("models/Clock.model", PushPullValue.PUSH); + exprectedStructure.clear(); + exprectedStructure.put("Hour_ang", Map.entry(Set.of("@Path(\"/hour_ang\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "double")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("double", + Map.entry(List.of(), + 1)))), + Map.entry("updateFromHour", Map.entry(Set.of("@PUT"), + Map.entry("void", + Map.entry(List.of("int"), + 1)))))))); + exprectedStructure.put("Hour", Map.entry(Set.of("@Path(\"/hour\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "int"), + Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("int", + Map.entry(List.of(), + 1)))), + Map.entry("updateFromMin", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("int"), + 3)))))))); + exprectedStructure.put("Min", Map.entry(Set.of("@Path(\"/min\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "int"), + Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("int", + Map.entry(List.of(), + 1)))), + Map.entry("tick", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of(), + 5)))))))); + exprectedStructure.put("Min_ang", Map.entry(Set.of("@Path(\"/min_ang\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "double")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("double", + Map.entry(List.of(), + 1)))), + Map.entry("updateFromMin", Map.entry(Set.of("@PUT"), + Map.entry("void", + Map.entry(List.of("int"), + 1)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testCustomerManagement() { + try { + ArrayList generatedCode = generateCode("models/CustomerManagement.model", null); + Map, // class annotations + Entry, // field name to type + Map, // class annotations + Entry, // arg types + Integer>>>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Companies", Map.entry(Set.of("@Path(\"/companies\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getCompany", Map.entry(Set.of(), + Map.entry("Company", + Map.entry(List.of("String"), + 1)))), + Map.entry("getAddressValue", Map.entry(Set.of("@Path(\"/{cid}/address\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String"), + 1)))), + Map.entry("getCompanyValue", Map.entry(Set.of("@Path(\"/{cid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("setAddress", Map.entry(Set.of("@Path(\"/{cid}/address\")","@PUT"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("addCampany", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))))); + exprectedStructure.put("Customers", Map.entry(Set.of("@Path(\"/customers\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getCustomer", Map.entry(Set.of(), + Map.entry("Customer", + Map.entry(List.of("String"), + 1)))), + Map.entry("getAddressValue", Map.entry(Set.of("@Path(\"/{uid}/address\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String"), + 1)))), + Map.entry("getCustomerValue", Map.entry(Set.of("@Path(\"/{uid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("getOrganizationValue", Map.entry(Set.of("@Path(\"/{uid}/organization\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String"), + 1)))), + Map.entry("addCustomer", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("setOrganization", Map.entry(Set.of("@Path(\"/{uid}/organization\")","@PUT"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))))); + exprectedStructure.put("Customer", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("organization", "String"), + Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getOrganization", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 1)))), + Map.entry("getAddress", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 2)))), + Map.entry("setOrganization", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("Customer", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String"), + 1)))))))); + exprectedStructure.put("Company", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("address", "String")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getAddress", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 1)))), + Map.entry("setAddress", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("Company", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String"), + 1)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testGroupChat() { + try { + ArrayList generatedCode = generateCode("models/GroupChat.model", null); + Map, // class annotations + Entry, // field name to type + Map, // class annotations + Entry, // arg types + Integer>>>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getAccount", Map.entry(Set.of(), + Map.entry("Account", + Map.entry(List.of("String"), + 1)))), + Map.entry("signUp", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String"), + 1)))), + Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{v1}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("updateNotificationsFromMessages", Map.entry(Set.of("@Path(\"/{v1}/notifications\")","@POST"), + Map.entry("void", + Map.entry(List.of("String","String","int","List","String"), + 1)))), + Map.entry("getNotificationsValue", Map.entry(Set.of("@Path(\"/{v1}/notifications\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("hasRead", Map.entry(Set.of("@Path(\"/{aid}/notifications\")","@DELETE"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))))); + exprectedStructure.put("Account", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("notifications", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("updateNotificationsFromMessages", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String","int","List","String"), + 1)))), + Map.entry("getNotifications", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("hasRead", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("Account", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("Map"), + 1)))))))); + exprectedStructure.put("Group", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("members", "List"), + Map.entry("client", "Client"), + Map.entry("messages", "List")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getMember", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of("int"), + 1)))), + Map.entry("getMembers", Map.entry(Set.of(), + Map.entry("List", + Map.entry(List.of(), + 1)))), + Map.entry("addGroupMember", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("getMessages", Map.entry(Set.of(), + Map.entry("List", + Map.entry(List.of(), + 1)))), + Map.entry("postMessage", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 2)))), + Map.entry("Group", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("List","List"), + 2)))))))); + exprectedStructure.put("Groups", Map.entry(Set.of("@Path(\"/groups\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getGroup", Map.entry(Set.of(), + Map.entry("Group", + Map.entry(List.of("String"), + 1)))), + Map.entry("getMemberValue", Map.entry(Set.of("@Path(\"/{gid}/members/{mno}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String","int"), + 1)))), + Map.entry("getMembersValue", Map.entry(Set.of("@Path(\"/{gid}/members\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("List", + Map.entry(List.of("String"), + 1)))), + Map.entry("addGroupMember", Map.entry(Set.of("@Path(\"/{gid}/members\")","@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("getGroupValue", Map.entry(Set.of("@Path(\"/{gid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("createGroup", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String"), + 1)))), + Map.entry("getMessagesValue", Map.entry(Set.of("@Path(\"/{gid}/messages\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("List", + Map.entry(List.of("String"), + 1)))), + Map.entry("postMessage", Map.entry(Set.of("@Path(\"/{gid}/messages\")","@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testInventoryManagement() { + try { + ArrayList generatedCode = generateCode("models/InventoryManagement.model", null); + Map, // class annotations + Entry, // field name to type + Map, // class annotations + Entry, // arg types + Integer>>>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("InventoryElement", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("count", "int")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getCount", Map.entry(Set.of(), + Map.entry("int", + Map.entry(List.of(), + 1)))), + Map.entry("receiveOrShip", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","int"), + 1)))), + Map.entry("InventoryElement", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("int"), + 1)))))))); + exprectedStructure.put("Inventory", Map.entry(Set.of("@Path(\"/inventory\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getInventoryElement", Map.entry(Set.of(), + Map.entry("InventoryElement", + Map.entry(List.of("String"), + 1)))), + Map.entry("getInventoryElementValue", Map.entry(Set.of("@Path(\"/{itemId}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("getCountValue", Map.entry(Set.of("@Path(\"/{itemId}/count\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("int", + Map.entry(List.of("String"), + 1)))), + Map.entry("registerItem", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String","int","String"), + 1)))), + Map.entry("receiveOrShip", Map.entry(Set.of("@Path(\"/{itemId}/count\")","@POST"), + Map.entry("void", + Map.entry(List.of("String","int"), + 1)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testOnlineBattleGame() { + try { + // check PULL-first + ArrayList generatedCode = generateCode("models/OnlineBattleGame.model", null); + Map, // class annotations + Entry, // field name to type + Map, // class annotations + Entry, // arg types + Integer>>>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Rooms", Map.entry(Set.of("@Path(\"/rooms\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getRoom", Map.entry(Set.of(), + Map.entry("Room", + Map.entry(List.of("String"), + 1)))), + Map.entry("getBlue_idValue", Map.entry(Set.of("@Path(\"/{rid}/blue_id\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String"), + 1)))), + Map.entry("getRed_nameValue", Map.entry(Set.of("@Path(\"/{rid}/red_name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String"), + 1)))), + Map.entry("getBlue_nameValue", Map.entry(Set.of("@Path(\"/{rid}/blue_name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String"), + 1)))), + Map.entry("getRed_idValue", Map.entry(Set.of("@Path(\"/{rid}/red_id\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String"), + 1)))), + Map.entry("getRoomValue", Map.entry(Set.of("@Path(\"/{rid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("changeBlueId", Map.entry(Set.of("@Path(\"/{rid}/blue_id\")","@PUT"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("createRoom", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String","String","String"), + 1)))), + Map.entry("changeRedId", Map.entry(Set.of("@Path(\"/{rid}/red_id\")","@PUT"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))))); + exprectedStructure.put("Room", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("blue_id", "String"), + Map.entry("red_id", "String"), + Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getBlue_id", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 1)))), + Map.entry("getRed_id", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 1)))), + Map.entry("getRed_name", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 2)))), + Map.entry("getBlue_name", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 2)))), + Map.entry("changeRedId", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("changeBlueId", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("Room", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 2)))))))); + exprectedStructure.put("Account", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("name", "String")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getName", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 1)))), + Map.entry("changeName", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("Account", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String"), + 1)))))))); + exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getAccount", Map.entry(Set.of(), + Map.entry("Account", + Map.entry(List.of("String"), + 1)))), + Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{aid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("getNameValue", Map.entry(Set.of("@Path(\"/{aid}/name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String"), + 1)))), + Map.entry("signUp", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("changeName", Map.entry(Set.of("@Path(\"/{aid}/name\")","@PUT"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + + private void testOnlineBattleGame2() { + try { + // check PULL-first + ArrayList generatedCode = generateCode("models/OnlineBattleGame2.model", null); + Map, // class annotations + Entry, // field name to type + Map, // class annotations + Entry, // arg types + Integer>>>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Room", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("members", "Members"), + Map.entry("client", "Client"), + Map.entry("battle", "boolean")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getMembers", Map.entry(Set.of(), + Map.entry("Members", + Map.entry(List.of(), + 1)))), + Map.entry("getBattle", Map.entry(Set.of(), + Map.entry("boolean", + Map.entry(List.of(), + 1)))), + Map.entry("battle", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","boolean"), + 2)))), + Map.entry("Room", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("boolean"), + 1)))))))); + exprectedStructure.put("Account", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("name", "String"), + Map.entry("point", "int")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getName", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 1)))), + Map.entry("changeName", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("updatePointFromBattle", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String","int","boolean","String"), + 1)))), + Map.entry("getPoint", Map.entry(Set.of(), + Map.entry("int", + Map.entry(List.of(), + 1)))), + Map.entry("Account", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","int"), + 2)))))))); + exprectedStructure.put("Member", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("id", "String"), + Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getId", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 1)))), + Map.entry("getName", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 2)))), + Map.entry("Member", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String"), + 1)))))))); + exprectedStructure.put("Members", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("value", "List")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("List", + Map.entry(List.of(), + 1)))), + Map.entry("getMember", Map.entry(Set.of(), + Map.entry("Member", + Map.entry(List.of("int"), + 1)))), + Map.entry("addRoomMember", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))))); + exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getAccount", Map.entry(Set.of(), + Map.entry("Account", + Map.entry(List.of("String"), + 1)))), + Map.entry("getNameValue", Map.entry(Set.of("@Path(\"/{mid}/name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String"), + 1)))), + Map.entry("changeName", Map.entry(Set.of("@Path(\"/{aid}/name\")","@PUT"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{mid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("updatePointFromBattle", Map.entry(Set.of("@Path(\"/{mid}/point\")","@POST"), + Map.entry("void", + Map.entry(List.of("String","String","int","boolean","String"), + 1)))), + Map.entry("getPointValue", Map.entry(Set.of("@Path(\"/{mid}/point\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("int", + Map.entry(List.of("String"), + 1)))), + Map.entry("signUp", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))))); + exprectedStructure.put("Rooms", Map.entry(Set.of("@Path(\"/rooms\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getRoom", Map.entry(Set.of(), + Map.entry("Room", + Map.entry(List.of("String"), + 1)))), + Map.entry("getRoomValue", Map.entry(Set.of("@Path(\"/{rid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("getBattleValue", Map.entry(Set.of("@Path(\"/{rid}/battle\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("boolean", + Map.entry(List.of("String"), + 1)))), + Map.entry("battle", Map.entry(Set.of("@Path(\"/{rid}/battle\")","@PUT"), + Map.entry("void", + Map.entry(List.of("String","boolean"), + 1)))), + Map.entry("getIdValue", Map.entry(Set.of("@Path(\"/{rid}/members/{mno}/id\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String","int"), + 1)))), + Map.entry("getNameValue", Map.entry(Set.of("@Path(\"/{rid}/members/{mno}/name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String","int"), + 1)))), + Map.entry("getMemberValue", Map.entry(Set.of("@Path(\"/{rid}/members/{mno}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String","int"), + 1)))), + Map.entry("getMembersValue", Map.entry(Set.of("@Path(\"/{rid}/members\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("List", + Map.entry(List.of("String"), + 1)))), + Map.entry("addRoomMember", Map.entry(Set.of("@Path(\"/{rid}/members\")","@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("createRoom", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String"), + 1)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testPOS() { + try { + // check PULL-first + ArrayList generatedCode = generateCode("models/POS.model", PushPullValue.PULL); + Map, // class annotations + Entry, // field name to type + Map, // class annotations + Entry, // arg types + Integer>>>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Points", Map.entry(Set.of("@Path(\"/points\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("int", + Map.entry(List.of(), + 2)))))))); + exprectedStructure.put("Total", Map.entry(Set.of("@Path(\"/total\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("int", + Map.entry(List.of(), + 2)))))))); + exprectedStructure.put("Payment", Map.entry(Set.of("@Path(\"/payment\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "int"), + Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("int", + Map.entry(List.of(), + 1)))), + Map.entry("purchase", Map.entry(Set.of("@PUT"), + Map.entry("void", + Map.entry(List.of("int"), + 3)))))))); + exprectedStructure.put("History", Map.entry(Set.of("@Path(\"/history\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "List")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("List", + Map.entry(List.of(), + 1)))), + Map.entry("updateFromPayment", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("int"), + 1)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + + // check PUSH-first + generatedCode = generateCode("models/POS.model", PushPullValue.PUSH); + exprectedStructure.clear(); + exprectedStructure.put("Payment", Map.entry(Set.of("@Path(\"/payment\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "int"), + Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("int", + Map.entry(List.of(), + 1)))), + Map.entry("purchase", Map.entry(Set.of("@PUT"), + Map.entry("void", + Map.entry(List.of("int"), + 5)))))))); + exprectedStructure.put("Total", Map.entry(Set.of("@Path(\"/total\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "int")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("int", + Map.entry(List.of(), + 1)))), + Map.entry("updateFromHistory", Map.entry(Set.of("@PUT"), + Map.entry("void", + Map.entry(List.of("List"), + 1)))))))); + exprectedStructure.put("History", Map.entry(Set.of("@Path(\"/history\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "List"), + Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("List", + Map.entry(List.of(), + 1)))), + Map.entry("updateFromPayment", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("int"), + 3)))))))); + exprectedStructure.put("Points", Map.entry(Set.of("@Path(\"/points\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "int")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("int", + Map.entry(List.of(), + 1)))), + Map.entry("updateFromPayment", Map.entry(Set.of("@PUT"), + Map.entry("void", + Map.entry(List.of("int"), + 1)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testSimpleTwitter() { + try { + ArrayList generatedCode = generateCode("models/SimpleTwitter.model", null); + Map, // class annotations + Entry, // field name to type + Map, // class annotations + Entry, // arg types + Integer>>>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getAccount", Map.entry(Set.of(), + Map.entry("Account", + Map.entry(List.of("String"), + 1)))), + Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{accountId}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("getTweetsValue", Map.entry(Set.of("@Path(\"/{accountId}/tweets\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("List", + Map.entry(List.of("String"), + 1)))), + Map.entry("tweet", Map.entry(Set.of("@Path(\"/{accountId}/tweets\")","@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("signUp", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))))); + exprectedStructure.put("Account", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("tweets", "List")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getTweets", Map.entry(Set.of(), + Map.entry("List", + Map.entry(List.of(), + 1)))), + Map.entry("tweet", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("Account", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("List"), + 1)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testVotingSystem() { + try { + ArrayList generatedCode = generateCode("models/VotingSystem.model", null); + Map, // class annotations + Entry, // field name to type + Map, // class annotations + Entry, // arg types + Integer>>>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Counts", Map.entry(Set.of("@Path(\"/counts\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map"), + Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 5)))))))); + exprectedStructure.put("Account", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("vote", "String")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getVote", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 1)))), + Map.entry("cast", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("Account", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String"), + 1)))))))); + exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getAccount", Map.entry(Set.of(), + Map.entry("Account", + Map.entry(List.of("String"), + 1)))), + Map.entry("getVoteValue", Map.entry(Set.of("@Path(\"/{aid}/vote\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String"), + 1)))), + Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{aid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("cast", Map.entry(Set.of("@Path(\"/{aid}/vote\")","@PUT"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("signUp", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testWeatherObservationSystem() { + try { + // check PULL-first + ArrayList generatedCode = generateCode("models/WeatherObservationSystem.model", PushPullValue.PULL); + Map, // class annotations + Entry, // field name to type + Map, // class annotations + Entry, // arg types + Integer>>>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Temp_c", Map.entry(Set.of("@Path(\"/temp_c\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("double", + Map.entry(List.of(), + 2)))))))); + exprectedStructure.put("Highest", Map.entry(Set.of("@Path(\"/highest\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "double")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("double", + Map.entry(List.of(), + 1)))), + Map.entry("updateFromTemp_f", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("double"), + 1)))), + Map.entry("reset", Map.entry(Set.of("@PUT"), + Map.entry("void", + Map.entry(List.of("double"), + 1)))))))); + exprectedStructure.put("Temp_f", Map.entry(Set.of("@Path(\"/temp_f\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "double"), + Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("double", + Map.entry(List.of(), + 1)))), + Map.entry("observe", Map.entry(Set.of("@PUT"), + Map.entry("void", + Map.entry(List.of("double"), + 3)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + + // check PUSH-first + generatedCode = generateCode("models/WeatherObservationSystem.model", PushPullValue.PUSH); + exprectedStructure.clear(); + exprectedStructure.put("Highest", Map.entry(Set.of("@Path(\"/highest\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "double")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("double", + Map.entry(List.of(), + 1)))), + Map.entry("updateFromTemp_f", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("double"), + 1)))), + Map.entry("reset", Map.entry(Set.of("@PUT"), + Map.entry("void", + Map.entry(List.of("double"), + 1)))))))); + exprectedStructure.put("Temp_f", Map.entry(Set.of("@Path(\"/temp_f\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "double"), + Map.entry("client", "Client")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("double", + Map.entry(List.of(), + 1)))), + Map.entry("observe", Map.entry(Set.of("@PUT"), + Map.entry("void", + Map.entry(List.of("double"), + 5)))))))); + exprectedStructure.put("Temp_c", Map.entry(Set.of("@Path(\"/temp_c\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "double")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("double", + Map.entry(List.of(), + 1)))), + Map.entry("updateFromTemp_f", Map.entry(Set.of("@PUT"), + Map.entry("void", + Map.entry(List.of("double"), + 1)))))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private ArrayList generateCode(String fileName, PushPullValue pushPullValue) throws FileNotFoundException, + ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedRightCurlyBracket, ExpectedInOrOutOrRefOrSubKeyword, + ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, + WrongPathExpression, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { + File file = new File(fileName); + Parser parser = new Parser(new BufferedReader(new FileReader(file))); + DataTransferModel model; + model = parser.doParse(); + DataFlowGraph graph = DataTransferModelAnalyzer.createDataFlowGraphWithStateStoringAttribute(model); + DataTransferModelAnalyzer.annotateWithSelectableDataTransferAttiribute(graph); + if (pushPullValue != null) { + // Select a specified push/pull transfer method if possible. + for (Edge e : graph.getEdges()) { + if (!((DataFlowEdge) e).isChannelToResource() && ((DataFlowEdge) e).getAttribute() instanceof PushPullAttribute) { + PushPullAttribute ppat = (PushPullAttribute) ((DataFlowEdge) e).getAttribute(); + ppat.selectOption(pushPullValue); + } + } + } + TypeInference typeInference = new TypeInference(new JavaSpecific()); + typeInference.infer(model); + DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); +// ArrayList codetree = JerseyMethodBodyGenerator.doGenerate(graph, model, JerseyCodeGenerator.doGenerate(graph, model)); + CodeGenerator codeGenerator = new CodeGeneratorFromDataFlowGraph(new JerseySpecific(), new JavaSpecific()); + ArrayList codetree = codeGenerator.generateCode(model, graph); + return codetree; + } + + private void checkStructure(ArrayList generatedCode, + Map, Entry, Map, Entry, Integer>>>>>>> exprectedStructure) { + for (var classEnt: exprectedStructure.entrySet()) { + String expectedClassName = classEnt.getKey(); + Entry, Entry, Map, Entry, Integer>>>>>> expectedClassInfo = classEnt.getValue(); + TypeDeclaration generatedClass = null; + for (CompilationUnit cu: generatedCode) { + for (TypeDeclaration type: cu.types()) { + if (type.getTypeName().equals(expectedClassName)) { + generatedClass = type; + break; + } + } + } + assertNotNull(generatedClass); + + Set expectedClassAnnotations = expectedClassInfo.getKey(); + for (String expectedAnnotation: expectedClassAnnotations) { + boolean existsAnnotation = false; + for (Annotation generatedAnnotation: generatedClass.getAnnotations()) { + if (expectedAnnotation.equals(generatedAnnotation.toString())) { + existsAnnotation = true; + } + } + assertTrue(existsAnnotation); + } + Entry, Map, Entry, Integer>>>>> expectedClassStructure = expectedClassInfo.getValue(); + Map exprectedFields = expectedClassStructure.getKey(); + Map, Entry, Integer>>>> exprectedMethods = expectedClassStructure.getValue(); + + for (String expectedFieldName: exprectedFields.keySet()) { + FieldDeclaration generatedField = null; + for (FieldDeclaration field: generatedClass.getFields()) { + if (field.getName().equals(expectedFieldName)) { + generatedField = field; + break; + } + } + assertNotNull(generatedField); + + String expectedFieldType = exprectedFields.get(expectedFieldName); + if (expectedFieldType.equals("void")) { + assertNull(generatedField.getType()); + } else { + assertEquals(expectedFieldType, generatedField.getType().getInterfaceTypeName()); + } + } + + for (String expectedMethodName: exprectedMethods.keySet()) { + MethodDeclaration generatedMethod= null; + for (MethodDeclaration method: generatedClass.getMethods()) { + if (method.getName().equals(expectedMethodName)) { + generatedMethod = method; + break; + } + } + assertNotNull(generatedMethod); + + Entry, Entry, Integer>>> expectedMethodInfo = exprectedMethods.get(expectedMethodName); + Set expectedMethodAnnotations = expectedMethodInfo.getKey(); + for (String expectedAnnotation: expectedMethodAnnotations) { + boolean existsAnnotation = false; + for (Annotation generatedAnnotation: generatedMethod.getAnnotations()) { + if (expectedAnnotation.replaceAll("\\{.*\\}", "\\{\\}").equals(generatedAnnotation.toString().replaceAll("\\{.*\\}", "\\{\\}"))) { + existsAnnotation = true; + } + } + assertTrue(existsAnnotation); + } + Entry, Integer>> expectedMethodSignature = expectedMethodInfo.getValue(); + String expectedReturnType = expectedMethodSignature.getKey(); + if (expectedReturnType.equals("void")) { + if (generatedMethod.getReturnType() != null) { + assertEquals(expectedReturnType, generatedMethod.getReturnType().getInterfaceTypeName()); + } else { + assertNull(generatedMethod.getReturnType()); + } + } else { + assertEquals(expectedReturnType, generatedMethod.getReturnType().getInterfaceTypeName()); + } + Entry, Integer> expectedMethodInfo2 = expectedMethodSignature.getValue(); + List expectedArgTypes = expectedMethodInfo2.getKey(); + for (String expectedArgType: expectedArgTypes) { + boolean existsArg = false; + for (VariableDeclaration var: generatedMethod.getParameters()) { + if (expectedArgType.equals(var.getType().getInterfaceTypeName())) { + existsArg = true; + } + } + assertTrue(existsArg); + } + int expectedLinesOfCode = expectedMethodInfo2.getValue(); + assertEquals(expectedLinesOfCode, generatedMethod.getBody().getStatements().size()); + } + } + } + + private void generateCheckCode(ArrayList generatedCode) { +// exprectedStructure.put("Main", Map.entry(Set.of(), +// Map.entry(Map.ofEntries(Map.entry("history", "History"), +// Map.entry("total", "Total"), +// Map.entry("payment", "Payment"), +// Map.entry("points", "Points")), +// Map.ofEntries(Map.entry("Main", Map.entry(Set.of(), +// Map.entry("void", +// Map.entry(List.of(), +// 4)))), +// Map.entry("getHistory", Map.entry(Set.of(), +// Map.entry("List", +// Map.entry(List.of(), +// 1)))), +// Map.entry("getTotal", Map.entry(Set.of(), +// Map.entry("int", +// Map.entry(List.of(), +// 1)))), +// Map.entry("getPayment", Map.entry(Set.of(), +// Map.entry("int", +// Map.entry(List.of(), +// 1)))), +// Map.entry("purchase", Map.entry(Set.of(), +// Map.entry("void", +// Map.entry(List.of("int"), +// 1)))), +// Map.entry("getPoints", Map.entry(Set.of(), +// Map.entry("int", +// Map.entry(List.of(), +// 1)))))))); + for (CompilationUnit cu: generatedCode) { + for (TypeDeclaration type: cu.types()) { + Collection annotations = type.getAnnotations(); + List fields = type.getFields(); + List methods = type.getMethods(); + // class annotations + if (annotations.size() == 0) { + System.out.println("\t\t\texprectedStructure.put(\"" + type.getTypeName() + "\", Map.entry(Set.of(),"); + } else { + System.out.print("\t\t\texprectedStructure.put(\"" + type.getTypeName() + "\", Map.entry(Set.of("); + String delim = ""; + for (Annotation annotation: annotations) { + System.out.print(delim + "\"" + annotation.toString().replace("\"", "\\\"") + "\""); + delim = ","; + } + System.out.println("),"); + } + // fields + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + 1) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + 1) % 4; j++) { + System.out.print(" "); + } + if (fields.size() == 0) { + System.out.println("Map.entry(Map.ofEntries(),"); + } else if (fields.size() == 1) { + FieldDeclaration field = fields.get(0); + System.out.println("Map.entry(Map.ofEntries(Map.entry(\"" + field.getName() + "\", \"" + field.getType().getInterfaceTypeName() + "\")),"); + } else { + int i = 0; + for (FieldDeclaration field: fields) { + if (i == 0) { + System.out.println("Map.entry(Map.ofEntries(Map.entry(\"" + field.getName() + "\", \"" + field.getType().getInterfaceTypeName() + "\"),"); + } else { + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + 1) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + 1) % 4; j++) { + System.out.print(" "); + } + if (i < fields.size() - 1) { + System.out.println("Map.entry(\"" + field.getName() + "\", \"" + field.getType().getInterfaceTypeName() + "\"),"); + } else { + System.out.println("Map.entry(\"" + field.getName() + "\", \"" + field.getType().getInterfaceTypeName() + "\")),"); + } + } + i++; + } + } + // methods + if (methods.size() == 0) { + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + 3) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + 3) % 4; j++) { + System.out.print(" "); + } + System.out.println("Map.ofEntries())));"); + } else { + int i = 0; + for (MethodDeclaration method: methods) { + // method name and method annotations + if (i == 0) { + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + 3) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + 3) % 4; j++) { + System.out.print(" "); + } + Collection methodAnnotations = method.getAnnotations(); + if (methodAnnotations.size() == 0) { + System.out.println("Map.ofEntries(Map.entry(\"" + method.getName() + "\", Map.entry(Set.of(),"); + } else { + System.out.print("Map.ofEntries(Map.entry(\"" + method.getName() + "\", Map.entry(Set.of("); + String delim = ""; + for (Annotation annotation: methodAnnotations) { + System.out.print(delim + "\"" + annotation.toString().replace("\"", "\\\"") + "\""); + delim = ","; + } + System.out.println("),"); + } + } else { + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + 1) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + 1) % 4; j++) { + System.out.print(" "); + } + Collection methodAnnotations = method.getAnnotations(); + if (methodAnnotations.size() == 0) { + System.out.println("Map.entry(\"" + method.getName() + "\", Map.entry(Set.of(),"); + } else { + System.out.print("Map.entry(\"" + method.getName() + "\", Map.entry(Set.of("); + String delim = ""; + for (Annotation annotation: methodAnnotations) { + System.out.print(delim + "\"" + annotation.toString().replace("\"", "\\\"") + "\""); + delim = ","; + } + System.out.println("),"); + } + } + // return type + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) % 4; j++) { + System.out.print(" "); + } + if (method.getReturnType() == null) { + System.out.println("Map.entry(\"void\", "); + } else { + System.out.println("Map.entry(\"" + method.getReturnType().getInterfaceTypeName() + "\", "); + } + // method parameters + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) % 4; j++) { + System.out.print(" "); + } + if (method.getParameters() == null || method.getParameters().size() == 0) { + System.out.println("Map.entry(List.of(),"); + } else { + System.out.print("Map.entry(List.of("); + String delim = ""; + for (VariableDeclaration arg: method.getParameters()) { + System.out.print(delim + "\"" + arg.getType().getInterfaceTypeName() + "\""); + delim = ","; + } + System.out.println("),"); + } + // method lines of code + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) % 4; j++) { + System.out.print(" "); + } + if (i < methods.size() - 1) { + System.out.println("" + method.getBody().getStatements().size() + ")))),"); + } else { + System.out.println("" + method.getBody().getStatements().size() + "))))))));"); + } + i++; + } + } + } + } + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java b/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java new file mode 100644 index 0000000..dd488ba --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java @@ -0,0 +1,1656 @@ +package tests; + +import static org.junit.Assert.*; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.junit.Test; + +import algorithms.*; +import code.ast.CompilationUnit; +import code.ast.FieldDeclaration; +import code.ast.MethodDeclaration; +import code.ast.TypeDeclaration; +import code.ast.VariableDeclaration; +import generators.CodeGenerator; +import generators.CodeGeneratorFromDataFlowGraph; +import generators.DataTransferMethodAnalyzer; +import generators.JavaSpecific; +import generators.StandaloneSpecific; +import generators.TypeInference; +import models.Edge; +import models.dataFlowModel.*; +import parser.*; +import parser.exceptions.ExpectedAssignment; +import parser.exceptions.ExpectedChannel; +import parser.exceptions.ExpectedChannelName; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; +import parser.exceptions.ExpectedEquals; +import parser.exceptions.ExpectedInOrOutOrRefOrSubKeyword; +import parser.exceptions.ExpectedLeftCurlyBracket; +import parser.exceptions.ExpectedRHSExpression; +import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.ExpectedRightCurlyBracket; +import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; +import parser.exceptions.WrongLHSExpression; +import parser.exceptions.WrongPathExpression; +import parser.exceptions.WrongRHSExpression; + +public class JavaCodeGeneratorTest { + + @Test + public void test() { + testAccounts(); + testClock(); + testCustomerManagement(); // Two methods with the same signature are generated. + testGroupChat(); + testInventoryManagement(); +// testOnlineBattleGame(); // A feature has not been implemented for Java prototype generation. + testOnlineBattleGame2(); // Two methods with the same signature are generated. PUSH-first implementation still does not work. + testPOS(); + testSimpleTwitter(); + testVotingSystem(); + testWeatherObservationSystem(); + } + + private void testAccounts() { + try { + ArrayList generatedCode = generateCode("models/Accounts.model", null); + Map, // field name to type + Map, // arg types + Integer>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 1))), + Map.entry("getAccount", Map.entry("Map", + Map.entry(List.of("int"), + 1))), + Map.entry("getName", Map.entry("String", + Map.entry(List.of("int"), + 1))), + Map.entry("changeName", Map.entry("void", + Map.entry(List.of("int","String"), + 1))), + Map.entry("getAccounts", Map.entry("List", + Map.entry(List.of(), + 1))), + Map.entry("signup", Map.entry("void", + Map.entry(List.of("String"), + 1)))))); + exprectedStructure.put("Account", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getName", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("changeName", Map.entry("void", + Map.entry(List.of("int","String"), + 1))), + Map.entry("Account", Map.entry("void", + Map.entry(List.of("String"), + 1)))))); + exprectedStructure.put("Accounts", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("List", + Map.entry(List.of(), + 1))), + Map.entry("getAccount", Map.entry("Account", + Map.entry(List.of("int"), + 1))), + Map.entry("signup", Map.entry("void", + Map.entry(List.of("String"), + 1)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testClock() { + try { + // check PULL-first + ArrayList generatedCode = generateCode("models/Clock.model", PushPullValue.PULL); + Map, // field name to type + Map, // arg types + Integer>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(Map.entry("hour", "Hour"), + Map.entry("hour_ang", "Hour_ang"), + Map.entry("min", "Min"), + Map.entry("min_ang", "Min_ang")), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 4))), + Map.entry("getHour", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("getHour_ang", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("getMin", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("tick", Map.entry("void", + Map.entry(List.of(), + 1))), + Map.entry("getMin_ang", Map.entry("double", + Map.entry(List.of(), + 1)))))); + exprectedStructure.put("Hour", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("updateFromMin", Map.entry("void", + Map.entry(List.of("int"), + 1)))))); + exprectedStructure.put("Hour_ang", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("Hour_ang", Map.entry("void", + Map.entry(List.of("Hour"), + 1)))))); + exprectedStructure.put("Min", Map.entry(Map.ofEntries(Map.entry("value", "int"), + Map.entry("hour", "Hour")), + Map.ofEntries(Map.entry("getValue", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("tick", Map.entry("void", + Map.entry(List.of(), + 2))), + Map.entry("Min", Map.entry("void", + Map.entry(List.of("Hour"), + 1)))))); + exprectedStructure.put("Min_ang", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("Min_ang", Map.entry("void", + Map.entry(List.of("Min"), + 1)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + + // check PUSH-first + generatedCode = generateCode("models/Clock.model", PushPullValue.PUSH); + exprectedStructure.clear(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(Map.entry("hour_ang", "Hour_ang"), + Map.entry("min_ang", "Min_ang"), + Map.entry("hour", "Hour"), + Map.entry("min", "Min")), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 4))), + Map.entry("getHour_ang", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("getMin_ang", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("getHour", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("getMin", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("tick", Map.entry("void", + Map.entry(List.of(), + 1)))))); + exprectedStructure.put("Hour_ang", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("updateFromHour", Map.entry("void", + Map.entry(List.of("int"), + 1)))))); + exprectedStructure.put("Min_ang", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("updateFromMin", Map.entry("void", + Map.entry(List.of("int"), + 1)))))); + exprectedStructure.put("Hour", Map.entry(Map.ofEntries(Map.entry("value", "int"), + Map.entry("hour_ang", "Hour_ang")), + Map.ofEntries(Map.entry("getValue", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("updateFromMin", Map.entry("void", + Map.entry(List.of("int"), + 2))), + Map.entry("Hour", Map.entry("void", + Map.entry(List.of("Hour_ang"), + 1)))))); + exprectedStructure.put("Min", Map.entry(Map.ofEntries(Map.entry("value", "int"), + Map.entry("min_ang", "Min_ang"), + Map.entry("hour", "Hour")), + Map.ofEntries(Map.entry("getValue", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("tick", Map.entry("void", + Map.entry(List.of(), + 3))), + Map.entry("Min", Map.entry("void", + Map.entry(List.of("Min_ang","Hour"), + 2)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testCustomerManagement() { + try { + ArrayList generatedCode = generateCode("models/CustomerManagement.model", null); + Map, // field name to type + Map, // arg types + Integer>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(Map.entry("companies", "Companies"), + Map.entry("customers", "Customers")), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 2))), + Map.entry("getAddress", Map.entry("String", + Map.entry(List.of("String"), + 1))), + Map.entry("setAddress", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getCustomer", Map.entry("Map", + Map.entry(List.of("String"), + 1))), + Map.entry("getCompanies", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("addCampany", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getOrganization", Map.entry("String", + Map.entry(List.of("String"), + 1))), + Map.entry("setOrganization", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), +// Map.entry("getAddress", Map.entry("String", +// Map.entry(List.of("String"), +// 1))), + Map.entry("getCompany", Map.entry("Map", + Map.entry(List.of("String"), + 1))), + Map.entry("getCustomers", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("addCustomer", Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))); + exprectedStructure.put("Customer", Map.entry(Map.ofEntries(Map.entry("organization", "String"), + Map.entry("company", "Company"), + Map.entry("companies", "Companies")), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getOrganization", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("getAddress", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("setOrganization", Map.entry("void", + Map.entry(List.of("String","String"), + 2))), + Map.entry("Customer", Map.entry("void", + Map.entry(List.of("String","Companies"), + 3)))))); + exprectedStructure.put("Companies", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getCompany", Map.entry("Company", + Map.entry(List.of("String"), + 1))), + Map.entry("addCampany", Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))); + exprectedStructure.put("Company", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getAddress", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("setAddress", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("Company", Map.entry("void", + Map.entry(List.of("String"), + 1)))))); + exprectedStructure.put("Customers", Map.entry(Map.ofEntries(Map.entry("value", "Map"), + Map.entry("companies", "Companies")), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getCustomer", Map.entry("Customer", + Map.entry(List.of("String"), + 1))), + Map.entry("addCustomer", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("Customers", Map.entry("void", + Map.entry(List.of("Companies"), + 1)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testGroupChat() { + try { + ArrayList generatedCode = generateCode("models/GroupChat.model", null); + Map, // field name to type + Map, // arg types + Integer>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(Map.entry("accounts", "Accounts"), + Map.entry("groups", "Groups")), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 2))), + Map.entry("getAccounts", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("signUp", Map.entry("void", + Map.entry(List.of("String"), + 1))), + Map.entry("getGroup", Map.entry("Map", + Map.entry(List.of("String"), + 1))), + Map.entry("getMessages", Map.entry("List", + Map.entry(List.of("String"), + 1))), + Map.entry("postMessage", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getAccount", Map.entry("Map", + Map.entry(List.of("String"), + 1))), + Map.entry("getMember", Map.entry("String", + Map.entry(List.of("String","int"), + 1))), + Map.entry("getNotifications", Map.entry("Map", + Map.entry(List.of("String"), + 1))), + Map.entry("hasRead", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getMembers", Map.entry("List", + Map.entry(List.of("String"), + 1))), + Map.entry("addGroupMember", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getGroups", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("createGroup", Map.entry("void", + Map.entry(List.of("String"), + 1)))))); + exprectedStructure.put("Accounts", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getAccount", Map.entry("Account", + Map.entry(List.of("String"), + 1))), + Map.entry("signUp", Map.entry("void", + Map.entry(List.of("String"), + 1)))))); + exprectedStructure.put("Group", Map.entry(Map.ofEntries(Map.entry("messages", "List"), + Map.entry("account", "Account"), + Map.entry("accounts", "Accounts"), + Map.entry("members", "List")), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getMessages", Map.entry("List", + Map.entry(List.of(), + 1))), + Map.entry("getMember", Map.entry("String", + Map.entry(List.of("int"), + 1))), + Map.entry("getMembers", Map.entry("List", + Map.entry(List.of(), + 1))), + Map.entry("postMessage", Map.entry("void", + Map.entry(List.of("String","String"), + 2))), + Map.entry("addGroupMember", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("Group", Map.entry("void", + Map.entry(List.of("List","Accounts","List"), + 3)))))); + exprectedStructure.put("Account", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getNotifications", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("updateNotificationsFromMessages", Map.entry("void", + Map.entry(List.of("String","String","int","List","String"), + 1))), + Map.entry("hasRead", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("Account", Map.entry("void", + Map.entry(List.of("Map"), + 1)))))); + exprectedStructure.put("Groups", Map.entry(Map.ofEntries(Map.entry("value", "Map"), + Map.entry("accounts", "Accounts")), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getGroup", Map.entry("Group", + Map.entry(List.of("String"), + 1))), + Map.entry("createGroup", Map.entry("void", + Map.entry(List.of("String"), + 1))), + Map.entry("Groups", Map.entry("void", + Map.entry(List.of("Accounts"), + 1)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testInventoryManagement() { + try { + ArrayList generatedCode = generateCode("models/InventoryManagement.model", null); + Map, // field name to type + Map, // arg types + Integer>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 1))), + Map.entry("getInventoryElement", Map.entry("Map", + Map.entry(List.of("String"), + 1))), + Map.entry("getInventory", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("registerItem", Map.entry("void", + Map.entry(List.of("String","int","String"), + 1))), + Map.entry("getCount", Map.entry("int", + Map.entry(List.of("String"), + 1))), + Map.entry("receiveOrShip", Map.entry("void", + Map.entry(List.of("String","int"), + 1)))))); + exprectedStructure.put("InventoryElement", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getCount", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("receiveOrShip", Map.entry("void", + Map.entry(List.of("String","int"), + 1))), + Map.entry("InventoryElement", Map.entry("void", + Map.entry(List.of("int"), + 1)))))); + exprectedStructure.put("Inventory", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getInventoryElement", Map.entry("InventoryElement", + Map.entry(List.of("String"), + 1))), + Map.entry("registerItem", Map.entry("void", + Map.entry(List.of("String","int","String"), + 1)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testOnlineBattleGame() { + try { + // check PULL-first + ArrayList generatedCode = generateCode("models/OnlineBattleGame.model", PushPullValue.PULL); + Map, // field name to type + Map, // arg types + Integer>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(Map.entry("accounts", "Accounts"), + Map.entry("rooms", "Rooms")), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 2))), + Map.entry("getRoom", Map.entry("Map", + Map.entry(List.of("String"), + 1))), + Map.entry("getName", Map.entry("String", + Map.entry(List.of("String"), + 1))), + Map.entry("changeName", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getAccount", Map.entry("Map", + Map.entry(List.of("String"), + 1))), + Map.entry("getBlue_id", Map.entry("String", + Map.entry(List.of("String"), + 1))), + Map.entry("changeBlueId", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getRed_id", Map.entry("String", + Map.entry(List.of("String"), + 1))), + Map.entry("changeRedId", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getAccounts", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("signUp", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getRooms", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("createRoom", Map.entry("void", + Map.entry(List.of("String","String","String"), + 1))), + Map.entry("getRed_name", Map.entry("String", + Map.entry(List.of("String"), + 1))), + Map.entry("getBlue_name", Map.entry("String", + Map.entry(List.of("String"), + 1)))))); + exprectedStructure.put("Room", Map.entry(Map.ofEntries(Map.entry("blue_id", "String"), + Map.entry("red_id", "String"), + Map.entry("account", "Account"), + Map.entry("accounts", "Accounts")), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getBlue_id", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("getRed_id", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("getRed_name", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("getBlue_name", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("changeRedId", Map.entry("void", + Map.entry(List.of("String","String"), + 2))), + Map.entry("changeBlueId", Map.entry("void", + Map.entry(List.of("String","String"), + 2))), + Map.entry("Room", Map.entry("void", + Map.entry(List.of("String","String","Accounts"), + 5)))))); + exprectedStructure.put("Account", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getName", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("changeName", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("Account", Map.entry("void", + Map.entry(List.of("String"), + 1)))))); + exprectedStructure.put("Accounts", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getAccount", Map.entry("Account", + Map.entry(List.of("String"), + 1))), + Map.entry("signUp", Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))); + exprectedStructure.put("Rooms", Map.entry(Map.ofEntries(Map.entry("value", "Map"), + Map.entry("accounts", "Accounts")), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getRoom", Map.entry("Room", + Map.entry(List.of("String"), + 1))), + Map.entry("createRoom", Map.entry("void", + Map.entry(List.of("String","String","String"), + 1))), + Map.entry("Rooms", Map.entry("void", + Map.entry(List.of("Accounts"), + 1)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + + // check PUSH-first + generatedCode = generateCode("models/OnlineBattleGame.model", PushPullValue.PUSH); + exprectedStructure.clear(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(Map.entry("accounts", "Accounts"), + Map.entry("rooms", "Rooms")), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 2))), + Map.entry("getAccount", Map.entry("Map", + Map.entry(List.of("String"), + 1))), + Map.entry("getBlue_name", Map.entry("String", + Map.entry(List.of("String"), + 1))), + Map.entry("getBlue_id", Map.entry("String", + Map.entry(List.of("String"), + 1))), + Map.entry("changeBlueId", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getRed_name", Map.entry("String", + Map.entry(List.of("String"), + 1))), + Map.entry("getRed_id", Map.entry("String", + Map.entry(List.of("String"), + 1))), + Map.entry("changeRedId", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getName", Map.entry("String", + Map.entry(List.of("String"), + 1))), + Map.entry("changeName", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getAccounts", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("signUp", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getRooms", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("createRoom", Map.entry("void", + Map.entry(List.of("String","String","String"), + 1))), + Map.entry("getRoom", Map.entry("Map", + Map.entry(List.of("String"), + 1)))))); + exprectedStructure.put("Account", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getName", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("changeName", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("Account", Map.entry("void", + Map.entry(List.of("String"), + 1)))))); + exprectedStructure.put("Accounts", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getAccount", Map.entry("Account", + Map.entry(List.of("String"), + 1))), + Map.entry("signUp", Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))); + exprectedStructure.put("Rooms", Map.entry(Map.ofEntries(Map.entry("value", "Map"), + Map.entry("accounts", "Accounts")), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getRoom", Map.entry("Room", + Map.entry(List.of("String"), + 1))), + Map.entry("createRoom", Map.entry("void", + Map.entry(List.of("String","String","String"), + 1))), + Map.entry("Rooms", Map.entry("void", + Map.entry(List.of("Accounts"), + 1)))))); + exprectedStructure.put("Room", Map.entry(Map.ofEntries(Map.entry("account", "Account"), + Map.entry("accounts", "Accounts"), + Map.entry("blue_id", "String"), + Map.entry("red_id", "String")), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getBlue_name", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("getBlue_id", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("getRed_name", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("getRed_id", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("updateBlue_nameFromBlue_id", Map.entry("void", + Map.entry(List.of("String","String","String"), + 2))), + Map.entry("updateRed_nameFromRed_id", Map.entry("void", + Map.entry(List.of("String","String","String"), + 2))), + Map.entry("changeRedId", Map.entry("void", + Map.entry(List.of("String","String"), + 3))), + Map.entry("changeBlueId", Map.entry("void", + Map.entry(List.of("String","String"), + 3))), + Map.entry("Room", Map.entry("void", + Map.entry(List.of("Accounts","String","String"), + 5)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + + private void testOnlineBattleGame2() { + try { + ArrayList generatedCode = generateCode("models/OnlineBattleGame2.model", null); + Map, // field name to type + Map, // arg types + Integer>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(Map.entry("accounts", "Accounts"), + Map.entry("rooms", "Rooms")), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 2))), + Map.entry("getAccount", Map.entry("Map", + Map.entry(List.of("String"), + 1))), + Map.entry("getMember", Map.entry("Map", + Map.entry(List.of("String","int"), + 1))), + Map.entry("getMembers", Map.entry("List", + Map.entry(List.of("String"), + 1))), + Map.entry("addRoomMember", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getAccounts", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("signUp", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getRoom", Map.entry("Map", + Map.entry(List.of("String"), + 1))), + Map.entry("getId", Map.entry("String", + Map.entry(List.of("String","int"), + 1))), + Map.entry("getName", Map.entry("String", + Map.entry(List.of("String"), + 1))), + Map.entry("changeName", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getRooms", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("createRoom", Map.entry("void", + Map.entry(List.of("String"), + 1))), +// Map.entry("getName", Map.entry("String", +// Map.entry(List.of("String","int"), +// 1))), + Map.entry("getBattle", Map.entry("boolean", + Map.entry(List.of("String"), + 1))), + Map.entry("battle", Map.entry("void", + Map.entry(List.of("String","boolean"), + 1))), + Map.entry("getPoint", Map.entry("int", + Map.entry(List.of("String"), + 1)))))); + exprectedStructure.put("Account", Map.entry(Map.ofEntries(Map.entry("name", "String"), + Map.entry("point", "int")), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getName", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("getPoint", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("updatePointFromBattle", Map.entry("void", + Map.entry(List.of("String","String","int","boolean","String"), + 1))), + Map.entry("changeName", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("Account", Map.entry("void", + Map.entry(List.of("String","int"), + 2)))))); + exprectedStructure.put("Member", Map.entry(Map.ofEntries(Map.entry("id", "String"), + Map.entry("account", "Account"), + Map.entry("accounts", "Accounts")), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getId", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("getName", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("Member", Map.entry("void", + Map.entry(List.of("String","Accounts"), + 2)))))); + exprectedStructure.put("Members", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("List", + Map.entry(List.of(), + 1))), + Map.entry("getMember", Map.entry("Member", + Map.entry(List.of("int"), + 1))), + Map.entry("addRoomMember", Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))); + exprectedStructure.put("Accounts", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getAccount", Map.entry("Account", + Map.entry(List.of("String"), + 1))), + Map.entry("signUp", Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))); + exprectedStructure.put("Room", Map.entry(Map.ofEntries(Map.entry("members", "Members"), + Map.entry("battle", "boolean"), + Map.entry("account", "Account"), + Map.entry("accounts", "Accounts")), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getMembers", Map.entry("Members", + Map.entry(List.of(), + 1))), + Map.entry("getBattle", Map.entry("boolean", + Map.entry(List.of(), + 1))), + Map.entry("battle", Map.entry("void", + Map.entry(List.of("String","boolean"), + 2))), + Map.entry("Room", Map.entry("void", + Map.entry(List.of("boolean","Accounts"), + 2)))))); + exprectedStructure.put("Rooms", Map.entry(Map.ofEntries(Map.entry("value", "Map"), + Map.entry("accounts", "Accounts")), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getRoom", Map.entry("Room", + Map.entry(List.of("String"), + 1))), + Map.entry("createRoom", Map.entry("void", + Map.entry(List.of("String"), + 1))), + Map.entry("Rooms", Map.entry("void", + Map.entry(List.of("Accounts"), + 1)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testPOS() { + try { + // check PULL-first + ArrayList generatedCode = generateCode("models/POS.model", PushPullValue.PULL); + Map, // field name to type + Map, // arg types + Integer>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(Map.entry("history", "History"), + Map.entry("total", "Total"), + Map.entry("payment", "Payment"), + Map.entry("points", "Points")), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 4))), + Map.entry("getHistory", Map.entry("List", + Map.entry(List.of(), + 1))), + Map.entry("getTotal", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("getPayment", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("purchase", Map.entry("void", + Map.entry(List.of("int"), + 1))), + Map.entry("getPoints", Map.entry("int", + Map.entry(List.of(), + 1)))))); + exprectedStructure.put("History", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("List", + Map.entry(List.of(), + 1))), + Map.entry("updateFromPayment", Map.entry("void", + Map.entry(List.of("int"), + 1)))))); + exprectedStructure.put("Total", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("Total", Map.entry("void", + Map.entry(List.of("History"), + 1)))))); + exprectedStructure.put("Payment", Map.entry(Map.ofEntries(Map.entry("value", "int"), + Map.entry("history", "History")), + Map.ofEntries(Map.entry("getValue", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("purchase", Map.entry("void", + Map.entry(List.of("int"), + 2))), + Map.entry("Payment", Map.entry("void", + Map.entry(List.of("History"), + 1)))))); + exprectedStructure.put("Points", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("Points", Map.entry("void", + Map.entry(List.of("Payment"), + 1)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + + // check PUSH-first + generatedCode = generateCode("models/POS.model", PushPullValue.PUSH); + exprectedStructure.clear(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(Map.entry("points", "Points"), + Map.entry("total", "Total"), + Map.entry("history", "History"), + Map.entry("payment", "Payment")), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 4))), + Map.entry("getPoints", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("getTotal", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("getHistory", Map.entry("List", + Map.entry(List.of(), + 1))), + Map.entry("getPayment", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("purchase", Map.entry("void", + Map.entry(List.of("int"), + 1)))))); + exprectedStructure.put("Points", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("updateFromPayment", Map.entry("void", + Map.entry(List.of("int"), + 1)))))); + exprectedStructure.put("Total", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("updateFromHistory", Map.entry("void", + Map.entry(List.of("List"), + 1)))))); + exprectedStructure.put("History", Map.entry(Map.ofEntries(Map.entry("value", "List"), + Map.entry("total", "Total")), + Map.ofEntries(Map.entry("getValue", Map.entry("List", + Map.entry(List.of(), + 1))), + Map.entry("updateFromPayment", Map.entry("void", + Map.entry(List.of("int"), + 2))), + Map.entry("History", Map.entry("void", + Map.entry(List.of("Total"), + 1)))))); + exprectedStructure.put("Payment", Map.entry(Map.ofEntries(Map.entry("value", "int"), + Map.entry("points", "Points"), + Map.entry("history", "History")), + Map.ofEntries(Map.entry("getValue", Map.entry("int", + Map.entry(List.of(), + 1))), + Map.entry("purchase", Map.entry("void", + Map.entry(List.of("int"), + 3))), + Map.entry("Payment", Map.entry("void", + Map.entry(List.of("Points","History"), + 2)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testSimpleTwitter() { + try { + ArrayList generatedCode = generateCode("models/SimpleTwitter.model", null); + Map, // field name to type + Map, // arg types + Integer>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 1))), + Map.entry("getAccount", Map.entry("Map", + Map.entry(List.of("String"), + 1))), + Map.entry("getAccounts", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("signUp", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getTweets", Map.entry("List", + Map.entry(List.of("String"), + 1))), + Map.entry("tweet", Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))); + exprectedStructure.put("Account", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getTweets", Map.entry("List", + Map.entry(List.of(), + 1))), + Map.entry("tweet", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("Account", Map.entry("void", + Map.entry(List.of("List"), + 1)))))); + exprectedStructure.put("Accounts", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getAccount", Map.entry("Account", + Map.entry(List.of("String"), + 1))), + Map.entry("signUp", Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testVotingSystem() { + try { + ArrayList generatedCode = generateCode("models/VotingSystem.model", null); + Map, // field name to type + Map, // arg types + Integer>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(Map.entry("accounts", "Accounts"), + Map.entry("counts", "Counts")), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 2))), + Map.entry("getAccounts", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("signUp", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getVote", Map.entry("String", + Map.entry(List.of("String"), + 1))), + Map.entry("cast", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("getAccount", Map.entry("Map", + Map.entry(List.of("String"), + 1))), + Map.entry("getCounts", Map.entry("Map", + Map.entry(List.of(), + 1)))))); + exprectedStructure.put("Accounts", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getAccount", Map.entry("Account", + Map.entry(List.of("String"), + 1))), + Map.entry("signUp", Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))); + exprectedStructure.put("Account", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 1))), + Map.entry("getVote", Map.entry("String", + Map.entry(List.of(), + 1))), + Map.entry("cast", Map.entry("void", + Map.entry(List.of("String","String"), + 1))), + Map.entry("Account", Map.entry("void", + Map.entry(List.of("String"), + 1)))))); + exprectedStructure.put("Counts", Map.entry(Map.ofEntries(Map.entry("value", "Map"), + Map.entry("account", "Account"), + Map.entry("accounts", "Accounts")), + Map.ofEntries(Map.entry("getValue", Map.entry("Map", + Map.entry(List.of(), + 5))), + Map.entry("Counts", Map.entry("void", + Map.entry(List.of("Accounts"), + 1)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private void testWeatherObservationSystem() { + try { + // check PULL-first + ArrayList generatedCode = generateCode("models/WeatherObservationSystem.model", PushPullValue.PULL); + Map, // field name to type + Map, // arg types + Integer>>>>> // lines of code + exprectedStructure = new HashMap<>(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(Map.entry("highest", "Highest"), + Map.entry("temp_f", "Temp_f"), + Map.entry("temp_c", "Temp_c")), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 3))), + Map.entry("getHighest", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("reset", Map.entry("void", + Map.entry(List.of("double"), + 1))), + Map.entry("getTemp_f", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("observe", Map.entry("void", + Map.entry(List.of("double"), + 1))), + Map.entry("getTemp_c", Map.entry("double", + Map.entry(List.of(), + 1)))))); + exprectedStructure.put("Highest", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("updateFromTemp_f", Map.entry("void", + Map.entry(List.of("double"), + 1))), + Map.entry("reset", Map.entry("void", + Map.entry(List.of("double"), + 1)))))); + exprectedStructure.put("Temp_f", Map.entry(Map.ofEntries(Map.entry("value", "double"), + Map.entry("highest", "Highest")), + Map.ofEntries(Map.entry("getValue", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("observe", Map.entry("void", + Map.entry(List.of("double"), + 2))), + Map.entry("Temp_f", Map.entry("void", + Map.entry(List.of("Highest"), + 1)))))); + exprectedStructure.put("Temp_c", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("Temp_c", Map.entry("void", + Map.entry(List.of("Temp_f"), + 1)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + + // check PUSH-first + generatedCode = generateCode("models/WeatherObservationSystem.model", PushPullValue.PUSH); + exprectedStructure.clear(); + exprectedStructure.put("Main", Map.entry(Map.ofEntries(Map.entry("temp_c", "Temp_c"), + Map.entry("highest", "Highest"), + Map.entry("temp_f", "Temp_f")), + Map.ofEntries(Map.entry("Main", Map.entry("void", + Map.entry(List.of(), + 3))), + Map.entry("getTemp_c", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("getHighest", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("reset", Map.entry("void", + Map.entry(List.of("double"), + 1))), + Map.entry("getTemp_f", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("observe", Map.entry("void", + Map.entry(List.of("double"), + 1)))))); + exprectedStructure.put("Temp_c", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("updateFromTemp_f", Map.entry("void", + Map.entry(List.of("double"), + 1)))))); + exprectedStructure.put("Highest", Map.entry(Map.ofEntries(), + Map.ofEntries(Map.entry("getValue", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("updateFromTemp_f", Map.entry("void", + Map.entry(List.of("double"), + 1))), + Map.entry("reset", Map.entry("void", + Map.entry(List.of("double"), + 1)))))); + exprectedStructure.put("Temp_f", Map.entry(Map.ofEntries(Map.entry("value", "double"), + Map.entry("highest", "Highest"), + Map.entry("temp_c", "Temp_c")), + Map.ofEntries(Map.entry("getValue", Map.entry("double", + Map.entry(List.of(), + 1))), + Map.entry("observe", Map.entry("void", + Map.entry(List.of("double"), + 3))), + Map.entry("Temp_f", Map.entry("void", + Map.entry(List.of("Highest","Temp_c"), + 2)))))); + + checkStructure(generatedCode, exprectedStructure); +// generateCheckCode(generatedCode); + } catch (FileNotFoundException + | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } + + private ArrayList generateCode(String fileName, PushPullValue pushPullValue) throws FileNotFoundException, + ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedRightCurlyBracket, ExpectedInOrOutOrRefOrSubKeyword, + ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, + WrongPathExpression, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation { + File file = new File(fileName); + Parser parser = new Parser(new BufferedReader(new FileReader(file))); + DataTransferModel model; + model = parser.doParse(); + DataFlowGraph graph = DataTransferModelAnalyzer.createDataFlowGraphWithStateStoringAttribute(model); + DataTransferModelAnalyzer.annotateWithSelectableDataTransferAttiribute(graph); + if (pushPullValue != null) { + // Select a specified push/pull transfer method if possible. + for (Edge e : graph.getEdges()) { + if (!((DataFlowEdge) e).isChannelToResource() && ((DataFlowEdge) e).getAttribute() instanceof PushPullAttribute) { + PushPullAttribute ppat = (PushPullAttribute) ((DataFlowEdge) e).getAttribute(); + ppat.selectOption(pushPullValue); + } + } + } + TypeInference typeInference = new TypeInference(new JavaSpecific()); + typeInference.infer(model); + DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); +// ArrayList codetree = JavaMethodBodyGenerator.doGenerate(graph, model, JavaCodeGenerator.doGenerate(graph, model)); + CodeGenerator codeGenerator = new CodeGeneratorFromDataFlowGraph(new StandaloneSpecific(), new JavaSpecific()); + ArrayList codetree = codeGenerator.generateCode(model, graph); + return codetree; + } + + private void checkStructure(ArrayList generatedCode, + Map, Map, Integer>>>>> exprectedStructure) { + for (var classEnt: exprectedStructure.entrySet()) { + String expectedClassName = classEnt.getKey(); + Entry, Map, Integer>>>> expectedClassStructure = classEnt.getValue(); + TypeDeclaration generatedClass = null; + for (CompilationUnit cu: generatedCode) { + for (TypeDeclaration type: cu.types()) { + if (type.getTypeName().equals(expectedClassName)) { + generatedClass = type; + break; + } + } + } + assertNotNull(generatedClass); + + Map exprectedFields = expectedClassStructure.getKey(); + Map, Integer>>> exprectedMethods = expectedClassStructure.getValue(); + + for (String expectedFieldName: exprectedFields.keySet()) { + FieldDeclaration generatedField = null; + for (FieldDeclaration field: generatedClass.getFields()) { + if (field.getName().equals(expectedFieldName)) { + generatedField = field; + break; + } + } + assertNotNull(generatedField); + + String expectedFieldType = exprectedFields.get(expectedFieldName); + if (expectedFieldType.equals("void")) { + assertNull(generatedField.getType()); + } else { + assertEquals(expectedFieldType, generatedField.getType().getInterfaceTypeName()); + } + } + + for (String expectedMethodName: exprectedMethods.keySet()) { + MethodDeclaration generatedMethod= null; + for (MethodDeclaration method: generatedClass.getMethods()) { + if (method.getName().equals(expectedMethodName)) { + generatedMethod = method; + break; + } + } + assertNotNull(generatedMethod); + + Entry, Integer>> expectedMethodInfo = exprectedMethods.get(expectedMethodName); + String expectedReturnType = expectedMethodInfo.getKey(); + if (expectedReturnType.equals("void")) { + if (generatedMethod.getReturnType() != null) { + assertEquals(expectedReturnType, generatedMethod.getReturnType().getInterfaceTypeName()); + } else { + assertNull(generatedMethod.getReturnType()); + } + } else { + assertEquals(expectedReturnType, generatedMethod.getReturnType().getInterfaceTypeName()); + } + Entry, Integer> expectedMethodInfo2 = expectedMethodInfo.getValue(); + List expectedArgTypes = expectedMethodInfo2.getKey(); + for (String expectedArgType: expectedArgTypes) { + boolean existsArg = false; + for (VariableDeclaration var: generatedMethod.getParameters()) { + if (expectedArgType.equals(var.getType().getInterfaceTypeName())) { + existsArg = true; + } + } + assertTrue(existsArg); + } + int expectedLinesOfCode = expectedMethodInfo2.getValue(); + assertEquals(expectedLinesOfCode, generatedMethod.getBody().getStatements().size()); + } + } + } + + private void generateCheckCode(ArrayList generatedCode) { +// exprectedStructure.put("Main", Map.entry(Map.ofEntries(Map.entry("history", "History"), +// Map.entry("total", "Total"), +// Map.entry("payment", "Payment"), +// Map.entry("points", "Points")), +// Map.ofEntries(Map.entry("Main", Map.entry("void", +// Map.entry(List.of(), +// 4))), +// Map.entry("getHistory", Map.entry("List", +// Map.entry(List.of(), +// 1))), +// Map.entry("getTotal", Map.entry("int", +// Map.entry(List.of(), +// 1))), +// Map.entry("getPayment", Map.entry("int", +// Map.entry(List.of(), +// 1))), +// Map.entry("purchase", Map.entry("void", +// Map.entry(List.of("int"), +// 1))), +// Map.entry("getPoints", Map.entry("int", +// Map.entry(List.of(), +// 1)))))); + for (CompilationUnit cu: generatedCode) { + for (TypeDeclaration type: cu.types()) { + List fields = type.getFields(); + List methods = type.getMethods(); + // fields + if (fields.size() == 0) { + System.out.println("\t\t\texprectedStructure.put(\"" + type.getTypeName() + "\", Map.entry(Map.ofEntries(),"); + } if (fields.size() == 1) { + System.out.println("\t\t\texprectedStructure.put(\"" + type.getTypeName() + "\", Map.entry(Map.ofEntries(),"); + } else { + int i = 0; + for (FieldDeclaration field: fields) { + if (i == 0) { + System.out.println("\t\t\texprectedStructure.put(\"" + type.getTypeName() + "\", Map.entry(Map.ofEntries(Map.entry(\"" + field.getName() + "\", \"" + field.getType().getInterfaceTypeName() + "\"),"); + } else { + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + 3) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + 3) % 4; j++) { + System.out.print(" "); + } + if (i < fields.size() - 1) { + System.out.println("Map.entry(\"" + field.getName() + "\", \"" + field.getType().getInterfaceTypeName() + "\"),"); + } else { + System.out.println("Map.entry(\"" + field.getName() + "\", \"" + field.getType().getInterfaceTypeName() + "\")),"); + } + } + i++; + } + } + // methods + if (methods.size() == 0) { + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + 1) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + 1) % 4; j++) { + System.out.print(" "); + } + System.out.println("Map.ofEntries())));"); + } else { + int i = 0; + for (MethodDeclaration method: methods) { + // method name and return type + if (i == 0) { + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + 1) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + 1) % 4; j++) { + System.out.print(" "); + } + if (method.getReturnType() == null) { + System.out.println("Map.ofEntries(Map.entry(\"" + method.getName() + "\", Map.entry(\"void\", "); + } else { + System.out.println("Map.ofEntries(Map.entry(\"" + method.getName() + "\", Map.entry(\"" + method.getReturnType().getInterfaceTypeName() + "\", "); + } + } else { + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + 3) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + 3) % 4; j++) { + System.out.print(" "); + } + if (method.getReturnType() == null) { + System.out.println("Map.entry(\"" + method.getName() + "\", Map.entry(\"void\", "); + } else { + System.out.println("Map.entry(\"" + method.getName() + "\", Map.entry(\"" + method.getReturnType().getInterfaceTypeName() + "\", "); + } + } + // method parameters + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) % 4; j++) { + System.out.print(" "); + } + if (method.getParameters() == null || method.getParameters().size() == 0) { + System.out.println("Map.entry(List.of(),"); + } else { + System.out.print("Map.entry(List.of("); + String delim = ""; + for (VariableDeclaration arg: method.getParameters()) { + System.out.print(delim + "\"" + arg.getType().getInterfaceTypeName() + "\""); + delim = ","; + } + System.out.println("),"); + } + // method lines of code + System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"); + for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) / 4; j++) { + System.out.print("\t"); + } + for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) % 4; j++) { + System.out.print(" "); + } + if (i < methods.size() - 1) { + System.out.println("" + method.getBody().getStatements().size() + "))),"); + } else { + System.out.println("" + method.getBody().getStatements().size() + "))))));"); + } + i++; + } + } + } + } + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java b/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java new file mode 100644 index 0000000..63cda9e --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java @@ -0,0 +1,104 @@ +package tests; + +import org.junit.Test; + +import generators.JavaSpecific; +import generators.TypeInference; +import models.algebra.Expression; +import models.algebra.InvalidMessage; +import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.UnificationFailed; +import models.algebra.ValueUndefined; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.ResourcePath; +import models.dataFlowModel.DataTransferChannel; +import models.dataFlowModel.DataTransferModel; +import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; +import parser.Parser; +import parser.Parser.TokenStream; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; +import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.WrongJsonExpression; +import simulator.Event; +import simulator.Resource; +import simulator.Simulator; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; +import simulator.interfaces.NativeSender; + +public class NativeAccessTest { + + @Test + public void test() { + try { + TokenStream stream = new Parser.TokenStream(); + Parser parser = new Parser(stream); + + // Construct a data transfer architecture model. + DataTransferModel model = new DataTransferModel(); + ResourcePath sampleText = new ResourcePath("sampleText"); + model.addResourcePath(sampleText); + + DataTransferChannel nativeInputEventChannel = new DataTransferChannel("NativeInput"); + nativeInputEventChannel.setNative(true); + ChannelMember textIn = new ChannelMember(sampleText); + stream.addLine("curText:Str"); + Expression curStateIn = parser.parseTerm(stream, model); + stream.addLine("input(nextText)"); + Expression messageIn = parser.parseTerm(stream, model); + stream.addLine("nextText"); + Expression nextStateIn = parser.parseTerm(stream, model); + textIn.getStateTransition().setCurStateExpression(curStateIn); + textIn.getStateTransition().setMessageExpression(messageIn); + textIn.getStateTransition().setNextStateExpression(nextStateIn); + nativeInputEventChannel.addChannelMemberAsOutput(textIn); + model.addInputChannel(nativeInputEventChannel); + + DataTransferChannel nativeOutputEventChannel = new DataTransferChannel("NativeOutput"); + nativeOutputEventChannel.setNative(true); + ChannelMember textOut = new ChannelMember(sampleText); + stream.addLine("curText:Str"); + Expression curStateOut = parser.parseTerm(stream, model); + stream.addLine("output(nextText)"); + Expression messageOut = parser.parseTerm(stream, model); + stream.addLine("nextText"); + Expression nextStateOut = parser.parseTerm(stream, model); + textOut.getStateTransition().setCurStateExpression(curStateOut); + textOut.getStateTransition().setMessageExpression(messageOut); + textOut.getStateTransition().setNextStateExpression(nextStateOut); + nativeOutputEventChannel.addChannelMemberAsInput(textOut); + model.addChannel(nativeOutputEventChannel); + TypeInference typeInference = new TypeInference(new JavaSpecific()); + typeInference.infer(model); + + // Create simulator + Simulator simulator = new Simulator(model); + + // Initial state + SystemState initialState = simulator.init(); + Resource ioResource = initialState.getResource("sampleText"); + + // Connect the simulator and native code + NativeSender textSender = new NativeSender(simulator, nativeInputEventChannel, sampleText, ioResource) { // Native code => model + }; + INativeReceiver textReceiver = new INativeReceiver() { // Model to native code + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { // Receive a message from the model + Expression message = event.getMessage(); + System.out.println(message); + } + }; + simulator.addNativeReceiver(textReceiver, nativeOutputEventChannel); + + stream.addLine("input(\"HelloWorld\")"); + Expression sendMessage = parser.parseTerm(stream, model); + textSender.sendToModel(sendMessage); // Send a message to the model + + } catch (ExpectedRightBracket | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/SimplifiedDataFlowModelTest.java b/AlgebraicDataflowArchitectureModel/src/tests/SimplifiedDataFlowModelTest.java index acb5333..099c6a6 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/SimplifiedDataFlowModelTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/SimplifiedDataFlowModelTest.java @@ -14,10 +14,14 @@ public void test() { // Construct a data-flow architecture model. DataTransferModel model = new DataTransferModel(); - ResourcePath payment = new ResourcePath("payment", 0); // a resource to specify the payment resource - ResourcePath loyalty = new ResourcePath("loyalty", 0); // a resource to specify the loyalty resource - ResourcePath history = new ResourcePath("history", 0); // a resource to specify the payment history resource - ResourcePath total = new ResourcePath("total", 0); // a resource to specify the total payment resource + ResourcePath payment = new ResourcePath("payment"); // a resource to specify the payment resource + ResourcePath points = new ResourcePath("points"); // a resource to specify the points resource + ResourcePath history = new ResourcePath("history"); // a resource to specify the payment history resource + ResourcePath total = new ResourcePath("total"); // a resource to specify the total payment resource + model.addResourcePath(payment); + model.addResourcePath(points); + model.addResourcePath(history); + model.addResourcePath(total); // === cin === // @@ -31,11 +35,11 @@ // === c1 === // // payment(p1, update1(y)) == y - // loyalty(l, update1(y)) == floor(y * 0.05) + // points(l, update1(y)) == floor(y * 0.05) // DataTransferChannel c1 = new DataTransferChannel("c1"); ChannelMember c1_payment = new ChannelMember(payment); - ChannelMember c1_loyalty = new ChannelMember(loyalty); + ChannelMember c1_loyalty = new ChannelMember(points); c1.addChannelMemberAsInput(c1_payment); c1.addChannelMemberAsOutput(c1_loyalty); assertEquals(c1.getChannelMembers().size(), 2); @@ -71,22 +75,23 @@ assertEquals(c3.getOutputChannelMembers().size(), 1); // Construct a data-flow architecture model. - model.addIOChannel(cin); + model.addInputChannel(cin); model.addChannel(c1); model.addChannel(c2); model.addChannel(c3); // Check the model. assertEquals(4, model.getResourcePaths().size()); - assertEquals(1, model.getIOChannels().size()); + assertEquals(1, model.getInputChannels().size()); assertEquals(3, model.getChannels().size()); // Extract the resource dependency graph. DataFlowGraph resourceDependencyGraph = model.getDataFlowGraph(); // Check the graph. - assertEquals(4, resourceDependencyGraph.getNodes().size()); - assertEquals(3, resourceDependencyGraph.getEdges().size()); + assertEquals(4, resourceDependencyGraph.getResourceNodes().size()); + assertEquals(4, resourceDependencyGraph.getChannelNodes().size()); + assertEquals(6, resourceDependencyGraph.getEdges().size()); for (Edge e: resourceDependencyGraph.getEdges()) { System.out.println(e.getSource() + "-(" + e + ")->" + e.getDestination()); } diff --git a/AlgebraicDataflowArchitectureModel/src/tests/SimulatorTest.java b/AlgebraicDataflowArchitectureModel/src/tests/SimulatorTest.java new file mode 100644 index 0000000..a6c2817 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/tests/SimulatorTest.java @@ -0,0 +1,227 @@ +package tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import models.algebra.Expression; +import models.algebra.InvalidMessage; +import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.UnificationFailed; +import models.algebra.ValueUndefined; +import models.algebra.Variable; +import models.algebra.Constant; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ResourcePath; +import models.dataFlowModel.DataTransferChannel; +import models.dataFlowModel.DataTransferModel; +import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; +import parser.Parser; +import parser.Parser.TokenStream; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; +import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.WrongJsonExpression; +import simulator.Event; +import simulator.Resource; +import simulator.Simulator; +import simulator.SystemState; +import simulator.ResourceIdentifier; +import simulator.states.MapResourceState; + +public class SimulatorTest { + @Test + public void test() { + try { + TokenStream stream = new Parser.TokenStream(); + Parser parser = new Parser(stream); + + // Construct a data transfer architecture model. + DataTransferModel model = new DataTransferModel(); + + ResourcePath customers = new ResourcePath("customers"); // "customers" + ResourcePath customer = new ResourcePath(customers, + new Variable("uid", DataConstraintModel.typeString)); // "customers.{uid}" + ResourcePath customer_off = new ResourcePath(customer, "off"); // "customers.{uid}.off" + ResourcePath customer_add = new ResourcePath(customer, "add"); // "customers.{uid}.add" + ResourcePath companies = new ResourcePath("companies"); // "companies" + ResourcePath company = new ResourcePath(companies, + new Variable("cid", DataConstraintModel.typeString)); // "companies.{cid}" + ResourcePath company_add = new ResourcePath(company, "add"); // "companies.{cid}.add" + ResourcePath company2 = new ResourcePath(companies, + new Variable("cid2", DataConstraintModel.typeString)); // "companies.{cid2}" + ResourcePath company2_add = new ResourcePath(company2, "add"); // "companies.{cid2}.add" + ResourcePath companyA = new ResourcePath(companies, + new Constant("A", DataConstraintModel.typeString)); // "companies.A" + ResourcePath companyA_add = new ResourcePath(companyA, "add"); // "companies.{cid2}.add" + model.addResourcePath(customer_off); + model.addResourcePath(customer_add); + model.addResourcePath(company_add); + model.addResourcePath(company2_add); + model.addResourcePath(customers); + model.addResourcePath(companies); + + // For channel CIO_AddCustomer + DataTransferChannel cio_addCustomer = new DataTransferChannel("CIO_AddCustomer"); // add a customer + ChannelMember customers1 = new ChannelMember(customers); + stream.addLine("db:Map"); + Expression curStateExp0 = parser.parseTerm(stream, model); + customers1.getStateTransition().setCurStateExpression(curStateExp0); + stream.addLine("addCustomer(uid:Str, off:Str)"); + Expression messageExp0 = parser.parseTerm(stream, model); + customers1.getStateTransition().setMessageExpression(messageExp0); + stream.addLine("insert(db, uid, {\"off\": off})"); + Expression nextStateExp0 = parser.parseTerm(stream, model); + customers1.getStateTransition().setNextStateExpression(nextStateExp0); + cio_addCustomer.addChannelMemberAsOutput(customers1); + + // For channel CIO_AddCompany + DataTransferChannel cio_addCompany = new DataTransferChannel("CIO_AddCompany"); // add a company + ChannelMember companies1 = new ChannelMember(companies); + stream.addLine("db:Map"); + Expression curStateExp1 = parser.parseTerm(stream, model); + companies1.getStateTransition().setCurStateExpression(curStateExp1); + stream.addLine("addCampany(cid:Str, add:Str)"); + Expression messageExp1 = parser.parseTerm(stream, model); + companies1.getStateTransition().setMessageExpression(messageExp1); + stream.addLine("insert(db, cid, {\"add\": add})"); + Expression nextStateExp1 = parser.parseTerm(stream, model); + companies1.getStateTransition().setNextStateExpression(nextStateExp1); + cio_addCompany.addChannelMemberAsOutput(companies1); + + // For channel CIO_SetCustomerOff + DataTransferChannel cio_setCustomerOff = new DataTransferChannel("CIO_SetCustomerOff", new Variable("uid")); // set customer's office + ChannelMember customer_off_1 = new ChannelMember(customer_off); + stream.addLine("cid:Str"); + Expression curStateExp2 = parser.parseTerm(stream, model); + customer_off_1.getStateTransition().setCurStateExpression(curStateExp2); + stream.addLine("setOff(cid2:Str)"); + Expression messageExp2 = parser.parseTerm(stream, model); + customer_off_1.getStateTransition().setMessageExpression(messageExp2); + stream.addLine("cid2"); + Expression nextStateExp2 = parser.parseTerm(stream, model); + customer_off_1.getStateTransition().setNextStateExpression(nextStateExp2); + cio_setCustomerOff.addChannelMemberAsOutput(customer_off_1); + + // For channel CIO_SetCompanyAdd + DataTransferChannel cio_setCompanyAdd = new DataTransferChannel("CIO_SetCompanyAdd", new Variable("cid")); // set companie's address + ChannelMember company_add_1 = new ChannelMember(company_add); + stream.addLine("a1:Str"); + Expression curStateExp3 = parser.parseTerm(stream, model); + company_add_1.getStateTransition().setCurStateExpression(curStateExp3); + stream.addLine("setAdd(a2:Str)"); + Expression messageExp3 = parser.parseTerm(stream, model); + company_add_1.getStateTransition().setMessageExpression(messageExp3); + stream.addLine("a2"); + Expression nextStateExp3 = parser.parseTerm(stream, model); + company_add_1.getStateTransition().setNextStateExpression(nextStateExp3); + cio_setCompanyAdd.addChannelMemberAsOutput(company_add_1); + + // For channel C + DataTransferChannel c = new DataTransferChannel("C", new Variable("uid")); // update customer's address + ChannelMember customer_off_2 = new ChannelMember(customer_off); + stream.addLine("cid:Str"); + Expression curStateExp4 = parser.parseTerm(stream, model); + customer_off_2.getStateTransition().setCurStateExpression(curStateExp4); + stream.addLine("sync(cid2:Str, add2:Str)"); + Expression messageExp4 = parser.parseTerm(stream, model); + customer_off_2.getStateTransition().setMessageExpression(messageExp4); + stream.addLine("cid2"); + Expression nextStateExp4 = parser.parseTerm(stream, model); + customer_off_2.getStateTransition().setNextStateExpression(nextStateExp4); + c.addChannelMemberAsInput(customer_off_2); + + ChannelMember company_add_2 = new ChannelMember(company2_add); + stream.addLine("a1:Str"); + Expression curStateExp5 = parser.parseTerm(stream, model); + company_add_2.getStateTransition().setCurStateExpression(curStateExp5); + stream.addLine("sync(cid2:Str, add2:Str)"); + Expression messageExp5 = parser.parseTerm(stream, model); + company_add_2.getStateTransition().setMessageExpression(messageExp5); + stream.addLine("add2"); + Expression nextStateExp5 = parser.parseTerm(stream, model); + company_add_2.getStateTransition().setNextStateExpression(nextStateExp5); + c.addChannelMemberAsInput(company_add_2); + + ChannelMember customer_add_2 = new ChannelMember(customer_add); + stream.addLine("a3:Str"); + Expression curStateExp6 = parser.parseTerm(stream, model); + customer_add_2.getStateTransition().setCurStateExpression(curStateExp6); + stream.addLine("sync(cid2:Str, add2:Str)"); + Expression messageExp6 = parser.parseTerm(stream, model); + customer_add_2.getStateTransition().setMessageExpression(messageExp6); + stream.addLine("add2"); + Expression nextStateExp6 = parser.parseTerm(stream, model); + customer_add_2.getStateTransition().setNextStateExpression(nextStateExp6); + c.addChannelMemberAsOutput(customer_add_2); + + model.addInputChannel(cio_addCustomer); + model.addInputChannel(cio_addCompany); + model.addInputChannel(cio_setCustomerOff); + model.addInputChannel(cio_setCompanyAdd); + model.addChannel(c); + + Simulator simulator = new Simulator(model); + + // Initial state + SystemState initialState = simulator.init(); + + assertEquals(2, initialState.getRootResources().size()); + for (Resource rootRes: initialState.getRootResources()) { + assertTrue(rootRes.getState() instanceof MapResourceState); + assertEquals(0, rootRes.getChildren().size()); + assertEquals(0, ((MapResourceState) rootRes.getState()).getChildStates().size()); + } + System.out.println("companies:" + initialState.getResource(ResourceIdentifier.createFrom(companies)).getState().getValue()); + System.out.println("customers:" + initialState.getResource(ResourceIdentifier.createFrom(customers)).getState().getValue()); + + // Next state (companies.addCompany("A", "Osaka")) + stream.addLine("addCompany(\"A\", \"Osaka\")"); + Expression messageAddComp = parser.parseTerm(stream, model); + Event addCompany = new Event(cio_addCompany, messageAddComp, companies, initialState.getResource(ResourceIdentifier.createFrom(companies))); + simulator.transition(addCompany); + SystemState nextState = simulator.getCurState(); + + assertEquals(2, nextState.getRootResources().size()); + Resource companiesRes = nextState.getResource(ResourceIdentifier.createFrom(companies)); + assertTrue(companiesRes.getState() instanceof MapResourceState); + assertEquals(1, companiesRes.getChildren().size()); + assertEquals(1, ((MapResourceState) companiesRes.getState()).getChildStates().size()); + System.out.println("companies:" + nextState.getResource(ResourceIdentifier.createFrom(companies)).getState().getValue()); + System.out.println("customers:" + nextState.getResource(ResourceIdentifier.createFrom(customers)).getState().getValue()); + + // After the next state (customers.addCustomer("1", "A")) + stream.addLine("addCustomer(\"1\", \"A\")"); + Expression messageAddCust = parser.parseTerm(stream, model); + Event addCustomer = new Event(cio_addCustomer, messageAddCust, customers, nextState.getResource(ResourceIdentifier.createFrom(customers))); + simulator.transition(addCustomer); + SystemState nextNextState = simulator.getCurState(); + + assertEquals(2, nextState.getRootResources().size()); + Resource customersRes = nextNextState.getResource(ResourceIdentifier.createFrom(customers)); + assertTrue(customersRes.getState() instanceof MapResourceState); + assertEquals(1, customersRes.getChildren().size()); + assertEquals(1, ((MapResourceState) customersRes.getState()).getChildStates().size()); + System.out.println("companies:" + nextNextState.getResource(ResourceIdentifier.createFrom(companies)).getState().getValue()); + System.out.println("customers:" + nextNextState.getResource(ResourceIdentifier.createFrom(customers)).getState().getValue()); + + // After the next next state (companies.A.setAdd("Tokyo")) + stream.addLine("setAdd(\"Tokyo\")"); + Expression messageSetAdd = parser.parseTerm(stream, model); + Event setAdd = new Event(cio_setCompanyAdd, messageSetAdd, company_add, nextNextState.getResource(ResourceIdentifier.createFrom(companyA_add))); + simulator.transition(setAdd); + SystemState nextNextNextState = simulator.getCurState(); + Resource customersRes2 = nextNextNextState.getResource(ResourceIdentifier.createFrom(customers)); + assertTrue(customersRes2.getState() instanceof MapResourceState); + assertEquals(1, customersRes2.getChildren().size()); + assertEquals(1, ((MapResourceState) customersRes2.getState()).getChildStates().size()); + System.out.println("companies:" + nextNextNextState.getResource(ResourceIdentifier.createFrom(companies)).getState().getValue()); + System.out.println("customers:" + nextNextNextState.getResource(ResourceIdentifier.createFrom(customers)).getState().getValue()); + + } catch (ExpectedRightBracket | WrongJsonExpression | ExpectedColon | ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed | ValueUndefined | ExpectedDoubleQuotation e) { + e.printStackTrace(); + } + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/UpdateCodeGenerationTest.java b/AlgebraicDataflowArchitectureModel/src/tests/UpdateCodeGenerationTest.java index 69a5b1f..bc1db89 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/UpdateCodeGenerationTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/UpdateCodeGenerationTest.java @@ -25,92 +25,110 @@ Symbol sum = new Symbol("sum", 1, Symbol.Type.PREFIX, "stream().mapToInt(x->x).sum", Symbol.Type.METHOD); // resources - ResourcePath payment = new ResourcePath("payment", DataConstraintModel.typeInt, 0); // a resource to specify the payment resource - ResourcePath loyalty = new ResourcePath("loyalty", DataConstraintModel.typeInt, 0); // a resource to specify the loyalty resource - ResourcePath history = new ResourcePath("history", DataConstraintModel.typeList, 0);// a resource to specify the payment history resource - ResourcePath total = new ResourcePath("total", DataConstraintModel.typeInt, 0); // a resource to specify the total payment resource + ResourcePath payment = new ResourcePath("payment"); // a resource to specify the payment resource + ResourcePath points = new ResourcePath("points"); // a resource to specify the loyalty resource + ResourcePath history = new ResourcePath("history"); // a resource to specify the payment history resource + ResourcePath total = new ResourcePath("total"); // a resource to specify the total payment resource + payment.setResourceStateType(DataConstraintModel.typeInt); + points.setResourceStateType(DataConstraintModel.typeInt); + history.setResourceStateType(DataConstraintModel.typeInt); + total.setResourceStateType(DataConstraintModel.typeInt); // fields in the Java program final Field fPayment = new Field("payment", DataConstraintModel.typeInt); - final Field fLoyalty = new Field("loyalty", DataConstraintModel.typeInt); + final Field fPoints = new Field("points", DataConstraintModel.typeInt); final Field fHistory = new Field("history", DataConstraintModel.typeList); final Field fTotal = new Field("total", DataConstraintModel.typeInt); // parameters in the Java program final Parameter pPayment = new Parameter("payment", DataConstraintModel.typeInt); - final Parameter pLoyalty = new Parameter("loyalty", DataConstraintModel.typeInt); + final Parameter pPoints = new Parameter("points", DataConstraintModel.typeInt); final Parameter pHistory = new Parameter("history", DataConstraintModel.typeList); final Parameter pTotal = new Parameter("total", DataConstraintModel.typeInt); IResourceStateAccessor pushAccessor = new IResourceStateAccessor() { @Override - public Expression getCurrentStateAccessorFor(ResourcePath target, ResourcePath from) { - if (target.equals(from)) { - if (target.equals(payment)) return fPayment; - if (target.equals(loyalty)) return fLoyalty; - if (target.equals(history)) return fHistory; - if (target.equals(total)) return fTotal; + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes = target.getResource(); + ResourcePath fromRes = from.getResource(); + if (targetRes.equals(fromRes)) { + if (targetRes.equals(payment)) return fPayment; + if (targetRes.equals(points)) return fPoints; + if (targetRes.equals(history)) return fHistory; + if (targetRes.equals(total)) return fTotal; } return null; } @Override - public Expression getNextStateAccessorFor(ResourcePath target, ResourcePath from) { - if (target.equals(payment)) return pPayment; - if (target.equals(loyalty)) return pLoyalty; - if (target.equals(history)) return pHistory; - if (target.equals(total)) return pTotal; + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes = target.getResource(); + if (targetRes.equals(payment)) return pPayment; + if (targetRes.equals(points)) return pPoints; + if (targetRes.equals(history)) return pHistory; + if (targetRes.equals(total)) return pTotal; + return null; + } + @Override + public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { return null; } }; // methods in the Java program final Symbol paymentGetter = new Symbol("getPayment", 1, Symbol.Type.METHOD); - final Symbol loyltyGetter = new Symbol("getLoyalty", 1, Symbol.Type.METHOD); + final Symbol pointsGetter = new Symbol("getPoints", 1, Symbol.Type.METHOD); final Symbol historyGetter = new Symbol("getHistory", 1, Symbol.Type.METHOD); final Symbol totalGetter = new Symbol("getTotal", 1, Symbol.Type.METHOD); IResourceStateAccessor pullAccessor = new IResourceStateAccessor() { @Override - public Expression getCurrentStateAccessorFor(ResourcePath target, ResourcePath from) { - if (target.equals(from)) { - if (target.equals(payment)) return fPayment; - if (target.equals(loyalty)) return fLoyalty; - if (target.equals(history)) return fHistory; - if (target.equals(total)) return fTotal; + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes = target.getResource(); + ResourcePath fromRes = from.getResource(); + if (targetRes.equals(fromRes)) { + if (targetRes.equals(payment)) return fPayment; + if (targetRes.equals(points)) return fPoints; + if (targetRes.equals(history)) return fHistory; + if (targetRes.equals(total)) return fTotal; } return null; } @Override - public Expression getNextStateAccessorFor(ResourcePath target, ResourcePath from) { - if (target.equals(payment)) { + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + ResourcePath targetRes = target.getResource(); + if (targetRes.equals(payment)) { Term getter = new Term(paymentGetter); getter.addChild(fPayment); return getter; } - if (target.equals(loyalty)) { - Term getter = new Term(loyltyGetter); - getter.addChild(fLoyalty); + if (targetRes.equals(points)) { + Term getter = new Term(pointsGetter); + getter.addChild(fPoints); return getter; } - if (target.equals(history)) { + if (targetRes.equals(history)) { Term getter = new Term(historyGetter); getter.addChild(fHistory); return getter; } - if (target.equals(total)) { + if (targetRes.equals(total)) { Term getter = new Term(totalGetter); getter.addChild(fTotal); return getter; } return null; + } + @Override + public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { + return null; } }; // === c1 === // - // payment(p1, update1(y)) == y - // loyalty(l, update1(y)) == floor(y * 0.05) + // payment(p1, update1(y)) = y + // points(l, update1(y)) = floor(y * 0.05) // DataTransferChannel c1 = new DataTransferChannel("c1"); ChannelMember c1_payment = new ChannelMember(payment); - ChannelMember c1_loyalty = new ChannelMember(loyalty); + ChannelMember c1_loyalty = new ChannelMember(points); c1.addChannelMemberAsInput(c1_payment); c1.addChannelMemberAsOutput(c1_loyalty); @@ -121,11 +139,11 @@ Symbol update1 = new Symbol("update1", 1); Term c1_message = new Term(update1); // update1(y) c1_message.addChild(y); - Term rawLoyality = new Term(DataConstraintModel.mul); // y*0.05 - rawLoyality.addChild(y); - rawLoyality.addChild(c_0_05); - Term nextLoyality = new Term(floor); // floor(y*0.05) - nextLoyality.addChild(rawLoyality); + Term rawPoints = new Term(DataConstraintModel.mul); // y*0.05 + rawPoints.addChild(y); + rawPoints.addChild(c_0_05); + Term nextPoints = new Term(floor); // floor(y*0.05) + nextPoints.addChild(rawPoints); StateTransition c1_payment_transition = new StateTransition(); c1_payment_transition.setCurStateExpression(p1); @@ -133,11 +151,11 @@ c1_payment_transition.setNextStateExpression(y); c1_payment.setStateTransition(c1_payment_transition); - StateTransition c1_loyalty_transition = new StateTransition(); - c1_loyalty_transition.setCurStateExpression(l); - c1_loyalty_transition.setMessageExpression(c1_message); - c1_loyalty_transition.setNextStateExpression(nextLoyality); - c1_loyalty.setStateTransition(c1_loyalty_transition); + StateTransition c1_points_transition = new StateTransition(); + c1_points_transition.setCurStateExpression(l); + c1_points_transition.setMessageExpression(c1_message); + c1_points_transition.setNextStateExpression(nextPoints); + c1_loyalty.setStateTransition(c1_points_transition); System.out.println(c1); @@ -147,21 +165,21 @@ System.out.println(c1.deriveUpdateExpressionOf(c1_loyalty).toImplementation(sideEffects)); System.out.println("-- PUSH --"); - Expression loyaltyPushUpdate = c1.deriveUpdateExpressionOf(c1_loyalty, pushAccessor); + Expression loyaltyPushUpdate = c1.deriveUpdateExpressionOf(c1_loyalty, pushAccessor).getKey(); Parameter param = null; for (Parameter p: loyaltyPushUpdate.getSubTerms(Parameter.class).values()) { - if (p.equals(pPayment) || p.equals(pLoyalty) || p.equals(pHistory) || p.equals(pTotal)) { + if (p.equals(pPayment) || p.equals(pPoints) || p.equals(pHistory) || p.equals(pTotal)) { param = p; break; } } System.out.println("void update(" + param.getType().getImplementationTypeName() + " " + param.toImplementation(sideEffects) + ") {"); - System.out.println("\t" + fLoyalty + " = " + loyaltyPushUpdate.toImplementation(sideEffects) + ";"); + System.out.println("\t" + fPoints + " = " + loyaltyPushUpdate.toImplementation(sideEffects) + ";"); System.out.println("}"); System.out.println("-- PULL --"); - System.out.println(loyalty.getResourceStateType().getImplementationTypeName() + " " + loyltyGetter.toImplementation() + "() {"); - System.out.println("\t return " + c1.deriveUpdateExpressionOf(c1_loyalty, pullAccessor).toImplementation(sideEffects) + ";"); + System.out.println(points.getResourceStateType().getImplementationTypeName() + " " + pointsGetter.toImplementation() + "() {"); + System.out.println("\t return " + c1.deriveUpdateExpressionOf(c1_loyalty, pullAccessor).getKey().toImplementation(sideEffects) + ";"); System.out.println("}"); } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed | ValueUndefined e) { @@ -172,8 +190,8 @@ // === c2 === // - // payment(p1, update2(z)) == z - // history(h, update2(z)) == cons(z, h) + // payment(p1, update2(z)) = z + // history(h, update2(z)) = cons(z, h) // DataTransferChannel c2 = new DataTransferChannel("c2"); ChannelMember c2_payment = new ChannelMember(payment); @@ -210,10 +228,10 @@ System.out.println(c2.deriveUpdateExpressionOf(c2_history).toImplementation(sideEffects)); System.out.println("-- PUSH --"); - Expression historyPushUpdate = c2.deriveUpdateExpressionOf(c2_history, pushAccessor); + Expression historyPushUpdate = c2.deriveUpdateExpressionOf(c2_history, pushAccessor).getKey(); Parameter param = null; for (Parameter p: historyPushUpdate.getSubTerms(Parameter.class).values()) { - if (p.equals(pPayment) || p.equals(pLoyalty) || p.equals(pHistory) || p.equals(pTotal)) { + if (p.equals(pPayment) || p.equals(pPoints) || p.equals(pHistory) || p.equals(pTotal)) { param = p; break; } @@ -224,7 +242,7 @@ System.out.println("-- PULL --"); System.out.println(history.getResourceStateType().getImplementationTypeName() + " " + historyGetter.toImplementation() + "() {"); - System.out.println("\t return " + c2.deriveUpdateExpressionOf(c2_history, pullAccessor).toImplementation(sideEffects) + ";"); + System.out.println("\t return " + c2.deriveUpdateExpressionOf(c2_history, pullAccessor).getKey().toImplementation(sideEffects) + ";"); System.out.println("}"); } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed | ValueUndefined e) { @@ -273,10 +291,10 @@ System.out.println(c3.deriveUpdateExpressionOf(c3_total).toImplementation(sideEffects)); System.out.println("-- PUSH --"); - Expression totalPushUpdate = c3.deriveUpdateExpressionOf(c3_total, pushAccessor); + Expression totalPushUpdate = c3.deriveUpdateExpressionOf(c3_total, pushAccessor).getKey(); Parameter param = null; for (Parameter p: totalPushUpdate.getSubTerms(Parameter.class).values()) { - if (p.equals(pPayment) || p.equals(pLoyalty) || p.equals(pHistory) || p.equals(pTotal)) { + if (p.equals(pPayment) || p.equals(pPoints) || p.equals(pHistory) || p.equals(pTotal)) { param = p; break; } @@ -287,7 +305,7 @@ System.out.println("-- PULL --"); System.out.println(total.getResourceStateType().getImplementationTypeName() + " " + totalGetter.toImplementation() + "() {"); - System.out.println("\t return " + c3.deriveUpdateExpressionOf(c3_total, pullAccessor).toImplementation(sideEffects) + ";"); + System.out.println("\t return " + c3.deriveUpdateExpressionOf(c3_total, pullAccessor).getKey().toImplementation(sideEffects) + ";"); System.out.println("}"); } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed | ValueUndefined e) { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java b/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java index 5f51af7..a7d7d6a 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java @@ -1,65 +1,49 @@ package tests; +import static org.junit.Assert.*; + import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; +import org.junit.Test; + import algorithms.*; import models.dataFlowModel.DataTransferModel; import parser.Parser; import parser.exceptions.ExpectedAssignment; import parser.exceptions.ExpectedChannel; import parser.exceptions.ExpectedChannelName; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; import parser.exceptions.ExpectedEquals; -import parser.exceptions.ExpectedInOrOutOrRefKeyword; +import parser.exceptions.ExpectedInOrOutOrRefOrSubKeyword; import parser.exceptions.ExpectedLeftCurlyBracket; import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; +import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; public class UpdateConflictCheckTest { - public static void main(String[] args) { + + @Test + public void test() { File file = new File("models/POS2.model"); try { Parser parser = new Parser(new BufferedReader(new FileReader(file))); + DataTransferModel model; try { - DataTransferModel model = parser.doParse(); - System.out.println(Validation.checkUpdateConflict(model)); - } catch (ExpectedRightBracket e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (ExpectedChannel e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (ExpectedChannelName e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (ExpectedLeftCurlyBracket e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (ExpectedInOrOutOrRefKeyword e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (ExpectedStateTransition e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (ExpectedEquals e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (ExpectedRHSExpression e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (WrongLHSExpression e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (WrongRHSExpression e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (ExpectedAssignment e) { - // TODO Auto-generated catch block + model = parser.doParse(); + assertTrue(Validation.checkUpdateConflict(model)); + } catch (ExpectedRightBracket | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket + | ExpectedRightCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals + | ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedAssignment + | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { e.printStackTrace(); } } catch (FileNotFoundException e) { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/parser/ParseTest.java b/AlgebraicDataflowArchitectureModel/src/tests/parser/ParseTest.java index a1ea0a3..8c5eae4 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/parser/ParseTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/parser/ParseTest.java @@ -17,13 +17,18 @@ import parser.exceptions.ExpectedAssignment; import parser.exceptions.ExpectedChannel; import parser.exceptions.ExpectedChannelName; +import parser.exceptions.ExpectedColon; +import parser.exceptions.ExpectedDoubleQuotation; import parser.exceptions.ExpectedEquals; -import parser.exceptions.ExpectedInOrOutOrRefKeyword; +import parser.exceptions.ExpectedInOrOutOrRefOrSubKeyword; import parser.exceptions.ExpectedLeftCurlyBracket; import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; +import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; public class ParseTest { @@ -40,7 +45,7 @@ for (Channel c: model.getChannels()) { for (ChannelMember out: ((DataTransferChannel) c).getOutputChannelMembers()) { String[] sideEffects = new String[] {""}; - System.out.println("next" + out.getResource().getResourceName() + " = " + ((DataTransferChannel) c).deriveUpdateExpressionOf(out).toImplementation(sideEffects)); + System.out.println("next" + out.getResource().getLeafResourceName() + " = " + ((DataTransferChannel) c).deriveUpdateExpressionOf(out).toImplementation(sideEffects)); } } @@ -50,11 +55,11 @@ for (Edge e: resourceDependencyGraph.getEdges()) { System.out.println(e.getSource() + "-(" + e + ")->" + e.getDestination()); } - } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword + } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedRightBracket | ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage - | UnificationFailed | ValueUndefined | ExpectedAssignment e) { + | UnificationFailed | ValueUndefined | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) { e.printStackTrace(); } } catch (FileNotFoundException e) {