From 085428bd9a513dd75df15b1886109968c44ab62f Mon Sep 17 00:00:00 2001 From: Chrissi <christopher@hbsc-werner.de> Date: Wed, 7 Aug 2019 14:45:13 +0200 Subject: [PATCH] optimize ModelJoin creation and remove small errors --- lib/modeljoin.jar | Bin 228674 -> 280086 bytes .../util/query/ModelJoinCreator.java | 89 ++- .../org/rosi_project/example/ExampleAml.scala | 38 +- .../model_management/sum/query/AQuery.scala | 102 --- .../sum/query/ModelJoinContainer.scala | 39 +- .../model_management/sum/query/Query.scala | 646 ++--------------- ...ewCompartment.scala => QueryFactory.scala} | 32 +- .../sum/query/RsumQuery.scala | 679 ++++++++++++++++++ src/main/scala/query/AMLLanguageQuery.scala | 22 +- .../scala/query/EclipseLibraryQuery.scala | 60 +- src/main/scala/query/IMDBdatabaseQuery.scala | 60 +- src/main/scala/query/LibraryQuery.scala | 16 +- 12 files changed, 969 insertions(+), 814 deletions(-) delete mode 100644 src/main/scala/org/rosi_project/model_management/sum/query/AQuery.scala rename src/main/scala/org/rosi_project/model_management/sum/query/{IQueryViewCompartment.scala => QueryFactory.scala} (75%) create mode 100644 src/main/scala/org/rosi_project/model_management/sum/query/RsumQuery.scala diff --git a/lib/modeljoin.jar b/lib/modeljoin.jar index 7dd9eed4acaada106ddb92d3b771163185721b73..f8f8f1c984bdb976963788009f4efb26734c4e40 100644 GIT binary patch delta 66878 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⁣<0j*tA0ya9XVOW_O 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 delta 15260 zcmbQ%BY5Z+FK>W1Gm8iV2L}hkqEeQLym8DNnJkkNceqc#aDs__`ua!ATGQ<xF|%%b zeSn=gJ%?rUI*vRDLtem<4WxK_o*bk5^aD?rO*Y>X%j5<LO?C|PnO^XWnQ!wFC2z3E z^ml$t?vn)^SU210?cxNfnSPL!5hTJs{oQkB(amud8SEh8$qGI`(_g<}7TT=t@C~eW zvw{yN*dmarlk-COHn#=sU<Rq(>=@P!)--*CIHUXIgf$$S<>GqTnGa>LOfD=Ap8oG0 zv+(p+Z<(bx>!%qpgM_CioMLjHuE5O51CkV(Tzi+j{&ul&sKo!dF*j6nrY~E{(X@nh zt8c^CuIWXYD;1VLRMKn}Vcqu9@UGd--rdq|b|+qR=<oaSM*hLmh5Sa!YfruS@ud0x z1pU6p-{;<4mML^>rqql=tDCmZt?&P=-G2Y)xo`dZ>;H)!$X=1z!4Xq>XVXKgd8MnL zS#fWAA|0CU7nWC9?_H)Tqh~QKcgLn@UjDcCy^QY5of5k_$}~1P=v36gxXJIX1o_U} zdD=>DZFUEz&tLNwh0CLgUwxCA9pNtK@iQgsRN}@1KmR=InIaP|^;q=s=XD<ESMFA| zRNC;|>+ZL;tLAL8$=;@PJm)s&72C$WKUqKbRbDrcc6z)h`Sw?@R<peNkG|V=Y8!tj zRl44?p1LjY``WIF+im8TOk!P~GrR8YRHp6G)B5v`x}IsRS)TDkWoEbTsy{cJ562#O z7x2(o`pNRwVX1z*a?0ljm@Z)zn>X*SNY#bq$>P6OiXGRz{mGxp!r9;W)5FY0*~-(? z#9v>Hj56wUV0yVH*hu^Gvh0sGB6an<Bad56*w*c#+w-*H-yi#mTVD?!p2(k<!#dqJ zXxhG#*;P(lfp5|;*{Tc3O3m|gQdq3qr)wj1Wg?GTd&!awQ~lcP^8>SYd`pS&bYEYu zd~=64Tg&AY<{v{8_P;E<urX0h(juppv&xU{uD);BtzY+ZW^Z`idO3mP%Q|Vv;@INO zdflZ3BKpNE;})vfUwLwDNASuCvG>k}-cOq5waM+^l-(DtqoR)en&SD?`i}9oM-un0 zd|+Gp{N(M+AI0u1vwp?r&zd$bpgv^gm3J&=tk34TsjV#ew0Kvf;-|M<ucHm$ZYs>2 z#@okpeu+WXWvOE?vhrfD8upbl{nM%wZoRf*)s`s*^(w8KEtWrwZ7jZP<zVI4@J{pL z2iuF!HfKqwUCoR>XztxDekQ77mhk6g=I6Js$+8yKj5#LC`=0a5n$K1TK9q<UxH{}< z{&o05FW<_U3NH6Gf2>QL&ic!&Mb6`8Osx2gyIOqt`&iOmJbS#px951ugY}zzxUPS& zli$G~#U-S~=fAoBn6B*h#7`SnUtMCWUa%zi?X9x)u{$}ZXl(0wsaZVfpk2<v2;=V& zJohZuKi2Blys}B_bY%DDJ?{<Q*q!oV`qh%_9X>U<N@~@WsNJ5$r=r{!1vgsN)+RK( zo2gNI)qUbK?v6C6vp?o8D4(@{k(p$ySBJy$LYCWRYgAw6TbE7P6Is7&a^2xmT$wgb z{();2eXrhHTfTyA&LLwjrde+f$p!KAyg9o0%e&sTh_n93_PT2sR(($m->5&kx`X-V zVSd92wx0yp<yY*u;bMQ3ZBa>2*R&(0pEh>Hoza+lGr@k|aqd%x_ZjfpJbIy=b;Qv9 zqf+nJ0$taQo5P(&qO13?^+xK?tN+W$9+hl5^&x|XoRrv;6Z;u?w=hM@HWpdj@wh+H z>_GCV>|0+s+`Cz-3Pkm{KC1HFQN{c{^w)j;MW+^asvQUvDw-s;^NoLnZ4*21hAETo ztBOw(NvL0N-J_IA*<#(J#dU7}Zom6VW@xEz+L<rVulv02__sG)eotR~H+^*R>7D#~ z0db4f?Ju`C8OJZ29_+lC(R8ux#iwph*{9By4=#H*QF{Ia?)j6n=O@~~3!Z1Uy!-9G zB3)sL+#O|1!WRB|Z<kN?oa8z|{bksZEpH#`^JJZR&AmgS%GOKeQOeij^#?NyPrVcE zGW@psgR-9P_9frDmwowWe#v{Sii@@UG>y+3*Sq{)KGMod30-4;d9(J6)2lr4*Dbgc zwM~C^fw5v<i^rk!tU9X>ODi&kBwS`s<9})C@sByco1LRsI_S10D+9xIeg+0a4FW27 z6X*L+-mrsh+IwcP$+G#{!h4NRKMh?Xy4{o|!u#Aj%i?F7R!@%3mttH$xh!A1e$Sk$ zy6tK2xBY)*DCqU_#plIgr=C}4e|*1U`K^Sa+1%Oo3$NZ=@*`ew^@6pokDC<2!#C`z zu4h*|t#CQBqNK92j%|7Y^Zj+fOilL%PFKe-inN{j<FxYQ$U{~QA=f1Ry&7&O=Kf{> z{cmcF{DF$6DUA<G3`DmG@ilMc(9>CL<-}UQmvQw;lcxzMrC1DV1$Kr-3urMdIe6)9 z%W56r2*ZeJo_&5#*4_-C`TXE<sl>Ob?;Mt>q^oiE{V3rmuE-7f&^paQfsZ@rtejT< zBs;MnS><Cr6)HXQH8I@p%WfS|pP5zBo)#UT`(gI#&zmo;FP?eqfZ7t4nvxYp+}meO zdL3%^p#DqmXQqHuwi6Fm`R{M6ai5r$!Pnrmrg)9e<qc^Xll&iE4_?`umt`t>JY)ae zz^ExIrLCtDCRYn}<jBnG^)Os%c64p<BnJUjg;R%|`d14(OHN%@Ctj*(qWnE3YHu9l zx;0au@pj+ZFl~b7zT>?gLL_?aZmE1dz1r@b#O9lG{<0U>PjbK2qJ8|3(Tm$>rp~{A z?pgP#HwJEx_8keyOYsT4EwJ#_8^7N+kA>cS@i$YclwIz-B!<&^RVuUn>hC=oW<0Ay zCnh~Ux~MMqLgnJ7tHp|S6TEKSjWE3QV$q{b`ur;{OW(N@x%*w((pklwm*hF$9LuSF z@#5xD-lKDiEH&etAFfTV@6GjbE&I4E*y>B{4BcJkiAFbm8dRP8#<KmU=ad!K6K~xA zo+5iZD=VPnXcKSg)E^Vo{H)$yo4VzG)#BDeD$%OTm2#yLFLEw=uDR{J+ov46i*xMv z7;;n=1!wI0CsP~UxnE+{--GQ<5<ZP-lcqN13CQl#e|tqt$$<a%RE<Z0Z5!&RtGr=I z?dIZj4tc3o*IMwh&wqWI#`lA(UmmV#7GA^do8el@V4eQtmUY%?kHw`YTa+yR^U9PR z{~q%2y6vYkGdgPvPi=ZNOL_InH)f&Mc6(+`%JyBgM(6e+t648fZ}ybDn(y{L_1mY9 zwl}B!{n07lU45myIbh!Muk|9gyCc~R`|B&WOZgY4v7L`Ow;}TS_RVG@`I=n2?zaXj zvYZJI?9;Y-=>B%AT9?qLuy|X4mYUk_?#UhL>c1{#EwT7HQFiX)yT2WuyR1lm(b2zm zn&kb&jU{hi-u?b_`j$z@#GhLH$^Ub#ROsLN9h>~CqO<2J$L{`^uU}-ny6$5`p2AZ$ zCIOx4^>df!&gwn>tz)%$#x}k^`|Hyyoi0wWu@`i^w66c5*^$Hs^HN!kuNzu!9{Fwg z;;4(Vs$rPhi!;5Jd#XY&H%9EQz5L<Dl0_x{ZF4v5j@Ej;cv8oH4Pi5hou+eG_AgJA ztGf{r-}ga(mGMGJfAJ5ysu%2C#(pTwzna%;emw)I7?HHR{(4dc3j;$fN;z^Zi)C|R zu`LTTh_SI;f*Hg>YP%iyz${t+HaxOeBvj<zJDo2nmvWprR2H>$%<yR_?A*a(pxB^u zI7z69QPgU3+9l8B)i2(0cK$x}Ep4j*r)B)VlH?YgQc1XSNqo&G^T=uU-@f!T>JFOv z_GJ6ZeYNj*-naa2ecJZ(^ZWLHxfaNli?pzuyX|N8^v1eE%jY+gtB!g1-gMqod9!}* z7Ndg&N6gktS^Qk)?p0m?&pfxiQe|^<e2RmXm)Krk9Dh~z?x`2<>Pvb~m$C{r?tAK3 zemmLHI-l25l=}pe>8$6L#}e*cX7yV(eVKByb=9iX9mRg1+pJlnsy<Ci?|J#REt_Xn z)%4VxtcBqV3~d+nW(#ZP))|!^+qPy;W>NB?dQGE(BLx}F`Oi)W`Bw96-d&|ta<Qp& z-m{d_{FyB!vuC~j_F~=KawDt2#f!Hzw%>muZ#VTjkMUHqn0{~5y>8bo?b+k39-|p; zw}DAL-lE{R;;L>BZ<aOFu7xITP5D=F&!D};{ncBwMNMl<p5J=eyO{5GNRB(RZ1sT+ zJntto+}%_^O+Eju_>CE6I)8oYastYKnLJ~DY?GUAvN^t(=V$B;k=fI;BBsj3?4A<2 z(?s(;Z;<+y|CW(gn-mUj-nk`e{$-6d)w?#Y$T=?PHrZ#%T&9Q9uKknZuvx6sRa*3A zO_$V>r!Oo;w+1|25qh*LC*fZ8VK(mjtydN2w=UghGF7eE(W>4tRq}n*jt7^#*HwhB z-?7$Z{g*urJF{B1zA6oMHvZKlojp@sXaD9T7TeGr+k{-!?byMltrl)$CAvpxL#m_a z^v4;KgMwv#f1K5G{QAwDEjmVvZ=0QMkdeIgdW(<S`H8dNc!~Vo6t(|@rt$I3sT<cH zRV>k}X#TQhpPgu|#hGVGG4*v^F)>TK&!z`S>c0??h~idzY4tZM&RDW0n)&~%SyO%I z%1+_3j?zC?D5EYqC&52-->OF<ms)>(O`fF~!V?;QYW|y!$2{jWEwl@2mY!<rT5KWa z-hbq6tX!U_5f?}FHy%-wA5TLUzrOyxDk|;EmTBBs@i`I2?WxC~PJb<27;~t8H`hJE z8+#^bvGRl;t={3Iu(SE<mZw3Y+fEjp*<4*2qOBbeekd(*T1nc0e|a7W6>Cq;@6x{T z=)|D_gBT%p*4ZIF4#F$GzS&Y6TfWP5I@>I!+oxEY<8;}yUtF2}NW#_c+Vt$ykK%K- zZH@PuV9j3{nObCd_tC}gVZv)?Xl-jVjHzFqUK=}E=;dFd2BqKs89ylIH>jP>{Z#Sx zr$fn)V+)lWUE5W))(Ule|FyC7%!H4d9>+)AS2zEpWt$kO5^!wEJFOiDcc-alGgz*R zVwK3cT9qZY!boDnWMB6g^~aSxPV8%m=i2|o`dGPBnTBZbn^3K1H?}IY^vbkvSec^h z*K>ACJ;&5Dc@NiLz0Pyx%)&f}GmHMs+rQUPfI0aKXFc1WTYa)3`Wh8N{vYoOaBk3= zFZ5TN%k5{L&$&l0Q*N8gnq0kXqxQ~nsoj%#CuVNB^E~TD_;rug1L`Rc+1Bnox%rOL zv0Re}efdt+jGUfZeu|m1#hjd&qVc3(ML)4#<z`0$|M9GPg{||}cvOE+iWgN2lJVY| z@yXp}`sNQy^PLzqq-H4Wc>41=!&@!(U%Rv}a94aZbl82mao<|5FG87GRWF`$9rznF z`O_<zZ~OvVQpMI!d;D($NBG?1Zx1kfdG>232_~qktG?g3?TNDt&%=K<5eMbJXB?`P z->^@?{QX{uU4=*N<@M|3>{M@=Pno#SdPdG~xr--4ZY$?_oO^KA?B70T6Pv5wq>p62 zoM-#z?1L|{ITNpZ$o|fAZ<qG>mgT3IvSz(GbD@Xb<e{Q+Mc>5VoAZN$9dGXOWWU({ z+2pC`x-Z3gE!=a~y1Lv{_~*3wQS@&!Hl}RrzY&j4F53U#heO1ytJVS&zkR8<J8*QR zQB-}rOZH!zwR>2ZOeP=mXuFkq;Y>mSTlnQ-30aSxvxn3e{gUSNFR6dmd4#>y(BIau zx&PhNjsH5_{%`E~`pqF;ck|!mv>6ZHEdMv}{D+<XAv5;g7vFJmze{P%-lH|AKGg2s z{7@cLQ8c9dWxdDBz@RAtYj3iHhAggTu}lUvI1dzy*Xv~^mL+bD$j!fPCh$*A;eX@l z_CuMmPuX|8oU|<aVs3A@ne?}{OP6jw>ZWEpX_NGpfA6j3G&`%ho6A^vA|9Q-YkPk0 zhZVg3`9Ha4Tw3j-t!$UK<rmLN-)maUj~4HooLTW_O^c67j)}yCY0(Q)HeIUO`>d+0 zrldyYn)FiL-)FYh+i0%UnB=|o=iT{-ZrnWZ<i?Mhhg)WUyE47Sdu7wPY}M3Ak+WUz zjcr4vCV6LXjhG^KuW<H%eWCSSd1tB(R$bBjv%<xHvEc&Uz?!mSdC&BppLurR-^LF| zH$7lD#=UsPO$V)MOgxV#t?U&($o;KTdRZc;R0`Mp8*Pg%{cq|$pO(s1e?98E%i@{8 zrk1Rkx^a!b_JBL3<?merf0U<*t_sZHvb&di;PlOhMR6GqZpxlc&{RqB@lacH@Vd{E zJ5Fv^GBIfa>T3k^oL<P;+u0@c-&FlwHBm|Z4S&Pg-(KJI<7G_Q4BuX4INfTJv3QT^ zIe~mOzQ{iB-r$!OK~Za39ye&1an|qF;R;$<Go^C&&NjBBu(z=V%!%{eeMR&e5^cJg z^to1qEs9J{Y>nBtJ@4oHj-DwwtZ#gr`p=u4x82g=<J@Ju@S@PCD^nQ#i`h&A)*Bu6 zaeTPc!17&W!(GM`T}q+1L|;X}y(liZl0(>OS(dNx#6!zpwD6udbF=GFxn;%or;M8Q z-mzbdwys%nBW6Zz%0%^ibzcTKmCc^l=LA2o`^4^5vM4G_<`=6)u+%5de@nO@Zt;EO zd+%fT($+gIa#5dk%7pz5jX5`SN2;Cv%H+7%bGt;mFVCZYF-t60ewbO}u2C7Pta0hW zibZD>9JK|`J8|;#^GFsJ=aqJCe1GTVlf`-l67?T^V*-3OEWNaZ^}2M%8}%tBg$KQ7 zD>uG(U3G)|!fMlN_U6T9HCr^rTRoWDl_i_xHor(ayiR1={GhbFSd+h3mr5twJ&agj zvLUX!I@0x-UCO4F%x&)L+{Fa!nqn$;1*ygsS?xM`+tIm0C-$_!wcMq$CRce|kL24F z*E1R~c+FP-X7vM;hB=4KFHN64;feFIP`9s-ELSd>^RxYDy!ra)`Rn5S>wP8~6y8ya zcU!A?MK9{&)!)y4W&IQTx@-GiTf6MmgWW+Qk{LeHFAv=h5tCefdJC6tXW|QU_RPgw zw|VN%&JJByBz}!awx6|Kw_C`V{d&X&?>NEmNDHxJvfFp@$kg|}U`REXvwG*PpVGS9 zUbHP_xVU#=WVQcl{tTl!vnTJTZ+H^%UfOHwyI*UCtXa~EUimD08X_zl-pXUGKK+XB z<;~A0Uru;jccMc(JnfL9d{*9+$q@-BUTbeWx_D9BWz)|}TY?T|yzg~n53y3aI?eFd zt_Q!)C|}ywK1u6v+S<EYBkJ#nSRd6tsJGzCq%gY)t6sVMoEZ{oRVNi18u)`VWbdI_ zuCZ?GQxa}>sV)d#z;{__t`+z3fX{O3P45eZSFQ`Zu{3UKiGsi1hInUdgO{qZ7hVfV z2irVY?PhL0(=1^*bEaMDwAZ3HH0OSOw#B>S^iIKI_4~>d_7N-XA4Fx}dh4iAKjl%s z`_qao0>_^x`c&`k;A>lAyfLwwrz&=SnqbGYWdT>GT?x7$Z*=^-?G~H+`b$gCa_zI& z(aDv)TeRxkU-Q?y-h_HiyuR|o*Mn`>RrlpNZ2#?Y|83Hgs>e0#4trCtN|fB<y)0%O z!12g$uWH!>@$%mCjO9%+@4v1%-Z!Q4l}Ahclh?P(>Lscd7mDZSe{vU-y!>+B%#)#! zDSDoocQY?`<~RGldRHz`cSoq_Y0A`n?OCt4Z2#bxc>TVaNc!K<$Bm)scMmGr*0J@J z>2FcB_^`*bDK0&*^@l@d)$*%hDGML{cVLlU;g@T^aOPKs^?F+?ciw*x-Ds<EE9$o4 zSKA#1YwLSDZx!xp=~eX&xVX1-hu_{`moDxy&k!nS_~r0G@!!9U{tm(I_s@IGIoxZ# zF_leL=Efn}`}1a>DgFLjVb4BSd54?lgjp(_FWz7lWqoNO(5ERnw=Iy{(fr%9;+C7$ z_2$c_vl%`N-J@yuq_F;R+P`zQ9Q8c+kJfNUar=8PSkHJ@&vBY}=D}vOcdr+>EwoBu zFUgsD;?8vL8#k6s&UyVOTB6ZiI4tzn`mb%@TmGr96Oy^IEnpQx&V+~eCyA#$vOi=L z+AZSk)^y`%rOB;|(CGr@4t32%t53emzb|7eqU>>AUqd<b-tR}#GMwG-MfiKZvrnHq z@n`U|w8K|bIRoZ4sJyB_DR0YVcq{5bJKv>_?+Me2C&wqg`1VMl=BD4BrX4$L7QEr# z(P)?Wv)!#`#tM6tw(kpzl{3p8Kc1h({;NxR#rjzXF9~~X7XG$G{R?N`u8+&M>=4ZR zBc5P>*{|TwUv^L(Xxt`}befHUAyI+>Y0M=dhsB?Pfq`N2fqst7f7%x^P2SNjuz79Q zMDQs4X2&VA;8FC+iSu*ngRK1z8wl8Ke>vG{p^ZvHQnuuWL)TUbtx8aQ<*<6q)Y(xF zR~_lgVV^qxXv>iU{14m}^%gogm1xVod-Hx@_3y`@-^wzqd$@#6l`S||DR0Zs$gD3x zZGGxhijQa3hCTeX>&l896IV_Q(^8koI;yNZ$wk8MlIJSptvjY0?TvjZ;{B{%s)Faw zTc!VfCl**awC0^yaOW*6&mKY73@1q`-4zZ~9dEm<9*;Ddo~HF|W6Fh(r5cYMB+lH= zzEIqsA;}UQwteS&yXGpDSiYb>zwOWUk4}Ct^YDz{8L~H}g?pwH%v>1tte&H}UN)-U zgVSH$=&8X(#;7HncQlsnpS$AFW~IMf-Es00`nLu}%1ll!USuqM%KFUlvVA)ruD)}B zH^VKiC(B*TZ?T<}+G~;NwyWqT*VpNX?x;lS9uRvYvPogWz1BaM-#E^W_|5vA!7BTk zVkVnAYt<iCP_!s`yjKcfWMDWrz48Q8`1A>1nMJ0{er4vbFP-S?ci4fa_4~vkcKwCj zFB!W67&kI09%0o=PZHWbxzNOZY3SA6k3FLmwQl&Vnf~+78*}Abyk#sxR>CTuvUoPB z%|4@`yEF7ob+z90L-$yum|Z_{3U`~w9!NZ}Va4iQj}oU$Na&3=vD|39Ugq+n>HCad z?45Jd{G*+<`Nq#T*Q~2gVB;@{h$?MX57heotu>?Op6K}%X9O*noMcWKS>4!>?`Wrg z=Ih<{^K$v$C_a6Vc;IhJqHBA&;KAn$7Y0aqyxRI>x33B7><g;Tu6Q@_Z)55g+2wd$ zv;JAB>9b=SS#y%OGK3@A4gYOsyP!8Q|M65&87~or<pvJC_nUKes@}b68F)c5adE>X zaivuqp8UN}-E|dBXU3j9HplAh>GVp!Jy)(jp0<70Z`*UWB~!XY^7EFvTV1<q4hqmc zXO+T?7#SG!n2^)?v@Dj%j#K<6Z<x<BIbb=*=I$lEEZ|8X>6O2kKn$>K)=J^c)oUJe zGq1~H*_^mzJu`>_o*n|v`b^$%PzXHfbGKMHROJ8NC5e|e)R^eH2B_$+$YokH|3}~f zCsxfRte%=IA~%*yFS&g-@6KI=E9^3|508q+|7HGD@uK;R$7&-hyPps2pL9R2ICodo zce2H~D+hWmpM1CX`MlrO`#%?+zx(gsb^rYg6{4oRhK)_HLwU}BUHjVfeC&j$2UhGV zzO?UMy}sqsj2#c6`W~K~rC$4zB`slRU*N|xSy#XGY!14{_4U%3Am4d=&Pv&>&3Yj? z<7fT>;k>QSuFbVH+t8*nf$PMTp3_N<#y@){HFwW5QOmjfUEkyW+UitGwGFSG?sBeK zHD_zh>Xg%u`yRKw+IQgHpQg&wdva&+E;M{=<#%^m=Hq1t>c40i33%uTX<xdxZcA@f z!cDh(pO`Pb)Qu25&hu)X$c~GfYEqixOr9s`x+EVz5p#Y~*ZD&yGQ>CB{<M3)XVs#- zo5h!sXA8G1Q`9Z^eDa3RLVjkevV;jm1xJe3JeYCd(TT~QDoVl<qVE+wDcKt}>0Xbg ztMY_%yHhXEGqvr0KJmls`rb*e0#?MjWUUM;d(r=&`SLn>iElL(e?QviPuj$@<oXr% zppImI@jIKDK2E%NGmayrL}f##`(dl9!x!shHFK5;3!aI-!l!4~*R_P%e8;{kJM`P0 zE(<h&w9=vOFz<ro?l-9qR@_v5S!wpBJaf~fYahLG53O77+pKtDf7+8B&u4nq=V-P% zS9A)0HQM@hqMDTOy4=aJ_s&_~PnmXlliRtFT^CKGZXLZf#apXjXL8Q5#61fimU5kc zynXp&-#xC|FX_(XimB6?8+bHuw`i2ejB266B}Y#3zh36Mbi4AYb-7lek7GJ{`+DO% z6J^v*WR|bqQ5t%j<sRqi@KAHn3yYmXqrB=ZrXA9pbM3>r126Mr<z?L+zfUgs*_ZKn z&8$|>$Xh`iXFffe64`yOsOa98=Reazb<>SnKkr!Z(6({k)>V9lHL|Q{1O(nMcxO<w z)j30r)3AWMG2K$Mv9WYrdyrM=bk?$MU5lgjJGGBY+^=U;xA(~Xq?sam4{Pmm<hLwQ zJ|sOiwZ8YYRo;Oo%HgX$)BPSKEI+gLZC%MtwLrD=M$6Wp@nqY5v+3iBJN8K*&Q;2a zJBrTMTCrr#CW~Xct;4=49uvHvF6&;UHTBZ<fThcBofTR>qg1D8)ueCvd^{K53N2s% z-QrTs+Y3I6CHGJM;`f>LirV7U9ELAU`Vvp?+8X!kc2}-Se*Lt(<@Z-?a+2b|7%sB< z#ecut`;sdg&s`4&&H5bB3*zT}bL{e$cm3|*Ss!OD+b?n_);*e;^N#Ub8o$kffNu|& z-|SxhCrP;ZiL`<9tm&PJ6D{H#?bm5dzFA;D@9^iYhYlj_avQ%JnkLPET+w)}YRfdG z`!la{{Ji#Vy<_q<@A{Pe$M1#3d!H)cn9{++t@J71!FjC%H)z)90>}M>W(N*;nZB*+ zaCT+7yS+<1y0BR-W^dzfuD|`_!7nek2tTmkwDdR`^UZya*x|oy5nd;!cN}u(DloW` z-D1^gC=>WEP<^rb;#zO37%lhBJJ(Nq5qa)!+uEC=d*&{_AMSBvdU5@JC!fL){tNl6 z>ib>n+uPEdv)rm5o$fuuuRW_=!%AMb*T3V?a+jyZZw|(GUAEnI;hk32%nKRKw*q}0 z@dVy-)=u{nbDp<k_Ql1yqV-7;!E2Tq$ZnKduJkB@SFP??h2gm`Tu0@eh5lfCJ}vst z@5<l`cIk&p&4d=t?F^by+2MWEucS~keDkU6*)K0~J==8Za<=x0Ez90^tKIQwk#1f( zk2@ly-Q0~e;qb!qr|d2jU;GU&m#6byU9G{&z_1@>tae=%i~r>P34W6|>=1?Y!Pkc0 z&XYD5s5O63KjW9;gt-ZS8M}C`^O(O(6WMt2dc&=`Q#0OAijGT>?)<mcIA+~9rBkbJ zOEoQ3ZBI|*JI}MT_k{crA;;ONX<MeoOD}$JSRT2Sd(FOE=~Iu-{~opKOhWR7MMZ}^ z*KS%WSgL#G&yN>BJg)Vc@x415m2$8Cq}FaTH=F-zYiFygeebQ0+fZ&juj*7wkkzk0 zOQwDby&C;z_l4qIgWW4zw#Hw`$}jq}z9aY2wMB)E6FzU={8-tdIr~T1)XQ2wL^tmI z+P(WZTYc4|rPHS6I%vJ_S-#}p+6|lk&b|A`Db6fmPthi~0;?HZRYH8tg=^Px+vPOx z)Jd)9>pPI?Ww9xC;l!3Gso2XCw!B@k;X_C0)Pu5&9g8N&>{+2y*7reUHJ2C%xBhCe z*e6HA6t7N7mS8!_`E}+2W?QC4i#44hyE_Xn9CuomJT0O@Z!^R1eLH#X+iNH7aX9>f zW!ti&3a?sYs=9b}JD6FnJ(AqAYM$i_50>h{1G`h2yXyr!7dD2l^cwg*+mtA@l*uvq zh{(?sOR5;2)l3j}{$iQy^nmfBSH<>AZ2L~c9A-B;J<H^j@$=*Ez40Mi#4T5A%bGlx z>>L`g<D!b?`Yz6?_aht_*0wa<x!W7r-yomS-LZprflxPBG;8k4G=<ovL&v9c_UKtL z8gyN(+o|+us)}PhN2o(&<vp>LGP8o7%-Guf=u&Np!vbanp+h#yDmpV&JYPOjQf^6o zGHZKY$Zp45<+H@kSRd}Q;rrmO)4D$9e6Lxgd8OU4yS>?Er|vZuu2|gDn)gu2VE5ai z_xkC}KVQq4%=OSrYx7-|*W$G+Z%zFcdhnC1NQEKq2d%Pw5_#U4P4!1PY+t_-_VE>d zb#w8WABp#TrAzLuNVuwc{C^N<-4w4|p<XRl+&sg+ZRO;B)mR;P(VoA2$=e+>FU{w8 zbxWr<!*28B>{B-Bikfw8x1!Cn1k~TNEn0a0kj}-u+`eb#`F(yq*U!z&x<l~jhM8es zbR&<?n=dWmylBCaD4}+4bLlBJ>L;8j+^MQ^i1C}uvf?{k^>!TfPgKQxG=KiE2<ZD? zk+|T)gGB)akLOk1yks~3)1Qm%iaxLEZtr|yBJfq=-u2LQet}1P-BTAFp7l%bf1I~c zY11Z`);7gkxyxQ;J^Umpzy7wE4O{+i-p9UuHv~-<UOnhxk^bb6wboGyxA&8nyB_?h zH!rlvxt6)Jy!4|}ap%>76Pwmfm0kVUdiT}rU8%WGug%_4U39TKYk70|B+o0)<=xh& ze!Nw-ce}*#o52=7Z~S=ugeomp{CCb+-)9xDQ@Z^8hkr9Ho5b__cGSLG*H^1`FG#G! zmgl*H$Bg%xbHYmwIsau<o8+|n+C5XgWz}CRdymxzOliI|*=vbT<q5Uj&p+rHSTOIp zH}k{BYnvXtHZ@ykzy7%0|0!WXw-?Fs-H+b?(USYVaoAVKeD1Z{A|*fnobEn#?pC?( zg=mjRCx)i(?t>ZoPaaFIUs1|!65YOIe|>sYQ%c7?c@E{*^UEK4btN`UxBJs9rk5~n zjxDS0{a~laGij5r^Zz=kxu^1SD^uXk<jV#n6MT1ZANIO&m6x;1o$sTqS#t9c*@p^0 zbhm!^u<z=>8wc$({hMw~^Lz0214p$t^OsrTZtks~^Y=4?+M%57!Fsz{7#KdHly@AN zEZ~_a&~l^cxxbkCHt#yN8{7betY}JD!vPW&*?jxtA|7zNG;v4p^n%~aTATk~Tg}A8 zkvaJttH*SOzs&N}W&bdXZC1ba2BJLyyf*1Cv%==uyUcuGt&UUtr*HVnEV=phYhCb4 zr^yStf;Z=Vo(=BPZRYv^k`bg1Y%{2VD?WX}7iQM&(Tt4A;KuRxgRG1<m{~Y7S^TFr znlk!M|G>>CwVj2FF^QR(Gm~ZdnIguJ>HCElrKcA#vaoKy%gcCy6C|;HgE-@EHZUts zj?oD+|7Nh5$$k0;UPj*Oc5EzC+ZB}<JEcKNrXwWov9pM77qep&5@BY}X4$SC#JF5= zdMFdK!1NuNOpenZ>}HhQZj-{;%LkS|Q^d&629eHt!WcDumkcBC_Ml2ePG*qw<oE6F z(+heT)u$ieViDc`u!d0+O+0~{MRfaw2F6D$AobIujx**><6#lm{=Jnk5>4rR9v0E< z*E$&kAmSU#-M1I?GA?EXYrH?5v3U9eUKXkCizhQ$f(_e#e>!6im^J<WbjG6X59Tm( zg1HD+6$r7gY>!*Ws1G(|`-EkT)?gLWCoE$u+U~HL@dDVc?ZWFBBf%2e^EWfbfmzcV zA28-k2N^J3R+vR}d-x7U3$Wtpm1#_V+aK&^)B$t1^Y3Tmg6MdEoiT5F*I~x95Q(Vc zjL#tw{QDX6rn`!<h;2V{hEWS51`3Jk&%{_nwwGUI{Ky3I<o4_<jExYz@2^AsG99e< zoCJ&5_WC=F{~@xC4;b%4Scy*<6SN@FV-ds{HGM)aBir=%pmbu!&txet$eaxsc>s+* zfN=Ws#7@S@=?A1)c(y;)W9ngt=zUYmWHo((G>gIZ*JeyFnIVF<i<zuIk*l!X&YDSv z2_gte1ly0;GAV-d!}b^UOdXQo<o&{)DRjDhA`|!Y4{|K5+iyfN&EsLN&0*PInZ~5g z3}&s)WHJ<)zI!s0!1gz_OnOXU=Hz|lR?{E!F$qk!Q)1EBKBs}{4^$#=2SP$%`YR<C zvF#EqOu`V^>A9zv5YqhHr?fFKaX<{rn{T!KK_62yRH4XPCj0606<N5p@0rN7jRWM^ z?WMDr8o(ZyzB-f19b`T0^qR#?Jlg~2GO>WyEp88Az;q3)WV^v)rW~*sC=*3Y=g?pg z+s?b3$pVsRC;R)m!42TvK7SRH5!jB&r_VzS-mb8j=?GY8`}5sQ9Bh!B{&zN$_jbEO zOzXg9z~sdF?$aG~SX8!09cN+&Tedyn6caaC8>Hk&&|{I=e(@4hBrC`VAg3Ufe@abn z&}U)WKKllfodomB9G2~OJ}|8p07uyN$BfL}5ChxyF{gnI-2UMh^CVX0^c<G$t!J2< z*qPFErt?QLOHSuF&g?b)++${;&GiDtjMF(DFbhmSc$N8IeR9HoKTz_4VNM1Hh9Fl* z7hhMs+!WDMj$9220<0JIK9IHB@?Pj|(>Z~_WGyS<#jf}4s$ZKcoOaCY6}lmnt@dyi ztKNe4Eur#1T7plmn783i={w=2U%wsdbjoY>Qi{=<_$}%fKd4wQw_KJ78ZirD01q#0 z-*Jt32N(0AQkLn(51E}o0kD1NLuLa;kRPVMdBofdW)wYU{sxxIe!{E+DRgH&W&Q#Z znm+Lv^FJ_S(sSlNV8+B3%%8xFwwF*w^((02qSp|{_RKfTT#VpFsbz1OXY(D(V(~|; zs+unUj=5R^B!;{~A_^8pV45?3^1-~AX}_6y6s~2l_(xs(&bNq}fkBU(fuR7b07h_@ zOg@<BGX1~@X5r~G-!rR&m0z>-K3mVkz>vYlz>o)138p<O5X#LzFsp)<BTv9ZgO$OE zlxmoARfVfrEdI#Dl&B6q-3U`DGClSqvjB5K4$Jg{kId3ca-ATV$$S$;CWm#%OqbJO z;Q>nud}5YnI^PYI6rFzO4YT0%>7SV8m|jhQ3QB?l093>E^Eot5WMg2sBFMlH4s#ut zE|@y`V4lPDhR@8-Ol@;O?8y_Rh)h5GomoHuq!T`b$Hc&Z>f{LvreFNR91f~h1*bh_ zW|2W2oQeb+4kI!aft02*Ps?JNZvB;6nn`g9NWcd)S~Y#mS7v>tcgtV`JkvE;Sa{?? zc5f3D+LO)1z#zoNz>o?v3rvelPx!`M0(RhmCTH0QRtAO~46g~TnV$HKIe7Z*H_SrQ zBfm4tF}>di5jpdnSr9z>_24_RG*i@$$p`b?rr-U+%s=_)4oPqjD}efL$h|sL5Ap1Q zX;B2LL~aj7fL#b9b{~YP6aYso*v+!ai)T+_VqoB7V_-l{F@KJMq5#xN;+wqd7(ai2 zHzSh>17s08sCgyui&>gU{1i-)9aGi?F#GK<W_fU~;{VMo%_M&vlmb94D>Ja*N|2z} zEtsIpWT{)cI%r1wGkbG=&|qU=&=x^=)YiK&ox;=K{9qQEe&P?a98=m8gsA;rW<jve z#PX{1E-^7MZ0ABxXi9Iu4&CsV*_o;GJ&X-WX<$dj{9~48+VvS^=;XZ5Qq%k1G4o7+ z{Eu0VY3^^Rpy>2JznBHUs`LLdOEazh50aRE;Xktx*!JpOUneIrGBA8#Vqge@#Q>O| z&Ny9>k;MYu5EPu+#3IL3!3-CbhUb+zY0JG07#SGqFbqjx11Ya#65yD=kdY-GY~_6C zs&h4r3=I6t3=A<~t6+pR7f7|w^uOGUywfY0SoE13dEg>~(|;PU@F;L*viMJV#>-d8 z%D|u?#K4dY(+s9L_@*bavbe%qp`z1QFtbQ8af!f%<-wT+Y)s1XTR+rT7#NKB85mF# ztG@(9y#gzX;PeHYEP~T_v#`i9{gHtSD}qh<TBmt*EfWL7JT?Y~EU*J$1g|_uX$AAO zESBkaSXrc*f|Ni4k<-)JS%jviu(8N7$(un$?y|86f?K{H*;u5ReC$A?uG2w{-{~3b zEc#50zHkv$1yD1o^gG)YX+Z`C9t8%5M3{wO`c%;Li<~SG)2lgH#1)vbS^OtuNC#)~ zF);9IGcY88mB5IS6o^ur6h<yckbsPytRcqI$jZR5R0lm|vx`CM6TqPXHhTK5z-~~g zc`wGmkOVUoOxIR|lorT?4D5YXl?{sMR1OA)BCsrs_&Ys;i=`2)=$C>*%n23-hEoFQ ziq=fyW@&_YdgH=ydu9fP%^VC2g)lR~v`E|Zh1@LlU{#qB?MKX*85nk8Sof)OdLkD~ z{Pg)eEQ(;I&;Iy43S?zq_$!89Wu54SD7EKhkp;DOr^oZMNHcAnJY7(TC3*UNUKVw* zC?_9_G*jISh-fDti#pg?Yahd(SC|<Xmhmt!)PUUwBY5XRls=flC_UYepM?i(N-RH% zG*kCNh*aD{MnQzsUyzjka)?x|01G7cr)hQ0o6F3=V8hM8Pz5s^Oy{nKD0NuPD2Xt| zSCB=TY14X;RO<Bef-Fj4XNtZpzqNyzfkB&_fuS0#8%FSL0V(YSJ8rHJi!@XI4v;`H zsB@tR7IhS6k!CX70}iBVdl;pr2k^4+fK3hG-N~E7%)lVR#lTPuGZ0L#+YeSgy>>sN z7(zYAEBC*%nHd<4axpNJg4Mx@-G?FSyACr-fYpO-))HlrX8L&?B6Z?8qX@#ACqYt= z&p@PH#aNWU8nVP#q?x8%gor*9V^IK$a*DG^GjUyoh~B)yD2=dTJxHqW21F|M2BQSn z2C(PE6Y6(7WoBUT;z9S^tUD0(=Omz^JGno|#D<xH!H1K9p$z6FFs<+qqBLI;8lA7t z=ty4HWMFt#ik^)ao`RIdP0wd!5d!D9PlbEy<mDL{R=z^d_sRUz8)aA`;GHT#u!H59 zOt<H<GceqAWMD`K+YTcH^&#p(y(>^5Bgo8@%`)9vnnjvP*c>ip#kgjAgA7Z+bZ;3J zF|Z3ZACR;B&B(x@%gn$K3o{H%msx|fWrNLmFT*0u^v4z?5HUSPmPG<w{nX2{NHeuN zOjnd=ahq=Iz$7qzr2-4j^nbD}a!kGcaAEH0`Eo3fhSc&udlr6WV_@(QWMBZbufZ09 z385&E`an<zPM@hW5yVMUsLf&V|EL>h+snkju$+y7p&YCfMo6TCRJl#dViKGFPo6~+ z)X$r)rNAQ1<dp@JkpVeLi^-@ACLlij10#!o!lWD)|ER!ngH?<S4BjjZ3~4Y!!E{|6 z$fp*dt`)dzC@_7OB8v?3q#Ty%Hx*f=nf5fG%A0`A`#1f%?N3GqhV`I^7}y*bVby}F z9^9i;0-MLL%p%QnwhdLDe|obrixAk*6Jc)KU6~jdj<KLOJuUj-npCFOF|qJ~%~Mce zk!E6@1efBU-lD={z!W<LN#w5ziy$+oAtk8FBF!W+8!p8<JzJH<oN4wPBoU7}Ogz)y zs<ME`s;2(|>6ktjNgmX7ogOfkNpkuGO{k(SH5O^6Zwt^BeNbaj0XG+Vzw9%6!o<K} z!-<~e&M!vQqy#n;tm&KEMt(VF28IAGbWL{4ku?2LXVC-uO;>|On(6r}B&nLkOx)Aw zuVP}GK0|{=i)q<fbU7YPXt*e7vPd%(Z$^?=*vupba*Gzz?;WVZg44OQSRl<YSuGZ6 zrnWsu^5t4ACQJ(sAc^=MVB*ARb^hGG=}tZqBqh4T5)GK1cnC?a-61BP=^5HAT1=%! zQH9y3-_V9S;<Yx5G*jPkh`fUiiyxE5NeJh{2`1&~uXUi2^h<|Dn(6;3h}3~6%<`aq zywLOpT^2besS8NL+y>B4;nri3X5zgJkxI~Gabse?2H`x=V^IeOI+s3+G}D<I5K-6$ zQSb<X0h7>cbYZZ`D|1+;%NwvrGgW__zR`fiWqN}Fi$0U+PY|bwFZvG?gI;=ONoIOp zeo^Z5JVO>OCS9iKvkY147}rmiG-8Pd+dJ2ZMVi@zm3i86=Ah~EPnk79dr~23+|!vw znt3BHNUCwVl`{*EVtNjX|AHU!w_md{FwBr(V8{W7G>mW)1}O~!4Mp%w=HNu_eWd5G zOrPk&BF%hS3a(0Sy1Xlk98;;xbbD78F>TOr1@aIAXt)AqHUmSmEHh&8V!Ed*ixv~7 z-1Jgc7GtJIiqluQvUsQjsWUU^CFdj-7Z)U!WCVD#vVpYEW0=QK62ic+LxY)tfdK#~ C_bTxK diff --git a/src/main/java/org/rosi_project/model_management/util/query/ModelJoinCreator.java b/src/main/java/org/rosi_project/model_management/util/query/ModelJoinCreator.java index 16881a0..9a6f688 100644 --- a/src/main/java/org/rosi_project/model_management/util/query/ModelJoinCreator.java +++ b/src/main/java/org/rosi_project/model_management/util/query/ModelJoinCreator.java @@ -14,6 +14,8 @@ import java.io.File; import org.rosi_project.model_sync.model_join.representation.core.AttributePath; import org.rosi_project.model_sync.model_join.representation.core.ClassResource; import org.rosi_project.model_sync.model_join.representation.grammar.CompoundKeepBuilder; +import org.rosi_project.model_sync.model_join.representation.grammar.CompoundKeepExpression; +import org.rosi_project.model_sync.model_join.representation.grammar.JoinExpression; import org.rosi_project.model_sync.model_join.representation.grammar.KeepExpression; import org.rosi_project.model_sync.model_join.representation.grammar.ModelJoinExpression; import org.rosi_project.model_sync.model_join.representation.util.JoinFactory.AbstractJoinBuilder; @@ -22,28 +24,23 @@ import org.rosi_project.model_sync.model_join.representation.writer.FileBasedMod public class ModelJoinCreator { - private AbstractJoinBuilder ajb = null; - public AbstractJoinBuilder createNaturalJoin(String start) { ClassResource classRessource = ClassResource.fromQualifiedName(start); - ajb = naturalJoin().join(classRessource).with(classRessource).as(classRessource); - return ajb; + return naturalJoin().join(classRessource).with(classRessource).as(classRessource); } public AbstractJoinBuilder createThetaJoin(String start, String condition) { ClassResource classRessource = ClassResource.fromQualifiedName(start); - ajb = thetaJoin().where(condition).join(classRessource).with(classRessource).as(classRessource); - return ajb; + return thetaJoin().where(condition).join(classRessource).with(classRessource).as(classRessource); } public AbstractJoinBuilder createOuterJoin(String start, boolean left) { ClassResource classRessource = ClassResource.fromQualifiedName(start); if (left) { - ajb = outerJoin().leftOuter().join(classRessource).with(classRessource).as(classRessource); + return outerJoin().leftOuter().join(classRessource).with(classRessource).as(classRessource); } else { - ajb = outerJoin().rightOuter().join(classRessource).with(classRessource).as(classRessource); + return outerJoin().rightOuter().join(classRessource).with(classRessource).as(classRessource); } - return ajb; } public void createAttribute(Object o, String ressourceName, String attrName) { @@ -58,16 +55,18 @@ public class ModelJoinCreator { } } - public CompoundKeepBuilder createOutgoingReference(String ressourceName, String attrName) { - ClassResource classRessource = ClassResource.fromQualifiedName(ressourceName); - AttributePath attrPath = AttributePath.from(classRessource, attrName); - return outgoing(attrPath).as(classRessource); + public CompoundKeepBuilder createOutgoingReference(String fromRessource, String toRessource, String attrName) { + ClassResource toClassRes = ClassResource.fromQualifiedName(toRessource); + ClassResource fromClassRes = ClassResource.fromQualifiedName(fromRessource); + AttributePath attrPath = AttributePath.from(fromClassRes, attrName); + return outgoing(attrPath).as(toClassRes); } - public CompoundKeepBuilder createIncomingReference(String ressourceName, String attrName) { - ClassResource classRessource = ClassResource.fromQualifiedName(ressourceName); - AttributePath attrPath = AttributePath.from(classRessource, attrName); - return incoming(attrPath).as(classRessource); + public CompoundKeepBuilder createIncomingReference(String fromRessource, String toRessource, String attrName) { + ClassResource toClassRes = ClassResource.fromQualifiedName(toRessource); + ClassResource fromClassRes = ClassResource.fromQualifiedName(fromRessource); + AttributePath attrPath = AttributePath.from(fromClassRes, attrName); + return incoming(attrPath).as(toClassRes); } public CompoundKeepBuilder createSubType(String ressourceName) { @@ -79,10 +78,60 @@ public class ModelJoinCreator { ClassResource classRessource = ClassResource.fromQualifiedName(ressourceName); return supertype(classRessource).as(classRessource); } + + public void addKeepExpression(Object o, KeepExpression ke) { + if (o instanceof AbstractJoinBuilder) { + ((AbstractJoinBuilder) o).keep(ke); + } + if (o instanceof CompoundKeepBuilder) { + ((CompoundKeepBuilder) o).keep(ke); + } + } + + public KeepExpression buildExpression(Object o) { + if (o instanceof CompoundKeepBuilder) { + return ((CompoundKeepBuilder) o).buildExpression(); + } + return null; + } + + public JoinExpression done(Object o) { + if (o instanceof AbstractJoinBuilder) { + return ((AbstractJoinBuilder) o).done(); + } + return null; + } + + public Object combine(Object current, Object added) { + JoinExpression realAdded = (JoinExpression)added; + if (current instanceof JoinExpression) { + JoinExpression realCurrent = (JoinExpression)current; + System.out.println("ClassName: " + realCurrent.getBaseModel().toString()); + AbstractJoinBuilder ajb = createNaturalJoin(realCurrent.getBaseModel().toString()); + for (KeepExpression ke : realCurrent.getKeepsList()) { + ajb.keep(ke); + } + for (KeepExpression ke : realAdded.getKeepsList()) { + ajb.keep(ke); + } + return ajb.done(); + } + if (current instanceof CompoundKeepExpression) { //createOutgoingReference(String ressourceName, String attrName) + CompoundKeepExpression realCurrent = (CompoundKeepExpression)current; + for (KeepExpression ke : realAdded.getKeepsList()) { + if (!realCurrent.getKeeps().contains(ke)) { + realCurrent.addKeepExpression(ke); + } + } + return realCurrent; + } + return null; + } - public void createFile(String fileName) { - if (ajb != null) { - ModelJoinExpression modelJoin = ModelJoinBuilder.createNewModelJoin().add(ajb.done()).build(); + public void createFile(Object joinExpression, String fileName) { + if (joinExpression instanceof JoinExpression) { + JoinExpression je = (JoinExpression) joinExpression; + ModelJoinExpression modelJoin = ModelJoinBuilder.createNewModelJoin().add(je).build(); File file = new File(fileName); diff --git a/src/main/scala/org/rosi_project/example/ExampleAml.scala b/src/main/scala/org/rosi_project/example/ExampleAml.scala index e56258a..38f5419 100644 --- a/src/main/scala/org/rosi_project/example/ExampleAml.scala +++ b/src/main/scala/org/rosi_project/example/ExampleAml.scala @@ -45,8 +45,7 @@ object ExampleAml extends App { //ieStack1.addInternalElements(ieSensor2) //runAllQueries() - //runAllViewQueries() - query_3() + runAllViewQueries() def runAllViewQueries() { //Query testing @@ -77,7 +76,7 @@ object ExampleAml extends App { */ def query1(): Unit = { //Query Objects - val q1 = new Query("Q1") + val q1 = new RsumQuery("Q1") val co = new HelperCAEXObject("", "") //laufe über alle naturals im RSUM und suche, die die davon instanzen sind //Query Roles & Settings @@ -90,7 +89,7 @@ object ExampleAml extends App { def query1Dot1(): Unit = { //Query Objects - val q11 = new Query("Q1.1") + val q11 = new RsumQuery("Q1.1") val suc = new SystemUnitClass("SUC", "13") //Query Roles & Settings @@ -106,7 +105,7 @@ object ExampleAml extends App { */ def query2(): Unit = { //Query Objects - val q2 = new Query("Q2") + val q2 = new RsumQuery("Q2") val ie = new InternalElement("", "") val att = new Attribute("50", "weigth", "") val ieRatt = new SystemUnitClassAttributesAttribute(ie, att) @@ -130,7 +129,7 @@ object ExampleAml extends App { */ def query3(): Unit = { //Query Objects - val q3 = new Query("Q3") + val q3 = new RsumQuery("Q3") val ih = new InstanceHierarchy("PPU","") val ie = new InternalElement("", "") val ihRie = new InstanceHierarchyInternalElementsInternalElement(ih, ie) @@ -154,7 +153,7 @@ object ExampleAml extends App { */ def query4(): Unit = { //Query Objects - val q4 = new Query("Q4") + val q4 = new RsumQuery("Q4") val ih = new InstanceHierarchy("PPU","") //wie kann ich auf die eigenschaften und werte prüfen val ie1 = new InternalElement("", "") val ie2 = new InternalElement("", "") @@ -185,7 +184,7 @@ object ExampleAml extends App { */ def query5(): Unit = { //Query Objects - val q5 = new Query("Q5") + val q5 = new RsumQuery("Q5") val ih = new InstanceHierarchy("PPU","") //wie kann ich auf die eigenschaften und werte prüfen val ie1 = new InternalElement("", "") val ie2 = new InternalElement("", "") @@ -216,7 +215,7 @@ object ExampleAml extends App { */ def query6(): Unit = { //Query Objects - val q6 = new Query("Q6") + val q6 = new RsumQuery("Q6") val ie1 = new InternalElement("", "") val ie2 = new InternalElement("", "") val ieRie = new SystemUnitClassInternalElementsInternalElement(ie1, ie2) @@ -240,7 +239,7 @@ object ExampleAml extends App { */ def query7(): Unit = { //Query Objects - val q7 = new Query("Q7") + val q7 = new RsumQuery("Q7") val suc = new SystemUnitClass("Stack", "") val ie = new InternalElement("", "") val ieRsuc = new InternalElementBaseSystemUnitSystemUnitClass(ie, suc) @@ -265,7 +264,7 @@ object ExampleAml extends App { */ def query8(): Unit = { //Query Objects - val q8 = new Query("Q8") + val q8 = new RsumQuery("Q8") val ie1 = new InternalElement("", "") val ie2 = new InternalElement("", "") val ieRie = new SystemUnitClassInternalElementsInternalElement(ie1, ie2) @@ -293,6 +292,8 @@ object ExampleAml extends App { println(q.getQuery()) println(q.getQuery().runQuery()) + println("+++++++++++ MJ ++++++++++++++++++++++") + q.getQuery().generateModelJoinFromQuery("Query1") } def query_2(): Unit = { @@ -312,6 +313,8 @@ object ExampleAml extends App { println(q.getQuery()) println(q.getQuery().runQuery()) + println("+++++++++++ MJ ++++++++++++++++++++++") + q.getQuery().generateModelJoinFromQuery("Query2") } def query_3(): Unit = { @@ -331,7 +334,7 @@ object ExampleAml extends App { println(q.getQuery()) println(q.getQuery().runQuery()) println("+++++++++++ MJ ++++++++++++++++++++++") - q.getQuery().generateModelJoinFromQuery() + q.getQuery().generateModelJoinFromQuery("Query3") } def query_4(): Unit = { @@ -353,6 +356,8 @@ object ExampleAml extends App { println(q.getQuery()) println(q.getQuery().runQuery()) + println("+++++++++++ MJ ++++++++++++++++++++++") + q.getQuery().generateModelJoinFromQuery("Query4") } def query_5(): Unit = { @@ -375,6 +380,8 @@ object ExampleAml extends App { println(q.getQuery()) println(q.getQuery().runQuery()) + println("+++++++++++ MJ ++++++++++++++++++++++") + q.getQuery().generateModelJoinFromQuery("Query5") } def query_6(): Unit = { @@ -391,6 +398,8 @@ object ExampleAml extends App { println(q.getQuery()) println(q.getQuery().runQuery()) + println("+++++++++++ MJ ++++++++++++++++++++++") + q.getQuery().generateModelJoinFromQuery("Query6") } def query_7(): Unit = { @@ -409,6 +418,8 @@ object ExampleAml extends App { println(q.getQuery()) println(q.getQuery().runQuery()) + println("+++++++++++ MJ ++++++++++++++++++++++") + q.getQuery().generateModelJoinFromQuery("Query7") } def query_8(): Unit = { @@ -422,9 +433,12 @@ object ExampleAml extends App { ie1.getQueryObject.label = "IE1" ie2.getQueryObject.label = "IE2" ie2.getQueryObject.multi = 3 //means >= 3 + ie2.getQueryObject.returned = false println(q.getQuery()) println(q.getQuery().runQuery()) + println("+++++++++++ MJ ++++++++++++++++++++++") + q.getQuery().generateModelJoinFromQuery("Query8") } } \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_management/sum/query/AQuery.scala b/src/main/scala/org/rosi_project/model_management/sum/query/AQuery.scala deleted file mode 100644 index 165cebc..0000000 --- a/src/main/scala/org/rosi_project/model_management/sum/query/AQuery.scala +++ /dev/null @@ -1,102 +0,0 @@ -package org.rosi_project.model_management.sum.query - -import scroll.internal.Compartment - -/** - * Describes the abstract query compartment with the roles that each query must implement. - */ -abstract class AQuery(val name: String) extends Compartment { - - def deleteQueryResults(): Unit - def deleteQueryObjects(): Unit - - /** - * Create ModelJoin syntax for views. - */ - def generateModelJoinFromQuery(): String - - /** - * Add a query role to the underlying object. - */ - def addQueryRole(obj: Object): AQuery#QueryObject - - /** - * Remove a query role from the query. - */ - def removeQueryRole(role: AQuery#QueryObject): Unit - - /** - * Proof if the query has a correct form. - * Not more than one connection island. - */ - def isQueryCorrect(): Boolean - - /** - * Running the query and getting a set of sets of result objects. - */ - def runQuery(): Set[Set[Object]] - - /** - * Abstract query object to create the query from example. - */ - abstract class QueryObject() { - - /** - * Label to identify a query object. - */ - var label: String = "" - - /** - * Describes is necessary to be in the results or to be not. - */ - var negated: Boolean = false - - /** - * Important to describe if a transitive closure should be created. - */ - var transitive: Boolean = false - - /** - * Describes how often a connection must exists. - */ - var multi: Int = 1 - - /** - * Describes if the elements should be returned in the results or not. - */ - var returned: Boolean = true - - private var attributeFilters: Set[AttributeFilter] = Set.empty - - /** - * Create and add an attribute filter object to a query object. - */ - def addAttributeFilter(attributeName: String, value: String, bigger: CheckingOption.Value): Boolean = { - if (attributeName == null || attributeName == "" || - bigger == null || value == null || value == "") { - return false - } - attributeFilters += new AttributeFilter(attributeName, value, bigger) - return true - } - - def getAttributeFilters(): Set[AttributeFilter] = attributeFilters - - def overallConnectionUnit(): Int - - override def toString(): String = "QO: " + label - } - - /** - * Abstract query results that each element which matches the query gets. - */ - abstract class QueryResult(val matchedQueryObject: QueryObject) { - - override def toString(): String = "QR: (" + this.player.right.get.toString() + " " + matchedQueryObject + ")" - } - - /** - * Should collect information about the attributes a query element must have - */ - class AttributeFilter(val attributeName: String, val value: String, val checking: CheckingOption.Value) {} -} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_management/sum/query/ModelJoinContainer.scala b/src/main/scala/org/rosi_project/model_management/sum/query/ModelJoinContainer.scala index a53ad57..c0bcefd 100644 --- a/src/main/scala/org/rosi_project/model_management/sum/query/ModelJoinContainer.scala +++ b/src/main/scala/org/rosi_project/model_management/sum/query/ModelJoinContainer.scala @@ -1,5 +1,42 @@ package org.rosi_project.model_management.sum.query -class ModelJoinContainer(val name: String, val source: String, val target: String) { +import org.rosi_project.model_management.util.query.ModelJoinCreator + +class ModelJoinContainer(val name: String, val source: String) { + + var connect: Map[String, Object] = Map() + + def isComparable(mjc: ModelJoinContainer): Boolean = { + var result = false + val size = mjc.connect.keySet.filter(connect.keySet.contains(_)).size + if (size == 1) { + val s = mjc.connect.keySet.filter(connect.keySet.contains(_)).head + if (s == source || s == mjc.source) { + result = true + } + } + result + } + + /** + * Return the container that is not needed anymore. + */ + def concat(mjc: ModelJoinContainer): ModelJoinContainer = { + val creator = new ModelJoinCreator + val s: String = mjc.connect.keySet.filter(connect.keySet.contains(_)).head + if (s == mjc.source) { + val res = creator.combine(connect.get(s).get, mjc.connect.get(s).get) + connect += (s -> res) + return mjc + } else { + val res = creator.combine(mjc.connect.get(s).get, connect.get(s).get) + mjc.connect += (s -> res) + return this + } + } + override def toString(): String = { + "MJC:" + " source=" + source + " name=" + name + " map=" + connect + } + } \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_management/sum/query/Query.scala b/src/main/scala/org/rosi_project/model_management/sum/query/Query.scala index dbb13df..d50547d 100644 --- a/src/main/scala/org/rosi_project/model_management/sum/query/Query.scala +++ b/src/main/scala/org/rosi_project/model_management/sum/query/Query.scala @@ -1,624 +1,102 @@ package org.rosi_project.model_management.sum.query import scroll.internal.Compartment -import org.rosi_project.model_management.core.RsumCompartment -import org.rosi_project.model_management.sum.compartments.IRelationCompartment -import org.rosi_project.model_management.sum.roles.IRelationRole -import org.rosi_project.model_management.util.query.ModelJoinCreator -import org.rosi_project.model_sync.model_join.representation.grammar.CompoundKeepBuilder /** - * Special query implementation for the query interface that works on the RSUM. + * Describes the abstract query compartment with the roles that each query must implement. */ -class Query(_name: String) extends AQuery(_name) { +abstract class Query(val name: String) extends Compartment { - RsumCompartment.combine(this) + def deleteQueryResults(): Unit + def deleteQueryObjects(): Unit - private var queryRelRoles: Set[QueryRelObject] = Set.empty - private var queryNatRoles: Set[QueryNatObject] = Set.empty - - private var queryRelResults: Set[QueryRelResult] = Set.empty - private var queryNatResults: Set[QueryNatResult] = Set.empty - - private def getQueryNatRole(obj: Object): QueryNatObject = { - //queryNatRoles.filter(+_ == +obj).foreach(return _) - queryNatRoles.foreach(q => { - if (+obj == +q) { - return q - } - }) - return null - } - - private def getQueryRelRole(obj: Object): QueryRelObject = { - //queryRelRoles.filter(+_ == +obj).foreach(return _) - queryRelRoles.foreach(q => { - if (+obj == +q) { - return q - } - }) - return null - } - - private def getNatResultRole(player: Object, queryObject: QueryNatObject): QueryNatResult = { - //queryNatResults.filter(r => r.connectedQueryObject == queryObject && +player == +r).foreach(return _) - queryNatResults.foreach(r => { - if (r.connectedQueryObject == queryObject && +player == +r) { - return r - } - }) - return null - } - - def generateModelJoinFromQuery(): String = { - val creator = new ModelJoinCreator - /*val start = queryNatRoles.head - val playerStart: Object = start.player.right.get - playerStart.getClass.getPackage.getName - playerStart.getClass.getSimpleName*/ - var relHelper: Set[ModelJoinContainer] = Set.empty - var relNames: Set[String] = Set.empty - var sources: Set[String] = Set.empty - var targets: Set[String] = Set.empty - - var names: Set[String] = Set.empty - var connected: Map[String, Object] = Map() - - queryNatRoles.foreach(q => { - val playerStart: Object = q.player.right.get - println(playerStart.getClass.getName) - names += playerStart.getClass.getName - }) - queryRelRoles.foreach(q => { - val playerStart: Object = q.player.right.get - val playerSource: Object = q.source.player.right.get - val playerTarget: Object = q.target.player.right.get - println("+" + playerStart.getClass.getName) - println(playerSource.getClass.getName) - println(playerTarget.getClass.getName) - if (!relNames.contains(playerStart.getClass.getName)) { - relNames += playerStart.getClass.getName - sources += playerSource.getClass.getName - targets += playerTarget.getClass.getName - relHelper += new ModelJoinContainer(playerStart.getClass.getName, playerSource.getClass.getName, playerTarget.getClass.getName) - if (!connected.contains(playerSource.getClass.getName)) { - connected += (playerSource.getClass.getName -> creator.createNaturalJoin(playerSource.getClass.getName)) - } - connected += (playerTarget.getClass.getName -> creator.createOutgoingReference(playerTarget.getClass.getName, playerStart.getClass.getSimpleName).asInstanceOf[Object]) - } - }) - - val start = sources.filter(!targets.contains(_)).head - val builder = creator.createNaturalJoin(start) - relHelper.filter(_.source == start).foreach(r => { - - }) - "" - } - - def deleteQueryResults(): Unit = { - queryRelResults.foreach(_.remove()) - queryRelResults = Set.empty - queryNatResults.foreach(_.remove()) - queryNatResults = Set.empty - } - - def deleteQueryObjects(): Unit = { - queryRelRoles.foreach(_.remove()) - queryRelRoles = Set.empty - queryNatRoles.foreach(_.remove()) - queryNatRoles = Set.empty - } - - def isQueryCorrect(): Boolean = { - //check if the query is correct and does not contain more close islands - queryRelRoles.foreach(qo => { - return qo.overallConnectionUnit() == (queryRelRoles.size + queryNatRoles.size) - }) - queryNatRoles.foreach(qo => { - return qo.overallConnectionUnit() == (queryRelRoles.size + queryNatRoles.size) - }) - return true - } - - def removeQueryRole(role: AQuery#QueryObject): Unit = { - if (role.isInstanceOf[QueryNatObject]) { - queryNatRoles -= role.asInstanceOf[QueryNatObject] - } - if (role.isInstanceOf[QueryRelObject]) { - queryRelRoles -= role.asInstanceOf[QueryRelObject] - } - } - - def addQueryRole(obj: Object): AQuery#QueryObject = { - val relResult = getQueryRelRole(obj) - if (relResult != null) return relResult - val natResult = getQueryNatRole(obj) - if (natResult != null) return natResult - //get player - val playerObj = obj.player.getOrElse(obj) - //difference between relation and natural - if (playerObj.isInstanceOf[IRelationCompartment]) { - val refComp = playerObj.asInstanceOf[IRelationCompartment] - this.combine(refComp) - val sourceRole: QueryNatObject = getQueryNatRole(refComp.getSource()) - val targetRole: QueryNatObject = getQueryNatRole(refComp.getTarget()) - if (sourceRole == null || targetRole == null) { - println("--- Error: Relational compartment can only be added if source and target are added before") - return null - } - val newRole = new QueryRelObject(sourceRole, targetRole) - queryRelRoles += newRole - playerObj play newRole - return newRole - } else { - val newRole = new QueryNatObject() - queryNatRoles += newRole - playerObj play newRole - return newRole - } - } + /** + * Create ModelJoin syntax for views. + */ + def generateModelJoinFromQuery(fileName: String): String - def runQuery(): Set[Set[Object]] = { - //delete at the end - var forDeletionQueryResults: Set[QueryNatResult] = Set.empty - //immediate values - var deleteNatResults: Set[QueryNatResult] = Set.empty - var doSomething = true - //output value - var result: Set[Set[Object]] = Set.empty - - //###add query results to all elements that can be results because of connection properties - //...iterate over non negated query relations and add result roles if necessary - queryRelRoles.filter(!_.isNegated()).foreach(queryRel => { - val playerQueryRel: IRelationCompartment = queryRel.player.right.get.asInstanceOf[IRelationCompartment] - RsumCompartment.getRelations().foreach(rsumRel => { - if (playerQueryRel.getClass.isInstance(rsumRel)) { - //search if their are existing results if not create new ones - val rsumNatSource: Object = rsumRel.getSource().player.right.get - val rsumNatTarget: Object = rsumRel.getTarget().player.right.get - var queryNatResultSource: QueryNatResult = getNatResultRole(rsumNatSource, queryRel.source) - if (queryNatResultSource == null) { - queryNatResultSource = new QueryNatResult(queryRel.source) - rsumNatSource play queryNatResultSource - queryNatResults += queryNatResultSource - } - var queryNatResultTarget: QueryNatResult = getNatResultRole(rsumNatTarget, queryRel.target) - if (queryNatResultTarget == null) { - queryNatResultTarget = new QueryNatResult(queryRel.target) - rsumNatTarget play queryNatResultTarget - queryNatResults += queryNatResultTarget - } - //connect them in a new relation result - val queryRelResult: QueryRelResult = new QueryRelResult(queryRel, queryNatResultSource, queryNatResultTarget, false) - rsumRel play queryRelResult - queryRelResults += queryRelResult - - //if transitive add new relation to separate list to add them at the end - if (queryRel.isTransitive) { - //set only source new because target must be old one, transitive query means always target same - queryNatResultSource = getNatResultRole(rsumNatSource, queryRel.target) - if (queryNatResultSource == null) { - queryNatResultSource = new QueryNatResult(queryRel.target) - rsumNatSource play queryNatResultSource - queryNatResults += queryNatResultSource - } - val transitiveQueryRelResult: QueryRelResult = new QueryRelResult(queryRel, queryNatResultSource, queryNatResultTarget, true) - rsumRel play transitiveQueryRelResult - queryRelResults += transitiveQueryRelResult - } - } - }) - }) - - //...iterate over negated related roles and search all opposite naturals that do not implement this rel - queryRelRoles.filter(_.isNegated()).foreach(queryRel => { - val playerQueryRel: IRelationCompartment = queryRel.player.right.get.asInstanceOf[IRelationCompartment] - var playerQueryNat: Object = null - if (queryRel.source.negated) { - playerQueryNat = playerQueryRel.getSource.player.right.get - } else { - playerQueryNat = playerQueryRel.getTarget.player.right.get - } - //source or target negated, search for negated class - RsumCompartment.getNaturals().foreach(rsumNat => { - if (playerQueryNat.getClass.isInstance(rsumNat)) - { - var goodElement: Boolean = true; - //filtered roles of the natural type - var roles: Set[IRelationRole] = Set.empty - if (queryRel.source.negated) { - roles = rsumNat.roles().filter(_.isInstanceOf[IRelationCompartment#ITarget]).toSet.asInstanceOf[Set[IRelationRole]] - } else { - roles = rsumNat.roles().filter(_.isInstanceOf[IRelationCompartment#ISource]).toSet.asInstanceOf[Set[IRelationRole]] - } - //if we find a role that works than we can not add this natural to the results - roles.foreach(r => { - val outerRelComp = r.getOuterCompartment() - //println("COMP: " + outerRelComp + " " + playerQueryRel + " " + playerQueryRel.getClass.isInstance(outerRelComp)) - if (playerQueryRel.getClass.isInstance(outerRelComp)) { - //we can not use this element - goodElement = false - } - }) - //if we do not find a compatible element in this natural role we can add it - if (goodElement) { - var queryNatRole: QueryNatObject = null - if (queryRel.source.negated) { - queryNatRole = queryRel.target - } else { - queryNatRole = queryRel.source - } - var queryNatResult: QueryNatResult = getNatResultRole(rsumNat, queryNatRole) - if (queryNatResult == null) { - queryNatResult = new QueryNatResult(queryNatRole) - rsumNat play queryNatResult - queryNatResults += queryNatResult - } - if (queryRel.source.negated) { - queryNatResult.increaseTargetNegated() - } else { - queryNatResult.increaseSourceNegated() - } - } - } - }) - }) - - //...iterate over all query naturals without a connection and add result roles if necessary - queryNatRoles.filter(_.connectionSize == 0).foreach(queryNat => { - //connected one are visited in the part before - val playerQueryNat: Object = queryNat.player.right.get - RsumCompartment.getNaturals().foreach(rsumNat => { - if (playerQueryNat.isInstanceOf[QueryHelper]) { - if (playerQueryNat.equals(rsumNat)) { - var queryNatResult: QueryNatResult = getNatResultRole(rsumNat, queryNat) - if (queryNatResult == null) { - queryNatResult = new QueryNatResult(queryNat) - rsumNat play queryNatResult - queryNatResults += queryNatResult - } - } - } else { - if (playerQueryNat.getClass.isInstance(rsumNat)) { - var queryNatResult: QueryNatResult = getNatResultRole(rsumNat, queryNat) - if (queryNatResult == null) { - queryNatResult = new QueryNatResult(queryNat) - rsumNat play queryNatResult - queryNatResults += queryNatResult - } - } - } - }) - }) - - //###proof correctness of results - //...proof attribute correctness once - queryNatResults.filter(!_.proofAttributes).foreach(deleteNatResults += _) - //delete them - deleteNatResults.foreach(queryResultNat => { - queryNatResults -= queryResultNat - forDeletionQueryResults += queryResultNat - queryResultNat.removeConnections() - }) - - //...proof the correctness of the query results and delete non correct ones - while (doSomething) { - deleteNatResults = Set.empty - //proof the connection correctness - queryNatResults.filter(!_.proofConnections).foreach(deleteNatResults += _) - - //do as long as everything is correct - doSomething = !deleteNatResults.isEmpty - //delete them - deleteNatResults.foreach(queryResultNat => { - queryNatResults -= queryResultNat - forDeletionQueryResults += queryResultNat - queryResultNat.removeConnections() - }) - } - - //###make good outputs from the current query results - //...only correct elements should now play result roles and are in the list - var combinedResult: Set[QueryCombinedResult] = queryRelResults.filter(!_.transitive).map(_.createCombinedResult()) - - //...combine the result elements to good output units - doSomething = true - while (doSomething) { - doSomething = false - combinedResult.foreach(combined => { - queryRelResults.foreach(rel => { - if (rel.source == combined.target && !combined.contains(rel.target)) { - //add in the back - combined.addBack(rel.target) - doSomething = true - } else { - if (rel.target == combined.source && !combined.contains(rel.source)) { - //add in the front - combined.addFront(rel.source) - doSomething = true - } - } - }) - }) - //delete duplicated elements - combinedResult = combinedResult.groupBy(_.getBetween).map(_._2.head).toSet - //combinedResult.distinct - } - - //create only results with tuples - /*queryRelResults.foreach(rel => { - var rSet: Set[Object] = Set.empty - if (rel.source.connectedQueryObject.returned) { - rSet += rel.source.player.right.get - } - if (rel.target.connectedQueryObject.returned) { - rSet += rel.target.player.right.get - } - result += rSet - })*/ - - //...bring the output format to the reals one - combinedResult.foreach(combined => { - var rSet: Set[Object] = Set.empty - combined.getBetween.foreach(queryNat => { - if (queryNat.connectedQueryObject.returned) { - rSet += queryNat.player.right.get - } - }) - result += rSet - }) - - //...add also single results - queryNatResults.foreach(queryResultNat => { - if (!queryResultNat.isConnected() && queryResultNat.connectedQueryObject.returned) { - result += Set(queryResultNat.player.right.get) - } - }) - - //...delete now really all not needed result roles - forDeletionQueryResults.foreach(_.remove()) - - return result - } + /** + * Add a query role to the underlying object. + */ + def addQueryRole(obj: Object): Query#QueryObject - override def toString(): String = name + ": " + isQueryCorrect + " Rs: " + queryNatRoles + " " + queryRelRoles + /** + * Remove a query role from the query. + */ + def removeQueryRole(role: Query#QueryObject): Unit /** - * Query object specialized for naturals in the RSUM. + * Proof if the query has a correct form. + * Not more than one connection island. */ - class QueryNatObject() extends QueryObject() { - private var sourceRelations: Set[QueryRelObject] = Set.empty - private var targetRelations: Set[QueryRelObject] = Set.empty - - def addSourceRelation(rel: QueryRelObject): Unit = { - sourceRelations += rel - } - - def removeSourceRelation(rel: QueryRelObject): Unit = { - sourceRelations -= rel - } - - def getSourceRelationsSize(): Int = sourceRelations.filter(!_.isNegated()).map(_.multiTarget).sum //sum up multi value not use size - def getNegatedSourceRelationsSize(): Int = sourceRelations.filter(_.isNegated()).size - - def addTargetRelation(rel: QueryRelObject): Unit = { - targetRelations += rel - } - - def removeTargetRelation(rel: QueryRelObject): Unit = { - targetRelations -= rel - } - - def getTargetRelationsSize(): Int = targetRelations.filter(!_.isNegated()).map(_.multiSource).sum - def getNegatedTargetRelationsSize(): Int = targetRelations.filter(_.isNegated()).size - - def connectionSize(): Int = targetRelations.size + sourceRelations.size - - def overallConnectionUnit(): Int = { - var visitedRel: Set[QueryRelObject] = Set.empty - var visitedNat: Set[QueryNatObject] = Set(this) - var unVisitedRel: Set[QueryRelObject] = targetRelations ++ sourceRelations - var unVisitedNat: Set[QueryNatObject] = Set.empty - while (!unVisitedRel.isEmpty || !unVisitedNat.isEmpty) { - //run over all unvisited relations - unVisitedRel.foreach(rel => { - if (!visitedNat.contains(rel.source)) - unVisitedNat += rel.source - if (!visitedNat.contains(rel.target)) - unVisitedNat += rel.target - }) - visitedRel ++= unVisitedRel - unVisitedRel = Set.empty - //run over all unvisited naturals - unVisitedNat.foreach(nat => { - nat.sourceRelations.filter(!visitedRel.contains(_)).foreach(unVisitedRel += _) - nat.targetRelations.filter(!visitedRel.contains(_)).foreach(unVisitedRel += _) - }) - visitedNat ++= unVisitedNat - unVisitedNat = Set.empty - } - return visitedRel.size + visitedNat.size - } - - override def toString: String = "QON: " + label + " C: " + connectionSize - } - + def isQueryCorrect(): Boolean + /** - * Query object specialized for relational compartments in the RSUM. + * Running the query and getting a set of sets of result objects. */ - class QueryRelObject(val source: QueryNatObject, val target: QueryNatObject) extends QueryObject() { - - def isNegated(): Boolean = source.negated || target.negated - def isTransitive(): Boolean = target.transitive - def multiTarget(): Int = target.multi - def multiSource(): Int = source.multi - - source.addSourceRelation(this) - target.addTargetRelation(this) - - def overallConnectionUnit(): Int = source.overallConnectionUnit() - - override def toString: String = "QOR: " + source.label + "-" + target.label - } - + def runQuery(): Set[Set[Object]] + /** - * Query result roles for natural query roles. + * Abstract query object to create the query from example. */ - class QueryNatResult(val connectedQueryObject: QueryNatObject) extends QueryResult(connectedQueryObject) { - private var sourceRelations: Set[QueryRelResult] = Set.empty - private var targetRelations: Set[QueryRelResult] = Set.empty - - private var negatedSources: Int = 0 - private var negatedTargets: Int = 0 - - def increaseSourceNegated(): Unit = { negatedSources += 1 } - def decreaseSourceNegated(): Unit = { negatedSources -= 1 } - - def increaseTargetNegated(): Unit = { negatedTargets += 1 } - def decreaseTargetNegated(): Unit = { negatedTargets -= 1 } + abstract class QueryObject() { /** - * Proof if the player has all the necessary attributes with its values. + * Label to identify a query object. */ - def proofAttributes(): Boolean = { - val player: Object = this.player.right.get - var returnValue = true - connectedQueryObject.getAttributeFilters.foreach(a => { - try { - //player.getClass.getMethods.foreach(f => println(f.toString)) - //println(player.getClass.getMethod("name").getReturnType) //getName - val met = player.getClass.getMethod(a.attributeName) - val result: String = met.invoke(player).asInstanceOf[String] - a.checking match { - case CheckingOption.equalsCheck => if (result != a.value) returnValue = false - case CheckingOption.biggerThan => if (result <= a.value) returnValue = false - case CheckingOption.smallerThan => if (result >= a.value) returnValue = false - case _ => - } - } catch { - case _: Throwable => { - println("!!! No attribute with this name!!!") - return false - } - } - }) - return returnValue - } + var label: String = "" /** - * Proof if the number of connections is equals to the related query object. + * Describes is necessary to be in the results or to be not. */ - def proofConnections(): Boolean = { - //TODO: proof also the number of types and not only the numbers - //println("S: " + _connectedQueryObject.getSourceRelationsSize() + " T: " + _connectedQueryObject.getTargetRelationsSize() + " NS: " + _connectedQueryObject.getNegatedSourceRelationsSize() + " NT: " + _connectedQueryObject.getNegatedTargetRelationsSize() + " Con: " + _connectedQueryObject) - //println("S: " + getSourceRelationsSize() + " T: " + getTargetRelationsSize() + " NS: " + negatedSources + " NT: " + negatedTargets + " This: " + this) - if (getSourceRelationsSize >= connectedQueryObject.getSourceRelationsSize() - && getTargetRelationsSize >= connectedQueryObject.getTargetRelationsSize() - && negatedSources >= connectedQueryObject.getNegatedSourceRelationsSize() - && negatedTargets >= connectedQueryObject.getNegatedTargetRelationsSize()) { - return true - } - return false - } + var negated: Boolean = false - def addSourceRelation(rel: QueryRelResult): Unit = { - sourceRelations += rel - } + /** + * Important to describe if a transitive closure should be created. + */ + var transitive: Boolean = false - def removeSourceRelation(rel: QueryRelResult): Unit = { - sourceRelations -= rel - } + /** + * Describes how often a connection must exists. + */ + var multi: Int = 1 - def getSourceRelationsSize(): Int = sourceRelations.size + /** + * Describes if the elements should be returned in the results or not. + */ + var returned: Boolean = true - def addTargetRelation(rel: QueryRelResult): Unit = { - targetRelations += rel + private var attributeFilters: Set[AttributeFilter] = Set.empty + + /** + * Create and add an attribute filter object to a query object. + */ + def addAttributeFilter(attributeName: String, value: String, bigger: CheckingOption.Value): Boolean = { + if (attributeName == null || attributeName == "" || + bigger == null || value == null || value == "") { + return false + } + attributeFilters += new AttributeFilter(attributeName, value, bigger) + return true } - def removeTargetRelation(rel: QueryRelResult): Unit = { - targetRelations -= rel - } + def getAttributeFilters(): Set[AttributeFilter] = attributeFilters - def getTargetRelationsSize(): Int = targetRelations.size - - def isConnected(): Boolean = (targetRelations.size + sourceRelations.size) > 0 + def overallConnectionUnit(): Int - def removeConnections(): Unit = { - sourceRelations.foreach(rel => { - rel.target.removeTargetRelation(rel) - queryRelResults -= rel - rel.remove() - }) - targetRelations.foreach(rel => { - rel.source.removeSourceRelation(rel) - queryRelResults -= rel - rel.remove() - }) - sourceRelations = Set.empty - targetRelations = Set.empty - negatedSources = 0 - negatedTargets = 0 - } - } + override def toString(): String = "QO: " + label + } /** - * Query result roles for relation query roles. + * Abstract query results that each element which matches the query gets. */ - class QueryRelResult(val connectedQueryObject: QueryRelObject, val source: QueryNatResult, val target: QueryNatResult, val transitive: Boolean) extends QueryResult(connectedQueryObject) { - //only add this relation to the connect results if it is not transitive - if (!transitive) { - source.addSourceRelation(this) - target.addTargetRelation(this) - } + abstract class QueryResult(val matchedQueryObject: QueryObject) { - /** - * Create a new combined result which is a copy of this one. - */ - def createCombinedResult(): QueryCombinedResult = new QueryCombinedResult(source, target) + override def toString(): String = "QR: (" + this.player.right.get.toString() + " " + matchedQueryObject + ")" } /** - * Helper class to connect the results to a chain. + * Should collect information about the attributes a query element must have */ - class QueryCombinedResult(var source: QueryNatResult, var target: QueryNatResult) { - - //list of all query results that are connected - private var between: Seq[QueryNatResult] = Seq(source, target) - - def getBetween(): Seq[QueryNatResult] = between - - def addFront(newIn: QueryNatResult): Unit = { - between = newIn +: between - source = newIn - } - - def addBack(newIn: QueryNatResult): Unit = { - between = between :+ newIn - target = newIn - } - - def contains(result: QueryNatResult): Boolean = ( between.contains(result) ) - - private def getSize(): Int = between.size - - protected def canEqual(other: Any): Boolean = other.isInstanceOf[QueryCombinedResult] - - override def equals(other: Any): Boolean = other match { - case that: QueryCombinedResult => { - if (that canEqual this) { - between.foreach(b => { - if (!that.contains(b)) - return false - }) - return that.getSize == this.getSize() - } else { - return false - } - } - case _ => return false - } - - override def toString(): String = "QCR: (" + between + ")" - } + class AttributeFilter(val attributeName: String, val value: String, val checking: CheckingOption.Value) {} } \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_management/sum/query/IQueryViewCompartment.scala b/src/main/scala/org/rosi_project/model_management/sum/query/QueryFactory.scala similarity index 75% rename from src/main/scala/org/rosi_project/model_management/sum/query/IQueryViewCompartment.scala rename to src/main/scala/org/rosi_project/model_management/sum/query/QueryFactory.scala index 462693e..0f9b590 100644 --- a/src/main/scala/org/rosi_project/model_management/sum/query/IQueryViewCompartment.scala +++ b/src/main/scala/org/rosi_project/model_management/sum/query/QueryFactory.scala @@ -6,20 +6,20 @@ import scala.collection.mutable.Set import org.rosi_project.model_management.core.RsumCompartment import org.rosi_project.model_management.sum.compartments.IRelationCompartment -trait IQueryViewCompartment extends Compartment { +trait QueryFactory extends Compartment { private var name: String = "" - private var query: Query = null + private var query: RsumQuery = null RsumCompartment.combine(this) protected def init(n: String): Unit = { name = n - query = new Query(n) + query = new RsumQuery(n) } - private var naturalRoles = Set[AQueryViewRole]() - private var relationalRoles = Set[AQueryViewRole]() + private var naturalRoles = Set[QueryFactoryElement]() + private var relationalRoles = Set[QueryFactoryElement]() def getName(): String = name @@ -29,8 +29,8 @@ trait IQueryViewCompartment extends Compartment { * Get a map with the simple names of all elements * and the connected elements in the view. */ - def getMapOfElements(): Map[String, Set[AQueryViewRole]] = { - var result: Map[String, Set[AQueryViewRole]] = Map.empty + def getMapOfElements(): Map[String, Set[QueryFactoryElement]] = { + var result: Map[String, Set[QueryFactoryElement]] = Map.empty naturalRoles.foreach(n => { if (result.contains(n.getClass.getSimpleName)) { result(n.getClass.getSimpleName) += n @@ -44,8 +44,8 @@ trait IQueryViewCompartment extends Compartment { /** * Get all elements with the specific simple name. */ - def getElementsWithClassName(s: String): Set[AQueryViewRole] = { - var result: Set[AQueryViewRole] = Set.empty + def getElementsWithClassName(s: String): Set[QueryFactoryElement] = { + var result: Set[QueryFactoryElement] = Set.empty naturalRoles.foreach(n => { if (n.getClass.getSimpleName == s) { result += n @@ -57,7 +57,7 @@ trait IQueryViewCompartment extends Compartment { /** * Get all elements with the same type from the view. */ - def getElementsWithExample[A <: AQueryViewRole](a: A): Set[A] = { + def getElementsWithExample[A <: QueryFactoryElement](a: A): Set[A] = { var result: Set[A] = Set.empty naturalRoles.foreach(n => { if (n.getClass.getName == a.getClass.getName) { @@ -67,7 +67,7 @@ trait IQueryViewCompartment extends Compartment { result } - protected def getRoleFromList(classname: Object): AQueryViewRole = { + protected def getRoleFromList(classname: Object): QueryFactoryElement = { relationalRoles.foreach { r => if (+r == +classname) { return r @@ -97,13 +97,13 @@ trait IQueryViewCompartment extends Compartment { println("-------------------------------------------------------------------") } - def getAllViewElements(): Set[AQueryViewRole] = naturalRoles + def getAllViewElements(): Set[QueryFactoryElement] = naturalRoles - def containsRole(role: AQueryViewRole): Boolean = naturalRoles.contains(role) + def containsRole(role: QueryFactoryElement): Boolean = naturalRoles.contains(role) - abstract class AQueryViewRole { + abstract class QueryFactoryElement { - protected var connected: AQuery#QueryObject = null + protected var connected: Query#QueryObject = null initializeElement() @@ -111,7 +111,7 @@ trait IQueryViewCompartment extends Compartment { protected def getCreationObject(): Object - def getQueryObject: AQuery#QueryObject = connected + def getQueryObject: Query#QueryObject = connected private def initializeElement(): Unit = { val obj = getCreationObject diff --git a/src/main/scala/org/rosi_project/model_management/sum/query/RsumQuery.scala b/src/main/scala/org/rosi_project/model_management/sum/query/RsumQuery.scala new file mode 100644 index 0000000..487b2eb --- /dev/null +++ b/src/main/scala/org/rosi_project/model_management/sum/query/RsumQuery.scala @@ -0,0 +1,679 @@ +package org.rosi_project.model_management.sum.query + +import scroll.internal.Compartment +import org.rosi_project.model_management.core.RsumCompartment +import org.rosi_project.model_management.sum.compartments.IRelationCompartment +import org.rosi_project.model_management.sum.roles.IRelationRole +import org.rosi_project.model_management.util.query.ModelJoinCreator +import org.rosi_project.model_sync.model_join.representation.grammar.CompoundKeepBuilder +import util.control.Breaks._ + +/** + * Special query implementation for the query interface that works on the RSUM. + */ +class RsumQuery(_name: String) extends Query(_name) { + + RsumCompartment.combine(this) + + private var queryRelRoles: Set[RelationalQueryObject] = Set.empty + private var queryNatRoles: Set[NaturalQueryObject] = Set.empty + + private var queryRelResults: Set[RelationalQueryResult] = Set.empty + private var queryNatResults: Set[NaturalQueryResult] = Set.empty + + private def getQueryNatRole(obj: Object): NaturalQueryObject = { + //queryNatRoles.filter(+_ == +obj).foreach(return _) + queryNatRoles.foreach(q => { + if (+obj == +q) { + return q + } + }) + return null + } + + private def getQueryRelRole(obj: Object): RelationalQueryObject = { + //queryRelRoles.filter(+_ == +obj).foreach(return _) + queryRelRoles.foreach(q => { + if (+obj == +q) { + return q + } + }) + return null + } + + private def getNatResultRole(player: Object, queryObject: NaturalQueryObject): NaturalQueryResult = { + //queryNatResults.filter(r => r.connectedQueryObject == queryObject && +player == +r).foreach(return _) + queryNatResults.foreach(r => { + if (r.connectedQueryObject == queryObject && +player == +r) { + return r + } + }) + return null + } + + def generateModelJoinFromQuery(fileName: String): String = { + val creator = new ModelJoinCreator + var relHelper: Set[ModelJoinContainer] = Set.empty + var relNames: Set[String] = Set.empty + + queryRelRoles.filter(r => r.isReturned() && !r.isNegated).foreach(q => { + val playerStart: Object = q.player.right.get + val playerSource: Object = q.source.player.right.get + val playerTarget: Object = q.target.player.right.get + println("+" + playerStart.getClass.getName + " " + playerSource.getClass.getName + " " + playerTarget.getClass.getName) + if (!relNames.contains(playerStart.getClass.getName)) { + var nameChange = playerStart.getClass.getSimpleName + if (nameChange.startsWith(playerSource.getClass.getSimpleName)) { + nameChange = nameChange.replaceFirst(playerSource.getClass.getSimpleName, "") + } + if (nameChange.startsWith(playerSource.getClass.getSuperclass.getSimpleName)) { + nameChange = nameChange.replaceFirst(playerSource.getClass.getSuperclass.getSimpleName, "") + } + if (nameChange.startsWith(playerSource.getClass.getSuperclass.getSuperclass.getSimpleName)) { + nameChange = nameChange.replaceFirst(playerSource.getClass.getSuperclass.getSuperclass.getSimpleName, "") + } + nameChange = Character.toLowerCase(nameChange.charAt(0)) + nameChange.substring(1); + nameChange = nameChange.replaceFirst(playerTarget.getClass.getSimpleName, "") + //create join and reference builder + val sourceMj = creator.createNaturalJoin(playerSource.getClass.getName) + val targetMj = creator.createOutgoingReference(playerSource.getClass.getName, playerTarget.getClass.getName, nameChange) + + val mjContainer = new ModelJoinContainer(nameChange, playerSource.getClass.getName) + playerSource.getClass.getMethods.filter(m => m.getParameterCount == 0 && m.getDeclaringClass.getName != "java.lang.Object") + .foreach(m => { + if (m.getName != "toString" && !m.getName.startsWith("get")) { + creator.createAttribute(sourceMj, playerSource.getClass.getName, m.getName) + } + }) + if (playerSource.getClass.getName != playerTarget.getClass.getName) { + playerTarget.getClass.getMethods.filter(m => m.getParameterCount == 0 && m.getDeclaringClass.getName != "java.lang.Object") + .foreach(m => { + if (m.getName != "toString" && !m.getName.startsWith("get")) { + creator.createAttribute(targetMj, playerTarget.getClass.getName, m.getName) + } + }) + } + + //unbuild and undone target and source + val buildTarget = creator.buildExpression(targetMj) + creator.addKeepExpression(sourceMj, buildTarget) + val buildSource = creator.done(sourceMj) + + mjContainer.connect += (playerSource.getClass.getName -> buildSource) + if (playerSource.getClass.getName != playerTarget.getClass.getName) { + mjContainer.connect += (playerTarget.getClass.getName -> buildTarget) + } + relHelper += mjContainer + relNames += playerStart.getClass.getName + } + }) + + if (relHelper.size > 0) { + var run = relHelper.size > 1 + while (run) { + var other: ModelJoinContainer = null + breakable { + relHelper.foreach(a => { + relHelper.foreach(b => { + if (a != b && a.isComparable(b)) { + other = a.concat(b) + break + } + }) + }) + } + run = relHelper.size > 1 && other != null + if (other != null) { + relHelper -= other + } + } + relHelper.foreach(r => { + creator.createFile(r.connect.get(r.source).get, fileName + ".modeljoin") + }) + } else { + queryNatRoles.filter(r => r.returned && !r.negated).foreach(q => { + val playerStart: Object = q.player.right.get + var clsName = playerStart.getClass.getName + if (playerStart.isInstanceOf[QueryHelper]) { + clsName = playerStart.getClass.getSuperclass.getName + } + println("-" + clsName) + val nj = creator.createNaturalJoin(clsName) + playerStart.getClass.getMethods.filter(m => m.getParameterCount == 0 && m.getDeclaringClass.getName != "java.lang.Object") + .foreach(m => { + if (m.getName != "toString" && !m.getName.startsWith("get")) { + creator.createAttribute(nj, clsName, m.getName) + } + }) + creator.createFile(creator.done(nj), fileName + ".modeljoin") + }) + } + "" + } + + def deleteQueryResults(): Unit = { + queryRelResults.foreach(_.remove()) + queryRelResults = Set.empty + queryNatResults.foreach(_.remove()) + queryNatResults = Set.empty + } + + def deleteQueryObjects(): Unit = { + queryRelRoles.foreach(_.remove()) + queryRelRoles = Set.empty + queryNatRoles.foreach(_.remove()) + queryNatRoles = Set.empty + } + + def isQueryCorrect(): Boolean = { + //check if the query is correct and does not contain more close islands + queryRelRoles.foreach(qo => { + return qo.overallConnectionUnit() == (queryRelRoles.size + queryNatRoles.size) + }) + queryNatRoles.foreach(qo => { + return qo.overallConnectionUnit() == (queryRelRoles.size + queryNatRoles.size) + }) + return true + } + + def removeQueryRole(role: Query#QueryObject): Unit = { + if (role.isInstanceOf[NaturalQueryObject]) { + queryNatRoles -= role.asInstanceOf[NaturalQueryObject] + } + if (role.isInstanceOf[RelationalQueryObject]) { + queryRelRoles -= role.asInstanceOf[RelationalQueryObject] + } + } + + def addQueryRole(obj: Object): Query#QueryObject = { + val relResult = getQueryRelRole(obj) + if (relResult != null) return relResult + val natResult = getQueryNatRole(obj) + if (natResult != null) return natResult + //get player + val playerObj = obj.player.getOrElse(obj) + //difference between relation and natural + if (playerObj.isInstanceOf[IRelationCompartment]) { + val refComp = playerObj.asInstanceOf[IRelationCompartment] + this.combine(refComp) + val sourceRole: NaturalQueryObject = getQueryNatRole(refComp.getSource()) + val targetRole: NaturalQueryObject = getQueryNatRole(refComp.getTarget()) + if (sourceRole == null || targetRole == null) { + println("--- Error: Relational compartment can only be added if source and target are added before") + return null + } + val newRole = new RelationalQueryObject(sourceRole, targetRole) + queryRelRoles += newRole + playerObj play newRole + return newRole + } else { + val newRole = new NaturalQueryObject() + queryNatRoles += newRole + playerObj play newRole + return newRole + } + } + + def runQuery(): Set[Set[Object]] = { + //delete at the end + var forDeletionQueryResults: Set[NaturalQueryResult] = Set.empty + //immediate values + var deleteNatResults: Set[NaturalQueryResult] = Set.empty + var doSomething = true + //output value + var result: Set[Set[Object]] = Set.empty + + //###add query results to all elements that can be results because of connection properties + //...iterate over non negated query relations and add result roles if necessary + queryRelRoles.filter(!_.isNegated()).foreach(queryRel => { + val playerQueryRel: IRelationCompartment = queryRel.player.right.get.asInstanceOf[IRelationCompartment] + RsumCompartment.getRelations().foreach(rsumRel => { + if (playerQueryRel.getClass.isInstance(rsumRel)) { + //search if their are existing results if not create new ones + val rsumNatSource: Object = rsumRel.getSource().player.right.get + val rsumNatTarget: Object = rsumRel.getTarget().player.right.get + var queryNatResultSource: NaturalQueryResult = getNatResultRole(rsumNatSource, queryRel.source) + if (queryNatResultSource == null) { + queryNatResultSource = new NaturalQueryResult(queryRel.source) + rsumNatSource play queryNatResultSource + queryNatResults += queryNatResultSource + } + var queryNatResultTarget: NaturalQueryResult = getNatResultRole(rsumNatTarget, queryRel.target) + if (queryNatResultTarget == null) { + queryNatResultTarget = new NaturalQueryResult(queryRel.target) + rsumNatTarget play queryNatResultTarget + queryNatResults += queryNatResultTarget + } + //connect them in a new relation result + val queryRelResult: RelationalQueryResult = new RelationalQueryResult(queryRel, queryNatResultSource, queryNatResultTarget, false) + rsumRel play queryRelResult + queryRelResults += queryRelResult + + //if transitive add new relation to separate list to add them at the end + if (queryRel.isTransitive) { + //set only source new because target must be old one, transitive query means always target same + queryNatResultSource = getNatResultRole(rsumNatSource, queryRel.target) + if (queryNatResultSource == null) { + queryNatResultSource = new NaturalQueryResult(queryRel.target) + rsumNatSource play queryNatResultSource + queryNatResults += queryNatResultSource + } + val transitiveQueryRelResult: RelationalQueryResult = new RelationalQueryResult(queryRel, queryNatResultSource, queryNatResultTarget, true) + rsumRel play transitiveQueryRelResult + queryRelResults += transitiveQueryRelResult + } + } + }) + }) + + //...iterate over negated related roles and search all opposite naturals that do not implement this rel + queryRelRoles.filter(_.isNegated()).foreach(queryRel => { + val playerQueryRel: IRelationCompartment = queryRel.player.right.get.asInstanceOf[IRelationCompartment] + var playerQueryNat: Object = null + if (queryRel.source.negated) { + playerQueryNat = playerQueryRel.getSource.player.right.get + } else { + playerQueryNat = playerQueryRel.getTarget.player.right.get + } + //source or target negated, search for negated class + RsumCompartment.getNaturals().foreach(rsumNat => { + if (playerQueryNat.getClass.isInstance(rsumNat)) { + var goodElement: Boolean = true; + //filtered roles of the natural type + var roles: Set[IRelationRole] = Set.empty + if (queryRel.source.negated) { + roles = rsumNat.roles().filter(_.isInstanceOf[IRelationCompartment#ITarget]).toSet.asInstanceOf[Set[IRelationRole]] + } else { + roles = rsumNat.roles().filter(_.isInstanceOf[IRelationCompartment#ISource]).toSet.asInstanceOf[Set[IRelationRole]] + } + //if we find a role that works than we can not add this natural to the results + roles.foreach(r => { + val outerRelComp = r.getOuterCompartment() + //println("COMP: " + outerRelComp + " " + playerQueryRel + " " + playerQueryRel.getClass.isInstance(outerRelComp)) + if (playerQueryRel.getClass.isInstance(outerRelComp)) { + //we can not use this element + goodElement = false + } + }) + //if we do not find a compatible element in this natural role we can add it + if (goodElement) { + var queryNatRole: NaturalQueryObject = null + if (queryRel.source.negated) { + queryNatRole = queryRel.target + } else { + queryNatRole = queryRel.source + } + var queryNatResult: NaturalQueryResult = getNatResultRole(rsumNat, queryNatRole) + if (queryNatResult == null) { + queryNatResult = new NaturalQueryResult(queryNatRole) + rsumNat play queryNatResult + queryNatResults += queryNatResult + } + if (queryRel.source.negated) { + queryNatResult.increaseTargetNegated() + } else { + queryNatResult.increaseSourceNegated() + } + } + } + }) + }) + + //...iterate over all query naturals without a connection and add result roles if necessary + queryNatRoles.filter(_.connectionSize == 0).foreach(queryNat => { + //connected one are visited in the part before + val playerQueryNat: Object = queryNat.player.right.get + RsumCompartment.getNaturals().foreach(rsumNat => { + if (playerQueryNat.isInstanceOf[QueryHelper]) { + if (playerQueryNat.equals(rsumNat)) { + var queryNatResult: NaturalQueryResult = getNatResultRole(rsumNat, queryNat) + if (queryNatResult == null) { + queryNatResult = new NaturalQueryResult(queryNat) + rsumNat play queryNatResult + queryNatResults += queryNatResult + } + } + } else { + if (playerQueryNat.getClass.isInstance(rsumNat)) { + var queryNatResult: NaturalQueryResult = getNatResultRole(rsumNat, queryNat) + if (queryNatResult == null) { + queryNatResult = new NaturalQueryResult(queryNat) + rsumNat play queryNatResult + queryNatResults += queryNatResult + } + } + } + }) + }) + + //###proof correctness of results + //...proof attribute correctness once + queryNatResults.filter(!_.proofAttributes).foreach(deleteNatResults += _) + //delete them + deleteNatResults.foreach(queryResultNat => { + queryNatResults -= queryResultNat + forDeletionQueryResults += queryResultNat + queryResultNat.removeConnections() + }) + + //...proof the correctness of the query results and delete non correct ones + while (doSomething) { + deleteNatResults = Set.empty + //proof the connection correctness + queryNatResults.filter(!_.proofConnections).foreach(deleteNatResults += _) + + //do as long as everything is correct + doSomething = !deleteNatResults.isEmpty + //delete them + deleteNatResults.foreach(queryResultNat => { + queryNatResults -= queryResultNat + forDeletionQueryResults += queryResultNat + queryResultNat.removeConnections() + }) + } + + //###make good outputs from the current query results + //...only correct elements should now play result roles and are in the list + var combinedResult: Set[CombinedQueryResult] = queryRelResults.filter(!_.transitive).map(_.createCombinedResult()) + + //...combine the result elements to good output units + doSomething = true + while (doSomething) { + doSomething = false + combinedResult.foreach(combined => { + queryRelResults.foreach(rel => { + if (rel.source == combined.target && !combined.contains(rel.target)) { + //add in the back + combined.addBack(rel.target) + doSomething = true + } else { + if (rel.target == combined.source && !combined.contains(rel.source)) { + //add in the front + combined.addFront(rel.source) + doSomething = true + } + } + }) + }) + //delete duplicated elements + combinedResult = combinedResult.groupBy(_.getBetween).map(_._2.head).toSet + //combinedResult.distinct + } + + //create only results with tuples + /*queryRelResults.foreach(rel => { + var rSet: Set[Object] = Set.empty + if (rel.source.connectedQueryObject.returned) { + rSet += rel.source.player.right.get + } + if (rel.target.connectedQueryObject.returned) { + rSet += rel.target.player.right.get + } + result += rSet + })*/ + + //...bring the output format to the reals one + combinedResult.foreach(combined => { + var rSet: Set[Object] = Set.empty + combined.getBetween.foreach(queryNat => { + if (queryNat.connectedQueryObject.returned) { + rSet += queryNat.player.right.get + } + }) + result += rSet + }) + + //...add also single results + queryNatResults.foreach(queryResultNat => { + if (!queryResultNat.isConnected() && queryResultNat.connectedQueryObject.returned) { + result += Set(queryResultNat.player.right.get) + } + }) + + //...delete now really all not needed result roles + forDeletionQueryResults.foreach(_.remove()) + + return result + } + + override def toString(): String = name + ": " + isQueryCorrect + " Rs: " + queryNatRoles + " " + queryRelRoles + + /** + * Query object specialized for naturals in the RSUM. + */ + class NaturalQueryObject() extends QueryObject() { + private var sourceRelations: Set[RelationalQueryObject] = Set.empty + private var targetRelations: Set[RelationalQueryObject] = Set.empty + + def addSourceRelation(rel: RelationalQueryObject): Unit = { + sourceRelations += rel + } + + def removeSourceRelation(rel: RelationalQueryObject): Unit = { + sourceRelations -= rel + } + + def getSourceRelationsSize(): Int = sourceRelations.filter(!_.isNegated()).map(_.multiTarget).sum //sum up multi value not use size + def getNegatedSourceRelationsSize(): Int = sourceRelations.filter(_.isNegated()).size + + def addTargetRelation(rel: RelationalQueryObject): Unit = { + targetRelations += rel + } + + def removeTargetRelation(rel: RelationalQueryObject): Unit = { + targetRelations -= rel + } + + def getTargetRelationsSize(): Int = targetRelations.filter(!_.isNegated()).map(_.multiSource).sum + def getNegatedTargetRelationsSize(): Int = targetRelations.filter(_.isNegated()).size + + def connectionSize(): Int = targetRelations.size + sourceRelations.size + + def overallConnectionUnit(): Int = { + var visitedRel: Set[RelationalQueryObject] = Set.empty + var visitedNat: Set[NaturalQueryObject] = Set(this) + var unVisitedRel: Set[RelationalQueryObject] = targetRelations ++ sourceRelations + var unVisitedNat: Set[NaturalQueryObject] = Set.empty + while (!unVisitedRel.isEmpty || !unVisitedNat.isEmpty) { + //run over all unvisited relations + unVisitedRel.foreach(rel => { + if (!visitedNat.contains(rel.source)) + unVisitedNat += rel.source + if (!visitedNat.contains(rel.target)) + unVisitedNat += rel.target + }) + visitedRel ++= unVisitedRel + unVisitedRel = Set.empty + //run over all unvisited naturals + unVisitedNat.foreach(nat => { + nat.sourceRelations.filter(!visitedRel.contains(_)).foreach(unVisitedRel += _) + nat.targetRelations.filter(!visitedRel.contains(_)).foreach(unVisitedRel += _) + }) + visitedNat ++= unVisitedNat + unVisitedNat = Set.empty + } + return visitedRel.size + visitedNat.size + } + + override def toString: String = "QON: " + label + " C: " + connectionSize + } + + /** + * Query object specialized for relational compartments in the RSUM. + */ + class RelationalQueryObject(val source: NaturalQueryObject, val target: NaturalQueryObject) extends QueryObject() { + + def isReturned(): Boolean = source.returned && target.returned + def isNegated(): Boolean = source.negated || target.negated + def isTransitive(): Boolean = target.transitive + def multiTarget(): Int = target.multi + def multiSource(): Int = source.multi + + source.addSourceRelation(this) + target.addTargetRelation(this) + + def overallConnectionUnit(): Int = source.overallConnectionUnit() + + override def toString: String = "QOR: " + source.label + "-" + target.label + } + + /** + * Query result roles for natural query roles. + */ + class NaturalQueryResult(val connectedQueryObject: NaturalQueryObject) extends QueryResult(connectedQueryObject) { + private var sourceRelations: Set[RelationalQueryResult] = Set.empty + private var targetRelations: Set[RelationalQueryResult] = Set.empty + + private var negatedSources: Int = 0 + private var negatedTargets: Int = 0 + + def increaseSourceNegated(): Unit = { negatedSources += 1 } + def decreaseSourceNegated(): Unit = { negatedSources -= 1 } + + def increaseTargetNegated(): Unit = { negatedTargets += 1 } + def decreaseTargetNegated(): Unit = { negatedTargets -= 1 } + + /** + * Proof if the player has all the necessary attributes with its values. + */ + def proofAttributes(): Boolean = { + val player: Object = this.player.right.get + var returnValue = true + connectedQueryObject.getAttributeFilters.foreach(a => { + try { + //player.getClass.getMethods.foreach(f => println(f.toString)) + //println(player.getClass.getMethod("name").getReturnType) //getName + val met = player.getClass.getMethod(a.attributeName) + val result: String = met.invoke(player).asInstanceOf[String] + a.checking match { + case CheckingOption.equalsCheck => if (result != a.value) returnValue = false + case CheckingOption.biggerThan => if (result <= a.value) returnValue = false + case CheckingOption.smallerThan => if (result >= a.value) returnValue = false + case _ => + } + } catch { + case _: Throwable => { + println("!!! No attribute with this name!!!") + return false + } + } + }) + return returnValue + } + + /** + * Proof if the number of connections is equals to the related query object. + */ + def proofConnections(): Boolean = { + //TODO: proof also the number of types and not only the numbers + //println("S: " + _connectedQueryObject.getSourceRelationsSize() + " T: " + _connectedQueryObject.getTargetRelationsSize() + " NS: " + _connectedQueryObject.getNegatedSourceRelationsSize() + " NT: " + _connectedQueryObject.getNegatedTargetRelationsSize() + " Con: " + _connectedQueryObject) + //println("S: " + getSourceRelationsSize() + " T: " + getTargetRelationsSize() + " NS: " + negatedSources + " NT: " + negatedTargets + " This: " + this) + if (getSourceRelationsSize >= connectedQueryObject.getSourceRelationsSize() + && getTargetRelationsSize >= connectedQueryObject.getTargetRelationsSize() + && negatedSources >= connectedQueryObject.getNegatedSourceRelationsSize() + && negatedTargets >= connectedQueryObject.getNegatedTargetRelationsSize()) { + return true + } + return false + } + + def addSourceRelation(rel: RelationalQueryResult): Unit = { + sourceRelations += rel + } + + def removeSourceRelation(rel: RelationalQueryResult): Unit = { + sourceRelations -= rel + } + + def getSourceRelationsSize(): Int = sourceRelations.size + + def addTargetRelation(rel: RelationalQueryResult): Unit = { + targetRelations += rel + } + + def removeTargetRelation(rel: RelationalQueryResult): Unit = { + targetRelations -= rel + } + + def getTargetRelationsSize(): Int = targetRelations.size + + def isConnected(): Boolean = (targetRelations.size + sourceRelations.size) > 0 + + def removeConnections(): Unit = { + sourceRelations.foreach(rel => { + rel.target.removeTargetRelation(rel) + queryRelResults -= rel + rel.remove() + }) + targetRelations.foreach(rel => { + rel.source.removeSourceRelation(rel) + queryRelResults -= rel + rel.remove() + }) + sourceRelations = Set.empty + targetRelations = Set.empty + negatedSources = 0 + negatedTargets = 0 + } + } + + /** + * Query result roles for relation query roles. + */ + class RelationalQueryResult(val connectedQueryObject: RelationalQueryObject, val source: NaturalQueryResult, val target: NaturalQueryResult, val transitive: Boolean) extends QueryResult(connectedQueryObject) { + //only add this relation to the connect results if it is not transitive + if (!transitive) { + source.addSourceRelation(this) + target.addTargetRelation(this) + } + + /** + * Create a new combined result which is a copy of this one. + */ + def createCombinedResult(): CombinedQueryResult = new CombinedQueryResult(source, target) + } + + /** + * Helper class to connect the results to a chain. + */ + class CombinedQueryResult(var source: NaturalQueryResult, var target: NaturalQueryResult) { + + //list of all query results that are connected + private var between: Seq[NaturalQueryResult] = Seq(source, target) + + def getBetween(): Seq[NaturalQueryResult] = between + + def addFront(newIn: NaturalQueryResult): Unit = { + between = newIn +: between + source = newIn + } + + def addBack(newIn: NaturalQueryResult): Unit = { + between = between :+ newIn + target = newIn + } + + def contains(result: NaturalQueryResult): Boolean = (between.contains(result)) + + private def getSize(): Int = between.size + + protected def canEqual(other: Any): Boolean = other.isInstanceOf[CombinedQueryResult] + + override def equals(other: Any): Boolean = other match { + case that: CombinedQueryResult => { + if (that canEqual this) { + between.foreach(b => { + if (!that.contains(b)) + return false + }) + return that.getSize == this.getSize() + } else { + return false + } + } + case _ => return false + } + + override def toString(): String = "QCR: (" + between + ")" + } +} \ No newline at end of file diff --git a/src/main/scala/query/AMLLanguageQuery.scala b/src/main/scala/query/AMLLanguageQuery.scala index a13b9fb..8259555 100644 --- a/src/main/scala/query/AMLLanguageQuery.scala +++ b/src/main/scala/query/AMLLanguageQuery.scala @@ -5,7 +5,7 @@ import aml.InternalElement import aml.SystemUnitClassAttributesAttribute import aml.CAEXObject import aml.Attribute -import org.rosi_project.model_management.sum.query.IQueryViewCompartment +import org.rosi_project.model_management.sum.query.QueryFactory import aml.InstanceHierarchyInternalElementsInternalElement import aml.InternalElementBaseSystemUnitSystemUnitClass import aml.HelperCAEXObject @@ -13,7 +13,7 @@ import aml.InstanceHierarchy import org.rosi_project.model_management.sum.query.CheckingOption import aml.SystemUnitClass -class AMLLanguageQuery extends IQueryViewCompartment { +class AMLLanguageQuery extends QueryFactory { init("AMLLanguageQuery") @@ -79,7 +79,7 @@ class AMLLanguageQuery extends IQueryViewCompartment { } def addInternalElements(v: AMLLanguageQuery#InternalElementRole): Boolean = { - if (hasInternalElements(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasInternalElements(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new SystemUnitClassInternalElementsInternalElementRole(this, v) return true } @@ -114,7 +114,7 @@ class AMLLanguageQuery extends IQueryViewCompartment { } def addAttributes(v: AMLLanguageQuery#AttributeRole): Boolean = { - if (hasAttributes(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasAttributes(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new SystemUnitClassAttributesAttributeRole(this, v) return true } @@ -201,7 +201,7 @@ class AMLLanguageQuery extends IQueryViewCompartment { } def addInternalElements(v: AMLLanguageQuery#InternalElementRole): Boolean = { - if (hasInternalElements(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasInternalElements(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new InstanceHierarchyInternalElementsInternalElementRole(this, v) return true } @@ -223,7 +223,7 @@ class AMLLanguageQuery extends IQueryViewCompartment { } - class CAEXObjectRole extends AQueryViewRole { + class CAEXObjectRole extends QueryFactoryElement { override protected def isRelational(): Boolean = { return false @@ -292,7 +292,7 @@ class AMLLanguageQuery extends IQueryViewCompartment { def setBaseSystemUnit(v: AMLLanguageQuery#SystemUnitClassRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (baseSystemUnit != null) { if (baseSystemUnit.getTarget() == v) return false baseSystemUnit.deleteElement() @@ -307,7 +307,7 @@ class AMLLanguageQuery extends IQueryViewCompartment { } - class SystemUnitClassInternalElementsInternalElementRole(private val source: AMLLanguageQuery#SystemUnitClassRole, private val target: AMLLanguageQuery#InternalElementRole) extends AQueryViewRole { + class SystemUnitClassInternalElementsInternalElementRole(private val source: AMLLanguageQuery#SystemUnitClassRole, private val target: AMLLanguageQuery#InternalElementRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -340,7 +340,7 @@ class AMLLanguageQuery extends IQueryViewCompartment { } - class SystemUnitClassAttributesAttributeRole(private val source: AMLLanguageQuery#SystemUnitClassRole, private val target: AMLLanguageQuery#AttributeRole) extends AQueryViewRole { + class SystemUnitClassAttributesAttributeRole(private val source: AMLLanguageQuery#SystemUnitClassRole, private val target: AMLLanguageQuery#AttributeRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -373,7 +373,7 @@ class AMLLanguageQuery extends IQueryViewCompartment { } - class InstanceHierarchyInternalElementsInternalElementRole(private val source: AMLLanguageQuery#InstanceHierarchyRole, private val target: AMLLanguageQuery#InternalElementRole) extends AQueryViewRole { + class InstanceHierarchyInternalElementsInternalElementRole(private val source: AMLLanguageQuery#InstanceHierarchyRole, private val target: AMLLanguageQuery#InternalElementRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -406,7 +406,7 @@ class AMLLanguageQuery extends IQueryViewCompartment { } - class InternalElementBaseSystemUnitSystemUnitClassRole(private val source: AMLLanguageQuery#InternalElementRole, private val target: AMLLanguageQuery#SystemUnitClassRole) extends AQueryViewRole { + class InternalElementBaseSystemUnitSystemUnitClassRole(private val source: AMLLanguageQuery#InternalElementRole, private val target: AMLLanguageQuery#SystemUnitClassRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true diff --git a/src/main/scala/query/EclipseLibraryQuery.scala b/src/main/scala/query/EclipseLibraryQuery.scala index 344278b..a4bf962 100644 --- a/src/main/scala/query/EclipseLibraryQuery.scala +++ b/src/main/scala/query/EclipseLibraryQuery.scala @@ -14,7 +14,7 @@ import elib.LibraryParentBranchLibrary import elib.Periodical import elib.Writer import elib.AudioVisualItem -import org.rosi_project.model_management.sum.query.IQueryViewCompartment +import org.rosi_project.model_management.sum.query.QueryFactory import elib.EmployeeManagerEmployee import elib.Person import java.util.Date @@ -29,7 +29,7 @@ import elib.CirculatingItem import elib.Item import elib.LibraryStockItem -class EclipseLibraryQuery extends IQueryViewCompartment { +class EclipseLibraryQuery extends QueryFactory { init("EclipseLibraryQuery") @@ -85,7 +85,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { "EclipseLibraryQuery:" } - class ItemRole extends AQueryViewRole { + class ItemRole extends QueryFactoryElement { override protected def isRelational(): Boolean = { return false @@ -145,7 +145,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { def setManager(v: EclipseLibraryQuery#EmployeeRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (manager != null) { if (manager.getTarget() == v) return false manager.deleteElement() @@ -234,7 +234,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } def addCast(v: EclipseLibraryQuery#PersonRole): Boolean = { - if (hasCast(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasCast(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new VideoCassetteCastPersonRole(this, v) return true } @@ -348,7 +348,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } def addBooks(v: EclipseLibraryQuery#BookRole): Boolean = { - if (hasBooks(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasBooks(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new BookAuthorWriterRole(v, this) return true } @@ -428,7 +428,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { def setAuthor(v: EclipseLibraryQuery#WriterRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (author != null) { if (author.getTarget() == v) return false author.deleteElement() @@ -443,7 +443,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class LibraryRole extends AQueryViewRole { + class LibraryRole extends QueryFactoryElement { private var employees: Set[EclipseLibraryQuery#LibraryEmployeesEmployeeRole] = Set.empty private var parentBranch: EclipseLibraryQuery#LibraryParentBranchLibraryRole = null @@ -500,7 +500,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } def addEmployees(v: EclipseLibraryQuery#EmployeeRole): Boolean = { - if (hasEmployees(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasEmployees(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new LibraryEmployeesEmployeeRole(this, v) return true } @@ -530,7 +530,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { def setParentBranch(v: EclipseLibraryQuery#LibraryRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (parentBranch != null) { if (parentBranch.getTarget() == v) return false parentBranch.deleteElement() @@ -558,7 +558,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } def addWriters(v: EclipseLibraryQuery#WriterRole): Boolean = { - if (hasWriters(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasWriters(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new LibraryWritersWriterRole(this, v) return true } @@ -593,7 +593,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } def addBorrowers(v: EclipseLibraryQuery#BorrowerRole): Boolean = { - if (hasBorrowers(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasBorrowers(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new LibraryBorrowersBorrowerRole(this, v) return true } @@ -628,7 +628,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } def addStock(v: EclipseLibraryQuery#ItemRole): Boolean = { - if (hasStock(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasStock(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new LibraryStockItemRole(this, v) return true } @@ -663,7 +663,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } def addBranches(v: EclipseLibraryQuery#LibraryRole): Boolean = { - if (hasBranches(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasBranches(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new LibraryBranchesLibraryRole(this, v) return true } @@ -698,7 +698,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } def addBooks(v: EclipseLibraryQuery#BookRole): Boolean = { - if (hasBooks(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasBooks(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new LibraryBooksBookRole(this, v) return true } @@ -753,7 +753,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { def setAuthor(v: EclipseLibraryQuery#WriterRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (author != null) { if (author.getTarget() == v) return false author.deleteElement() @@ -776,7 +776,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { def setReader(v: EclipseLibraryQuery#PersonRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (reader != null) { if (reader.getTarget() == v) return false reader.deleteElement() @@ -831,7 +831,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class PersonRole extends AQueryViewRole { + class PersonRole extends QueryFactoryElement { override protected def isRelational(): Boolean = { return false @@ -869,7 +869,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class LibraryEmployeesEmployeeRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#EmployeeRole) extends AQueryViewRole { + class LibraryEmployeesEmployeeRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#EmployeeRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -902,7 +902,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class LibraryParentBranchLibraryRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#LibraryRole) extends AQueryViewRole { + class LibraryParentBranchLibraryRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#LibraryRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -935,7 +935,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class LibraryWritersWriterRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#WriterRole) extends AQueryViewRole { + class LibraryWritersWriterRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#WriterRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -968,7 +968,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class BookOnTapeAuthorWriterRole(private val source: EclipseLibraryQuery#BookOnTapeRole, private val target: EclipseLibraryQuery#WriterRole) extends AQueryViewRole { + class BookOnTapeAuthorWriterRole(private val source: EclipseLibraryQuery#BookOnTapeRole, private val target: EclipseLibraryQuery#WriterRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -1001,7 +1001,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class BookOnTapeReaderPersonRole(private val source: EclipseLibraryQuery#BookOnTapeRole, private val target: EclipseLibraryQuery#PersonRole) extends AQueryViewRole { + class BookOnTapeReaderPersonRole(private val source: EclipseLibraryQuery#BookOnTapeRole, private val target: EclipseLibraryQuery#PersonRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -1034,7 +1034,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class LibraryBorrowersBorrowerRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#BorrowerRole) extends AQueryViewRole { + class LibraryBorrowersBorrowerRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#BorrowerRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -1067,7 +1067,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class LibraryStockItemRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#ItemRole) extends AQueryViewRole { + class LibraryStockItemRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#ItemRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -1100,7 +1100,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class BookAuthorWriterRole(private val source: EclipseLibraryQuery#BookRole, private val target: EclipseLibraryQuery#WriterRole) extends AQueryViewRole { + class BookAuthorWriterRole(private val source: EclipseLibraryQuery#BookRole, private val target: EclipseLibraryQuery#WriterRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -1135,7 +1135,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class LibraryBranchesLibraryRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#LibraryRole) extends AQueryViewRole { + class LibraryBranchesLibraryRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#LibraryRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -1168,7 +1168,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class VideoCassetteCastPersonRole(private val source: EclipseLibraryQuery#VideoCassetteRole, private val target: EclipseLibraryQuery#PersonRole) extends AQueryViewRole { + class VideoCassetteCastPersonRole(private val source: EclipseLibraryQuery#VideoCassetteRole, private val target: EclipseLibraryQuery#PersonRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -1201,7 +1201,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class EmployeeManagerEmployeeRole(private val source: EclipseLibraryQuery#EmployeeRole, private val target: EclipseLibraryQuery#EmployeeRole) extends AQueryViewRole { + class EmployeeManagerEmployeeRole(private val source: EclipseLibraryQuery#EmployeeRole, private val target: EclipseLibraryQuery#EmployeeRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -1234,7 +1234,7 @@ class EclipseLibraryQuery extends IQueryViewCompartment { } - class LibraryBooksBookRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#BookRole) extends AQueryViewRole { + class LibraryBooksBookRole(private val source: EclipseLibraryQuery#LibraryRole, private val target: EclipseLibraryQuery#BookRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true diff --git a/src/main/scala/query/IMDBdatabaseQuery.scala b/src/main/scala/query/IMDBdatabaseQuery.scala index 12c15ee..52acbe1 100644 --- a/src/main/scala/query/IMDBdatabaseQuery.scala +++ b/src/main/scala/query/IMDBdatabaseQuery.scala @@ -9,7 +9,7 @@ import imdbdatabase.IMDBVotesVote import imdbdatabase.VoteUserUser import imdbdatabase.FigurePlayedByActor import imdbdatabase.Person -import org.rosi_project.model_management.sum.query.IQueryViewCompartment +import org.rosi_project.model_management.sum.query.QueryFactory import imdbdatabase.IMDB import imdbdatabase.Figure import imdbdatabase.Actor @@ -18,7 +18,7 @@ import imdbdatabase.Vote import imdbdatabase.IMDBUsersUser import imdbdatabase.IMDBActorsActor -class IMDBdatabaseQuery extends IQueryViewCompartment { +class IMDBdatabaseQuery extends QueryFactory { init("IMDBdatabaseQuery") @@ -54,7 +54,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { "IMDBdatabaseQuery:" } - class IMDBRole extends AQueryViewRole { + class IMDBRole extends QueryFactoryElement { private var users: Set[IMDBdatabaseQuery#IMDBUsersUserRole] = Set.empty private var votes: Set[IMDBdatabaseQuery#IMDBVotesVoteRole] = Set.empty @@ -96,7 +96,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } def addUsers(v: IMDBdatabaseQuery#UserRole): Boolean = { - if (hasUsers(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasUsers(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new IMDBUsersUserRole(this, v) return true } @@ -131,7 +131,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } def addVotes(v: IMDBdatabaseQuery#VoteRole): Boolean = { - if (hasVotes(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasVotes(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new IMDBVotesVoteRole(this, v) return true } @@ -166,7 +166,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } def addActors(v: IMDBdatabaseQuery#ActorRole): Boolean = { - if (hasActors(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasActors(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new IMDBActorsActorRole(this, v) return true } @@ -201,7 +201,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } def addFilms(v: IMDBdatabaseQuery#FilmRole): Boolean = { - if (hasFilms(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasFilms(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new IMDBFilmsFilmRole(this, v) return true } @@ -223,7 +223,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } - class FilmRole extends AQueryViewRole { + class FilmRole extends QueryFactoryElement { private var library: IMDBdatabaseQuery#IMDBFilmsFilmRole = null private var votes: Set[IMDBdatabaseQuery#VoteFilmFilmRole] = Set.empty @@ -276,7 +276,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { def setLibrary(v: IMDBdatabaseQuery#IMDBRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (library != null) { if (library.getSource() == v) return false library.deleteElement() @@ -304,7 +304,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } def addVotes(v: IMDBdatabaseQuery#VoteRole): Boolean = { - if (hasVotes(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasVotes(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new VoteFilmFilmRole(v, this) return true } @@ -339,7 +339,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } def addFigures(v: IMDBdatabaseQuery#FigureRole): Boolean = { - if (hasFigures(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasFigures(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new FilmFiguresFigureRole(this, v) return true } @@ -361,7 +361,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } - class VoteRole extends AQueryViewRole { + class VoteRole extends QueryFactoryElement { private var user: IMDBdatabaseQuery#VoteUserUserRole = null private var library: IMDBdatabaseQuery#IMDBVotesVoteRole = null @@ -405,7 +405,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { def setUser(v: IMDBdatabaseQuery#UserRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (user != null) { if (user.getTarget() == v) return false user.deleteElement() @@ -428,7 +428,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { def setLibrary(v: IMDBdatabaseQuery#IMDBRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (library != null) { if (library.getSource() == v) return false library.deleteElement() @@ -451,7 +451,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { def setFilm(v: IMDBdatabaseQuery#FilmRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (film != null) { if (film.getTarget() == v) return false film.deleteElement() @@ -504,7 +504,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } def addPlays(v: IMDBdatabaseQuery#FigureRole): Boolean = { - if (hasPlays(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasPlays(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new FigurePlayedByActorRole(v, this) return true } @@ -534,7 +534,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { def setLibrary(v: IMDBdatabaseQuery#IMDBRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (library != null) { if (library.getSource() == v) return false library.deleteElement() @@ -549,7 +549,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } - class PersonRole extends AQueryViewRole { + class PersonRole extends QueryFactoryElement { override protected def isRelational(): Boolean = { return false @@ -587,7 +587,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } - class FigureRole extends AQueryViewRole { + class FigureRole extends QueryFactoryElement { private var playedBy: Set[IMDBdatabaseQuery#FigurePlayedByActorRole] = Set.empty private var film: IMDBdatabaseQuery#FilmFiguresFigureRole = null @@ -634,7 +634,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } def addPlayedBy(v: IMDBdatabaseQuery#ActorRole): Boolean = { - if (hasPlayedBy(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasPlayedBy(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new FigurePlayedByActorRole(this, v) return true } @@ -664,7 +664,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { def setFilm(v: IMDBdatabaseQuery#FilmRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (film != null) { if (film.getSource() == v) return false film.deleteElement() @@ -728,7 +728,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { def setLibrary(v: IMDBdatabaseQuery#IMDBRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (library != null) { if (library.getSource() == v) return false library.deleteElement() @@ -743,7 +743,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } - class FigurePlayedByActorRole(private val source: IMDBdatabaseQuery#FigureRole, private val target: IMDBdatabaseQuery#ActorRole) extends AQueryViewRole { + class FigurePlayedByActorRole(private val source: IMDBdatabaseQuery#FigureRole, private val target: IMDBdatabaseQuery#ActorRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -778,7 +778,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } - class VoteUserUserRole(private val source: IMDBdatabaseQuery#VoteRole, private val target: IMDBdatabaseQuery#UserRole) extends AQueryViewRole { + class VoteUserUserRole(private val source: IMDBdatabaseQuery#VoteRole, private val target: IMDBdatabaseQuery#UserRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -811,7 +811,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } - class IMDBUsersUserRole(private val source: IMDBdatabaseQuery#IMDBRole, private val target: IMDBdatabaseQuery#UserRole) extends AQueryViewRole { + class IMDBUsersUserRole(private val source: IMDBdatabaseQuery#IMDBRole, private val target: IMDBdatabaseQuery#UserRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -846,7 +846,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } - class IMDBVotesVoteRole(private val source: IMDBdatabaseQuery#IMDBRole, private val target: IMDBdatabaseQuery#VoteRole) extends AQueryViewRole { + class IMDBVotesVoteRole(private val source: IMDBdatabaseQuery#IMDBRole, private val target: IMDBdatabaseQuery#VoteRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -881,7 +881,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } - class IMDBActorsActorRole(private val source: IMDBdatabaseQuery#IMDBRole, private val target: IMDBdatabaseQuery#ActorRole) extends AQueryViewRole { + class IMDBActorsActorRole(private val source: IMDBdatabaseQuery#IMDBRole, private val target: IMDBdatabaseQuery#ActorRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -916,7 +916,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } - class IMDBFilmsFilmRole(private val source: IMDBdatabaseQuery#IMDBRole, private val target: IMDBdatabaseQuery#FilmRole) extends AQueryViewRole { + class IMDBFilmsFilmRole(private val source: IMDBdatabaseQuery#IMDBRole, private val target: IMDBdatabaseQuery#FilmRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -951,7 +951,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } - class VoteFilmFilmRole(private val source: IMDBdatabaseQuery#VoteRole, private val target: IMDBdatabaseQuery#FilmRole) extends AQueryViewRole { + class VoteFilmFilmRole(private val source: IMDBdatabaseQuery#VoteRole, private val target: IMDBdatabaseQuery#FilmRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -986,7 +986,7 @@ class IMDBdatabaseQuery extends IQueryViewCompartment { } - class FilmFiguresFigureRole(private val source: IMDBdatabaseQuery#FilmRole, private val target: IMDBdatabaseQuery#FigureRole) extends AQueryViewRole { + class FilmFiguresFigureRole(private val source: IMDBdatabaseQuery#FilmRole, private val target: IMDBdatabaseQuery#FigureRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true diff --git a/src/main/scala/query/LibraryQuery.scala b/src/main/scala/query/LibraryQuery.scala index 809b0f1..4de34bd 100644 --- a/src/main/scala/query/LibraryQuery.scala +++ b/src/main/scala/query/LibraryQuery.scala @@ -5,11 +5,11 @@ import lib.Library import lib.HelperPerson import lib.Person import lib.LibraryEmployeesEmployee -import org.rosi_project.model_management.sum.query.IQueryViewCompartment +import org.rosi_project.model_management.sum.query.QueryFactory import lib.Employee import org.rosi_project.model_management.sum.query.CheckingOption -class LibraryQuery extends IQueryViewCompartment { +class LibraryQuery extends QueryFactory { init("LibraryQuery") @@ -29,7 +29,7 @@ class LibraryQuery extends IQueryViewCompartment { "LibraryQuery:" } - class LibraryRole extends AQueryViewRole { + class LibraryRole extends QueryFactoryElement { private var employees: Set[LibraryQuery#LibraryEmployeesEmployeeRole] = Set.empty @@ -74,7 +74,7 @@ class LibraryQuery extends IQueryViewCompartment { } def addEmployees(v: LibraryQuery#EmployeeRole): Boolean = { - if (hasEmployees(v) || !containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (hasEmployees(v) || !containsRole(v.asInstanceOf[QueryFactoryElement])) return false new LibraryEmployeesEmployeeRole(this, v) return true } @@ -136,7 +136,7 @@ class LibraryQuery extends IQueryViewCompartment { def setManager(v: LibraryQuery#EmployeeRole): Boolean = { if (v == null) return false - if (!containsRole(v.asInstanceOf[AQueryViewRole])) return false + if (!containsRole(v.asInstanceOf[QueryFactoryElement])) return false if (manager != null) { if (manager.getTarget() == v) return false manager.deleteElement() @@ -151,7 +151,7 @@ class LibraryQuery extends IQueryViewCompartment { } - class PersonRole extends AQueryViewRole { + class PersonRole extends QueryFactoryElement { override protected def isRelational(): Boolean = { return false @@ -180,7 +180,7 @@ class LibraryQuery extends IQueryViewCompartment { } - class LibraryEmployeesEmployeeRole(private val source: LibraryQuery#LibraryRole, private val target: LibraryQuery#EmployeeRole) extends AQueryViewRole { + class LibraryEmployeesEmployeeRole(private val source: LibraryQuery#LibraryRole, private val target: LibraryQuery#EmployeeRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true @@ -213,7 +213,7 @@ class LibraryQuery extends IQueryViewCompartment { } - class EmployeeManagerEmployeeRole(private val source: LibraryQuery#EmployeeRole, private val target: LibraryQuery#EmployeeRole) extends AQueryViewRole { + class EmployeeManagerEmployeeRole(private val source: LibraryQuery#EmployeeRole, private val target: LibraryQuery#EmployeeRole) extends QueryFactoryElement { override protected def isRelational(): Boolean = { return true -- GitLab