From 9d17ba7d476eefe4347d854647c58bbd19272c13 Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Thu, 24 Apr 2025 16:45:14 -0700 Subject: [PATCH 01/15] Add module for xtable rest service --- pom.xml | 22 +++ xtable-service/README.md | 52 +++++++ ...t 2025-05-01 at 9.04.59\342\200\257AM.png" | Bin 0 -> 277148 bytes ...t 2025-05-01 at 9.05.10\342\200\257AM.png" | Bin 0 -> 289179 bytes xtable-service/pom.xml | 110 +++++++++++++++ .../xtable/service/ConversionResource.java | 45 ++++++ .../xtable/service/ConversionService.java | 128 ++++++++++++++++++ .../service/ConversionServiceConfig.java | 24 ++++ .../xtable/service/ConversionServiceUtil.java | 53 ++++++++ .../service/models/ConvertTableRequest.java | 79 +++++++++++ .../service/models/ConvertTableResponse.java | 39 ++++++ .../xtable/service/models/InternalTable.java | 54 ++++++++ .../xtable/service/spark/SparkBootstrap.java | 37 +++++ .../xtable/service/spark/SparkHolder.java | 74 ++++++++++ .../src/main/resources/application.properties | 17 +++ .../main/resources/xtable-hadoop-defaults.xml | 91 +++++++++++++ .../org/apache/xtable/XTableResourceIT.java | 26 ++++ .../org/apache/xtable/XTableResourceTest.java | 34 +++++ 18 files changed, 885 insertions(+) create mode 100644 xtable-service/README.md create mode 100644 "xtable-service/examples/Screenshot 2025-05-01 at 9.04.59\342\200\257AM.png" create mode 100644 "xtable-service/examples/Screenshot 2025-05-01 at 9.05.10\342\200\257AM.png" create mode 100644 xtable-service/pom.xml create mode 100644 xtable-service/src/main/java/org/apache/xtable/service/ConversionResource.java create mode 100644 xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java create mode 100644 xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceConfig.java create mode 100644 xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceUtil.java create mode 100644 xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableRequest.java create mode 100644 xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java create mode 100644 xtable-service/src/main/java/org/apache/xtable/service/models/InternalTable.java create mode 100644 xtable-service/src/main/java/org/apache/xtable/service/spark/SparkBootstrap.java create mode 100644 xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java create mode 100644 xtable-service/src/main/resources/application.properties create mode 100644 xtable-service/src/main/resources/xtable-hadoop-defaults.xml create mode 100644 xtable-service/src/test/java/org/apache/xtable/XTableResourceIT.java create mode 100644 xtable-service/src/test/java/org/apache/xtable/XTableResourceTest.java diff --git a/pom.xml b/pom.xml index d70d45de2..bd128c743 100644 --- a/pom.xml +++ b/pom.xml @@ -53,6 +53,7 @@ xtable-utilities xtable-aws xtable-hive-metastore + xtable-service @@ -97,6 +98,10 @@ 1.7 1.7 2.12.0 + quarkus-bom + io.quarkus.platform + 3.2.12.Final + 4.9.3 false @@ -352,6 +357,16 @@ ${spark.version} provided + + org.antlr + antlr4-runtime + ${antlr4.version} + + + org.scala-lang + scala-reflect + ${scala.version} + commons-cli @@ -594,6 +609,13 @@ jettison 1.5.4 + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + diff --git a/xtable-service/README.md b/xtable-service/README.md new file mode 100644 index 000000000..00a0b119e --- /dev/null +++ b/xtable-service/README.md @@ -0,0 +1,52 @@ + + +# XTable REST Service + +The `rest-service-open-api.yaml` defines the api contract for running table format conversion using XTable's REST service. +See XTable's `spec` module for more details: https://github.com/apache/incubator-xtable/tree/main/spec + +## How to run the service locally + +#### Before running the service, ensure that you have the required credentials set in your enviroment needed to read and write to cloud storage. + +To run the service locally, first ensure you have built the project with +```sh +mvn clean install -DskipTests +``` + + +Then you can run start the quarkus service using the following command: +```sh +mvn quarkus:dev -pl xtable-service +``` +This will start the service on `http://localhost:8080`. + +Note quarkus will automatically reload the service when you make changes to the code. + +## Testing with Postman + +If you would like to test the service with an api client, you can download Postman https://www.postman.com/downloads/ + +Ensure that when you are testing that you have set the service URL, headers, and request body correctly. +See the screenshots below for an example. + +![Screenshot 2025-05-01 at 9.04.59 AM.png](examples/Screenshot%202025-05-01%20at%209.04.59%E2%80%AFAM.png) + +![Screenshot 2025-05-01 at 9.05.10 AM.png](examples/Screenshot%202025-05-01%20at%209.05.10%E2%80%AFAM.png) \ No newline at end of file diff --git "a/xtable-service/examples/Screenshot 2025-05-01 at 9.04.59\342\200\257AM.png" "b/xtable-service/examples/Screenshot 2025-05-01 at 9.04.59\342\200\257AM.png" new file mode 100644 index 0000000000000000000000000000000000000000..2a7eb4da6ba059e7fe0186e93f04fa8ecc690820 GIT binary patch literal 277148 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%0DI5@C0Av|g`zyG9b1 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

7GEwS;sZ@C9Vn=) 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 literal 0 HcmV?d00001 diff --git "a/xtable-service/examples/Screenshot 2025-05-01 at 9.05.10\342\200\257AM.png" "b/xtable-service/examples/Screenshot 2025-05-01 at 9.05.10\342\200\257AM.png" new file mode 100644 index 0000000000000000000000000000000000000000..5c541b25994b0032c9c0bdb90ab8fef4dc5c3bae GIT binary patch literal 289179 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

3{Ha{C$=F{6+pd zD*fp@yYKI)^ykCz-%;t$-`PWdCwPA+c>iYw{=Q0oU#0)F0)I!PzoXKBT7kb4yuTB? z|Fi=Cr&hXZ&Tv}7*#bm@I1>OQjr3<7Z+C!Bp(eht!=P3yYvm zFYe6@^P3N3myE}vUu-yyXwO|BYo==8h0XQ3qD0ZTJ}F8y==chBwnT}+i}G#sc&%5W z{x-iSfKEpbBUb0gFexxF@R)cnLdOK+!5O4Mh^Upyhjt`I++suP>)-XQnCr#p*Z^aS z-({xT9UQkJscY{356Z*;^fvx+FQy6(=)Ie5+%c*en(p93+oh{z=(;bu6ovWfu$-Zq zycJAf*}UBx{lmmGvh5_agNhF#f)1ewQKz30WhDY)5m7)CMCjQ|zylW5ant-L3{9+#8lE0H~}q{ zJFoU=6t8_eMzjZ?gs{=-r;JsIK6;zvie}`%SBAh}(d(C<)@fH$)K~IsC%SJ29*LFi z!LjyWdM28XcoHik!_QJNwh*D^&&|IlF1(F$yn;?u@3!X}+z)_;R^X#=OYeZqz z0fu_D2!#d_q60>otXZ?gE_2V!X9=EDkM|#>pfjuu_u@q-L<4I67KrPYkbjI^gyE0= zMPuv58{`r6o;$g0MDJ}Wi0zGixwMn6=5?F-=M79h1#!1$?M>!xP9CXiJXjoRmqq=8 zhtq|Z$9*?W)VNp4*a)m0j0Q?{BC;M#>Ra2R4!X(|N;rt`66&_|aKkYH;W%<=aw6`s z`b78ia_j33gN6o37RVtcSKHV zY9G)ma}9Z;EOFU$bw(`?!R&U?QsD8HSi`$|^p<^=ZUyU>>@>{`q zY0APdX|;}sD#8Hw711}Oi}VD^vwGWNV((1T?q|jd+MO*j@1&2yFN9(EL!)|TH!y`j z^hk>bj1*=7f!{K|V=yRbRxWZrM|$kF=J#GdTx4;NxoapmBPK6Y42ii7%$4lD(;4gE z^Lf`V!&>^itHVBJ|57`44;8jMI&8Mpf7jr_*H4daDOFg(6v7+4!$Uz=Am6vj^y4bf zFP{U41Gk=fEd0*8DIayZ?t#bDpIWZ&Qj6GqAfoqnYI)x@d>=RM7ZBP+h)>iet*(gf zAlTAtk7aHqICG9yjVy_XHsG>|JRYhe(=yM zZ7?WM#e%$JV%AzyV$%T2z#QobV#hJDIrFfWF4E5o=j_|uZ z?<4=%<5fqMcuINK>Mb>dlZ7ZYD+{@g^|KE<)wI?Q#EF{K)u2OyZydk%EQeTDn`A5c zLT=FJG|_91WFEf7ixW=3<@nN02C{m(%{}Z);J2R~Dw%8#9>?@A&m^?fZ5}8DxdRai zM74)m@VyY)t~rtaDK+ZeTvH;y;CJ`Nx0gdUd9nbY*>tnQhvd`dHGB$DyD&LwOED}1 z#;!|1Vq>g4Z487z9$%h@NAufS7j-CD3_#|9-)n7dExsgP(H`uxU!f7T>k@Dx8PvjT zR1f}evRYP~`*7(a2#MDMT~TK)2A;1MEYcD`BJ-M~_|N~4J>Lt0orvr7>PS=R9$ZSS zM&?^v+vr(jqJ9i4@5b;5zXT7uye{=G7iSUv9x~8^P#UC_zx`BAkAvyw>1a%KA1L3n zKjH5tD~elP81Z}>czCHZKD{{1-*_XSRH5 zul;^td(G!zV1LVk8RLPI?(y~hb8iLB%@PHjCb`gfbNvY0xQ}(c=)^tWzCr!1&$}x+ z??LM)EosqZwznVb4rUG*pAWmuYdAGjnqO$q@fp(@d>WDvl$LE}oQhc-&fvgYGH*|T z<$chGV{XfUIqd+r+uMtai*Kx@@qLFBt%S`J;|)xbTdU;XZcOT4I#Ywc6#7Qw#MOQK z57GYAUmow=U`th1$RdpEDP7iLpR=B@(>3aEO7Dy45#+ic-POq{T=?Ql{ga-%Y)hX< zHFSDkCss!;8aoBh*JNYE)pK%en_BYl+4Ng|#ax?D#t#og)z8Fe-`)ws;% zi$bPkIjlbAWvW}Kwn)ef4c_a#*|%~WU1UJviz+M+4O`1?ylvgr_#xQl8@K&+O!eof z1J5b=y>w)Odx&VE^w0I@V?dsEc&u{8$>0|wWvp6b=1R8lh1rPE=~vSBZ!qrW6}DO> z;%4y&4HaTVY;XCbHiG$$2^AyHi>*Q|ZsrR7tTDF3_g%6jE}NC+IQfm z{_=1iRkzeUKc`;$yz=8aU~#f^&}J3O`!vFKq*O{sEw9ngwf)N;O~47lQl!0>aP=h3 z^r=i-i$M|gHk}#ma>W{PEq$E*nTKernSfmLKnrNmn8Uu}22-xJ(AhCy-lwH$?`*DO zt_4s=L`Pfp_xJM%xz)Wu6~VQzh%GS%nJlMOQJcO8AWi7dbVWUT>Y5vUTH4htVA?1U zE9{6k^$+(h6syb|1Is#X$JEqR0fP_GpA?EJO0=Hq1%QPP>ekvb|60qds^5j+ar)S67E(x4)evzGM zBb!|DTYYwCviuSAB&R*V%Hd2m1${Q12lGsWWwGDIOTTD-4Y|b z;Q8gtm!-jAkCV(5?+r%{h0#%vMI+4wcPnyf7jO(r9{HA6PG2)e6r5>uQC>N@ zf3;YGacLp?>x~<05;S&9alNZavr6O~H|ZHo)z`lm4fia*-|_Gi^Y8 zQO~|s>3tvT`AdVx!@SR!ICZ6Fh3DI0b*Ixvp$S&wETR3!glWaFow8NA1TF3>8j6U<2NmK;0pymnA>f*f=G55Lzv8_h1*WO` z*q$tZyN&Fwu)ph!=u961qQqKNxKJAAIOrKGec^azulLOlqvcVw{vrB^^JynQb%JA` z*#c@&Pvwq7Lyy%WEz ze9$LajNb|26>jYo1dqlWcCu&et)h3QQSXeglq zRwZjVhYK?{F5gdkvSUW>J&e6iUGG>!4fV!O zo>}{K{kNYVD5Njn$=vKvFKco#EYlPkyFMtiH~Z1FD!MyQ7^6&01Wqy6x!uxU{S^LLszV@$iHWatj*4c;_S&Bf^SYA*z) zMig4a*|z92IyFJ~=xXdKe64nTq+gjs(Xu-3Zjnz`9#gQE*|_p94x=OTB(83AdE-)$ z)`uBxuJUX0oOdVL1`~?=9YuL^Z&Ov|V`4Q(SQgV8xnq|j&Pb%KP=;`o8&$vTQ6~g` z#ujJCu$TtFE6>QF;O9*Fpvkc=n0u&K+Bx(!jgk6Qhmi^&Vh0{_N1iD$cMD3Y`|bB< zdog-brVr!O=o_S5=QOtfuXtXg)FWW^ve511I?$s|TU{Uy9Zym8B$Fo{8g$eZxz3oC5QTH zJ%I_RNR|(d;OAWn6D>O5KX+Ogc)lk7;L|?FLnI7U!c$H5=otdIT&co;+md{)bZZg% zqWF#9t+8j4=H*9SL0sM+!bej;r-!Y3VxH<(m+Xhq*x|?DOGW*nR=KQTjk~?B`#f(| zz&~8jD_1_>mUy5-(q+a(ElWK_cjCYh_*I>^Cgj9>^u-?Ba|;S zXAWc+#XIh8EX?}4?eWEmPLjP1q%}$P^@@FSZ5JoAPU$|hXd9nz2zJABo2`fQ4s0IY zIMS|m3}ea6vM?{QwVSMB)5>_??=~N^B3nP(B#@>*fe`UtDT515z2~r{jSH0JztL=K zRBkkKV*5bRLi>SOUR~&!^BgsTn$Box=+>l>egjtG*IaNnOkD#%jYF|VV+Y+$UJYZOznT?~~w7Fj? z4eb&gGOqx&Otg~^6lXX_ze9t^lxHspfc)|rqX*#~Lk6~c(G}}Hi=S1ktSob#pV7ZJ z-qVqOElL(7Afqa8;BiZJ*U#`~h4t>_ER`0k*bjcaM0j||-|{D?yO2Kjy*bb`u-nuq zEZsB`a3G34Q}@mX?>QIsr3|HQE9;Aurkr&F<{DO}H$BtT#CI7u2fwS{f97b?A5&h} zd&_rFeQ)!1z`elp8jEqf>QV)jN|?{1q^AdxIOlYCNpJmLi#D?ua#o;!rEA5@jBNhq z7p3=UB^s-F^Fz??8YkMjQ+;nOC{}~RalFZQg)osFZ|pQOJKA>SQlrS!gYeK&5xUcQ zq9uK|Id6H45AoV;6qBERP9aR{EOK+)$Cj&EyFC?Li8w4P%Dd684uSxt*go`+$si-z zd`JIa6WaW1Z+I%!jofZuF1fK^xoYfih({Bh5r}PiGj_gzq;Xg$lVhI~^sMxS_qqo4 ztIR1Q)%Lw<++3aIhExi4AsHDxNw)2oYMhKolP#PXHy$@oV(wklpYD`Au#k2udd#o8 z=;^&q{|hCu%%mI1FDK&S&N2qZMMqCxD^@kwQh#I%{l#qgr^k4rZW>x;-cSDA+G_gc z^#vXdF-KV|u#IYc$Q~1;u9a&Pz^#YtF1%a35E`qmPkBal@GbKJ%6oV)B_zJ^bEbFB z8VfMvJhTCC-*eRKEZne1D8r-lRsH8sbMT{9)NqHb6(qvud z<2i~4X`+;}U3$7SW3_#$3kL)8JjwnMoPFG<-5G3d$(d9BqS_&xV{Hz+fHd0T2m4B| zHPSbn)$$u{r1VkG(DL-emE{mHIwU^~eN^_zY$jAq_G~#+cduGVuxqJ7p=zY-BfOgU zg2X#}PEePYv^d96-ckKJ*ci@Po~CPo+dPJKC&>|R7qFSdI|WF3)@Q$zj@LQN zHgndJ^-8{Zn}|mS?=!Ap8M@x=@p}&na%keyU%a4Zq=gPzGZmjcH#pst{6RLk@j3Cyh<>|=?g#XDA&o> zadoF-pcIT5 z5wY53jg~m^uI@zb{V;3f3^aD0Grh66m0_(h zUij7B1bXWWrovTA4LMM|sk5>Qab|XThH|=VPJqbM!?tT0WHN>%2jbyE$P_ zN)d4SD+gj8e0LQfZGv)CK@dGBE;pl2_R8k`w4UUQxql@S-umw9*kS(TXM`Hi{BIUe zA-O_nOS|{456&h;%Sd}Z^zKT#Jr7czO9obSwl?o)b$5z=-RjRUInXG@`2FNk5K2og z`6SJylf54oIXDy4dq;?Pve!UF&yrw=sh4aOirtm z;0!t6HQQ)^kLO0Yl-V{7#@X90byH^zkM8Hx;{;2zhyFvWRJI-FJKW|({8uARj%VVj zCLUSD`H6OZ!cwsg6Xi2~nFTqtOb6R!W4*31eXPNPJ)`wGUh7ouv#zEU#xxfiwR(Ds zwKl3f>jt_FD!4_P7>-q5p{t9NjcmoLKDmf*X5~HQVj%0x`$Vf=i;IryOae7NGHmzR z`OuH~tpl$zci|WeWNR(in*{V;rc+m_!cZ#zxY-oJJzvnJ?37Qba_?i;=Kv}__ty+p z+~F=Js6)xe_~-*0zTvADZ^o_1N|e`kz$ft5Xd0zX2p47d^5;h9AHcA(L&{dU#>}jJ zYKMh9_7{OrUQr7)53^DBXi5Y1sbLU3Us#(ytk3M&z|O;Qv;Lj2nnmn^O;r`cwkwqS zYQL*OaZKC>P0b&Ny{=?$KpyBeOTQ^@)y=`UGRg2{cd87LLSBekWd;j%Vf&u_d;JwY zUXr6vP7MjC+!?tYDa75-&>su_DK;wC8D7O@^Yb@^J(HPF6jr! zwr)MnVO)a>Z=42u^%Y3$oaM&!r4R31*{4Z}3OaBWg07%_;U0>bMOCxJkDZ=wjy|At znnnF#>`fE*yokfq;V$-e|qQ1 z8C9`jzmw4BcY_87`SaR|xTRKkc=r1BU@Ve@z5D&$f*vGo3M3t$XN(n$7@D5dwPYu5 zm41q9AD2B&u_3Dc%;5jnSNL^)@#^N#8@c8x(%aVbP3yzQJr$B;C0Hrl)hc&E?tW`0 zNF$vu=f0jStfEsJjr4tIpTh?FN#@GMcEq98326hP02+omw;!8Tza?P3mZN(XpxN1x zmpoxg8t^ioKl+5+>QC0H(5II){#0w{Iw( zF{O8Qdnh$RtL!yq!?@I^cd;kKMKj8PEt<_t&kbf=mDb;2O6xYd{fc`=Jj3_yxQKK* zz3(|&> zhBZrZ&krONxtVP<%4{Crq0N9z%^ z(~L)s?>K0+Eu*O}F2_6jx-fIHX|)-b$Ng@sg-z@TmXvUvv!K*fe@-uvFjcC~RuiWiSfIKQZ8aU;1h3o69HIfCToa+%;=t_v+Q39GnN zHH*_0W@V7Z$l`mZlM_BS<+04`L_L*3)Xo za_{xT1oYA`6YRAF2Pco0ek!tWS&FQsGU8Ex_r7OAs{N+A^bodkH0)K;wwDCWtzVnt@ z+&pF^A<~wK6jqpBJAV6dhv`g$#f7Z1X=*v&vSaO?Mu@K}XSq2u6BRB$E7dRebcHt8 zX14;*vkjz9lxw7X0CFoIIr!8cJ5xq_Pp3wH{@jfBq+Bcm%O+y>=RkUivt0Ujq9bZ4 zQOh%&zpEHVC-Ye|30b_Py0P5rkw{sF14roXkJ171N0c6-DSLu+u{cUCs3{8vZ93j5 zER=zr!R23PU>YJ2V6H%AZQGL>PStbIJ^#Qj=jA_imu%C$!0_1wcqwF!9~;}ZnZm{! zU)kJzi}B1hNYSm2=#Tax6Gf`2D;zHfl5HIazHd{=pYl5QOlw||iqz|%qG0LOIxEYRg ze5Rn9g<>=*G&zYhJM3-d;<S~Ruf+rsJC`a=w15*vD#M8Wo;$S`<=b5T84>w zWGjp8vpdoZ)6vNs7IaSMU~XX1)^A4Ed92Fj7iTSdLbHuaW1Vci_mA$_chhK2 z9fBesY`&A3{102MG$nsJ!&Z_X)!oBQz;1$y=jbXH# zx-UW9 zQwl;IL4GMNLstgc(0fd~tiHO{9o?FNf5BUIGf8!o0h(>gzRUehmjbRm=3OJXnZLUi z%$eQUp|N$FnUdEw(n`euHS6#NQV1E+53^?Jo@=lE0Gw)qj;Ho-FGJX{T0oK&Eg zlMrLL>P1uhcI6hKw`eH4J$Kk5R({??!B*AMB{p1kMc4in_uiVmj-<;+S%dN&Y4!ib z-d9IOy|3$U17lEO3j+coY>RFI0Rd65NNE^a8iwu^6h#oQ2&GYShK8X*S{jrdLb^d( z`uBeKIs4rEJL}%N?p;gIU*{i}OORpa`-$g$-zNyerh7XCRZZ zLBszcv+g+s)6;rpzX#qawjMAYw*cLu-fSt&;*+Lf4Knu*5D=;{~|Llb>bbx>Ih9S(UD-P*bHox=nJUj@8w2YBTOMhec*)*_&>% z%ggQq5v}+ID^2qR)=&akk*Y5lGvr@mz>#idB~!F`jIcMla&NurVVs-5`2Zn)%Ci2w z!Dy8%8~*aBdMi)kH`=5O=FV)Gp~0G&Xm`H|kK)FvI0^SX`Fk0hF(M>z2#JK1BA6IzVLlE~o`o-yfja0ng0P4op3# zBI$artf#WCqn{?s7&^Ndw-ghd^h$D+jKrQzQ@wReEdk`P&{5!PY;Mj2!*1S*0!_VL zSJ^4`*fRI^xn9pVe|5}sp~>QL!RzJ^krOf<(1I9{)1aDnQi>lgamxuNJLmNvCe$m8 zGx3k2{=d8cwD1~vQLSedMOdz3x(C6CK!5MtgMq!>?PBUo=11y(tY-OZS6Tzpttc$Z z9awh@B&dp_=h5a^#U6>KEN$U<0J=pV7pYIY@ACMV^{OmlA>kXTV=gvx>JlIAEbbN^ zl!!<3!f*eAmOqC)p&|tUh}-UfMfmPJj?Lwmy`6M9%ABo9vOH+~?_8z|E~yb{p&xB^ zqfpiuFhidjdKHjrIBR?&FF|Kl+$xXWeq=wV>2dLomA|#tM91Je4QHY#QA(aY5f0w1 zc7qEOt#v5<^sa>=2o4U46jvV1c1>hC;fiUw?S-+5k7b-_s@0l{edBn}&EV5=i=#rC zWv~-RnkIcdv)ksF{M|LlK{H&ZORQnX)!LYD;m+e!zM^4x+wgHq4NI4ZP)X52-Q9Rz zEjWBawi8Q)(1tD3Lt^M^q?NCjX_(2ZsVrfCl1^atW>R)`w#BDM2MAzBpxgN*5uIue zM)Bb{SkX!e*GqMmd>SaDQ^=bKI8a}|?y)K*f2-6(6R6k+_qsB4tdO)N>kx6RBw2bS znPOlEndsgi?1Xqfha2_1&tqy%O%ud7S~svTQ`fgPMfx3Y4P|nkUe(h~;ifTa`PkGO zcUP8|=fHEffw~E3X4vAf*HZmYW89aY2Qr9@d0mLR^k*N8x?dO0BDpBxPQ>7%U#7?2 zItFE-ayLV@WK@OG1s|)Hk$$5Y@*o@qw;`&!CsVJgL|IRw=~bMGXM#AB<0U`!jhut6 zopQ{SnC|jQL8m;*4!Pukfs^`{0NWhqdfMqnfS#obS8kA70cu34Kr@%zkjt+y*3M%l zCF%V^>JKChH3OTT1-5b|JWLdhX|s6{buGKmeuqJ(NG`}Jsw-8wkrUo(H^E2K>&Ni3 z0^j#$brsLTnkHK7`5 zA=5g@gk9^vW@4n;_6tqz{W7D_*ALFy+IX*Ea+WPx_I=CW#(xT2|B4!K40GaY zL+nxUfH3uj6b|$jg;J`Vo!@AHXgEPBIXNc>{Zh5d_zGse|2S;y&U1Y#0Gm{**Be{9)nXHzTcZbp9xRANudH$(Yz zu!G-Lb~eA=x?jHxO)BcWc&reeMHh}~S4gLcR%9Zy3UM{*YH$sI)PPbKIC5 z8E3%u7udw?y=RJcj-QTc5TmJ%^c#c@u#8@HR%KX;fP$i8nptP+f)0=oWb{l?_UXV4 zA=OhUg_O?Dr>9PmX}zFUn#iM{SJZPw>3tQ;W0;p4Zsa%X;P&Og;nj0$0iN9C^f+8?1 z-`<>zDOI)+cgl;A|4>XF!#IphS%!US*t{lRw zR#|v?SdYB43(on#Il#kB=eS8q(EGi0BvuYTtxLWF+ve<=Bo(k*95z%TT@{(KrL&L> z4gw1}@ug-)KTJUr1w%~UML%=xy;Bk&W|SNLC5(=?Q`s`quzzZ2uv9)MpR z3S^nq4Ck8d(m0;f+SH2IQ&%0V)|M(B5_OU~8CYMcw_2CRRx%Y@3ciY#LPsL zd~@6t>nU-u>)HBDv-W(8o*TwWPV`5+nOxKJWUQr6Z(=U=7=71p|K@$Pav{Qb)(1N^ zSPbS~{pU-^Oo3*(XGUXM@`2Z+jWI&RDLo=+t&Yy^4ypbGZBRn3?Jt<~Q5>Y<56;nu zI`TutN_#ngBnVemakeco5=og zC(GX__^ox?ZxcY^??pJMM?#VNHb`XQs(D{-3d5tb7H+^;;5?fKlVji0)%dnvl{AgQ z?`$Lrl5D^+Hf7 z^=?vMOOEBwxJZ#6DXoB<-v$a3-cie+VB=-&Lv#nG#OpzUyb)Bm~L)`ZyN%}fKB!2z@fRa?FC{Xul{{5#kQPHWZ+=F zw-oHvLuXYo-2Elze#H+`D)vkY*{c;g=ge<->?0R{{ub10t2*Ja@{aR2E20N6a{763 z)oF-v0}^k&Ry5W zp-AJ|a-H#3zE?WexkP~q7Qk=P_9-n=)XlMnKPimB{7qYuYqPCU%rW8O*Q8opgvqBg zrx$|(7ncEd0=<5Ts<_pl(q-c|1B0XW(N8Z9P8B=MPG}$bn1Ra*ti7t;PI}#b?==T7 zAG2W*T(!tCXjv;eUEQB;D7CNt9o`0Ij}yUaXi$_oJ}~e}1^-#cd)$wIL32c&G0oir z=d_^fMFs%Bm%++$dD6)terI?R)2Wib8IiFyE`(WIx$Y%q8}Hanjqi|X-mS4a8bgh` z6^)%n(_see2G_&jP_ScW-nx%`*O&HgH3TUHgn7A@r$ue0M+BeHUuPq^tPSl?Sko*|8S*4;HJ)c$7U0O|e>0TL z|3;f^oX09aQ|sbnzkC!k8!3zvPJ=FWl+JYQC|TKD=8je9{}bN6rOba$(1Mzn z)JEmlGE5IGz--^KQ(5)hjjLc6uSy4kF|`$_Kq^_E8nLRTTTp9Sd$YVyH{4#Iw}fHq zGtT9){)UKc?XtTnH829D9?VzQOcrm*wi_NC1~(LKB`>}8J7w}! zh*og#q!4QDGtnW{FGGN-ggNMc2ry4z9NO^Lv~HKAes|;B`9o%Jj;qQhTKb~Ua}WfT z2?V+#xZ9|;{pdQ$@2-k66*$BNKo9O&;a$Nl@K(5N?zz}{!kXO$s zUc8o-LN}HbA4_T?~MEH+N`cMJh>5p9z6SJ z8w0L?-Lc{MX=9b(id~L8`y!6LX|nB^p~X83ViWH5@;$b`N0ieHHcw#aQ5xEUUJ3j0 zuUMaTW}hNkvn8II-hE-1(My>Z^)O@BBv6=Pyz8Xcq)lUU!*h*b-{FJxhk4AU0!h8L zrkQX`DX&>pVN$C~`K3S4Ty^8%0pGV&N|r^_my1CGq{SbY(D4lCJa01B9WP0m&pyad z$|%8g@;Nn}%1&#GsFKdz6oPVYVC_=|kJVRei$mgrmLusn2Pq0Rb-^vETk+U%pdE9# zJGxOh znyftn@;L{MEiKb$t$Z9_3w3Y9;;mfl9Kv1OUH$4AL%XA0VH)`1O0>U#0IF-0_LLcS z;4j$ZH)7SEzwTnDJg3Qi343QHjvGFlYgNnHH#Ut)-j1ZuglebUOYU;?P3$A|vlFvj z?<{B)-gH&Vqu5)>&omlg#4J^f?zxZMiptT>e;q=$MBVDK!QQAYIP|5Vo0LRy5je=& zJT((u&T+{7e!npSe3!NFC#5Npt_mqbajabQ3dmT$uP9k{q@jo>-bN=?YgZ2 zO;k&Yyae6ZTaB-|_Fq|*o1$qoHgC3M@vg}dPAA}MEm+NmHwfQzW^Yc$O+DkGP5>In zOWo*6Xgch`bb5kRKgfkd5`R}lCXZ-UKHxi#FvcN%!w|t+CK4^Eb~cz!_+DT;CO0e% zlDbk4kSc~oMbXn8COLL!XI`Xm4K=yC2u%kwQP)-L z;&vC+mj$ZnAYoJdmJn*HB{BZ@`@QgbFVfP?h=vj%-a+auvmWR!-vPg_Sqs-HzVGg> zm*d+hHx)1syBY$#jbIPk--c5mHf6|P72yX`pHJg1fu@Kc-YkAnBknu=K6b=G5G3hg z&zkVLvHGb?>=#`|r=Bf2`g)1u#jMhS3`lB;CeDAWc#NItNUn*bYlt3|v!_He66js-i4e0n8=tPa){ z7h}>?0;I??F(EW9#W=1_(jgj4sv| zT~utXzrFlKDAHG`XHbx{@j-&Nc|{ zwP=f#Snxdwv$sNsUz&$Tw7-S$@aC#U0>0KEkmJ&aTi!&A=7yXax#nCB(ou07%3|ub z)L3$(wKUd>p{p}>5Ex%xIG&~bZCHisJJX-o{acSBmu=6?~g)Ky!?m8iiVC7v#l!aj_*QW z4E1ay8}7}uFnr9~a}IisXAxYA8@F&aGZ*%XWLC-vk{2vjC#!(w`$4JNwDqhU5^Z@*RiA zm$c>8Gox?lqT@q>&~-2d*sE3FW-?8=GSv^%$%$r`B(Lj}#EYg@L*AAXx~I0*Rqv9)Oqm!nJrl{?i9-p~&Jg*!9>N9hIB}F<+x~0dQ zKmi>C)aH8M36^VIYRB|XnOzhpgokVfQ?|oZgSj=GOGgh;Afzn1Ta}kCJ2Vv~i8*>J zn<)%rce7>+U2D5CaT{;VbqpGi43X7;N9Szvl3b{Qg`(MhQa=0OiShA5EM>zqHsiZ( z#(>(%pmU;qv{y{N)p|l_VhzVaxd{)*aRoKhNh++54xFX@ggXs=m{|vGjCJMlb);+$ zyUhIZ&ndh27h1PlZo_^Asa)n4h4)*9RkAIo!y^n@i3V(g@4T)*;|}A}8QgU~{kpd9 z`3oVSaxtR+>RKYj_E2X+Nn1Nx1yQ6$}chO65 z_tblyhfhm^o37{Z=J@1EB6owd-rCZG_nZm=_Vg*O3J>;k!9Mz6uui$&D(3b$kW}(v z;S^3oSE_gkXEd^_?HEG(<4sfHpejt_9*S#C77ac`lduj!$3i9Bpg#HG2Q?x|nBB>v z{J&zHFo0%OTr|M7+ZczAuVXRT!R<-)mcBxs2xQdg(BeAqrJ-|emYsgZ3L|b;5Fy8b z`8pF*&i97j>ML)=ileF`@ztfjfWOT`?InT9G_j0>Ef#C5M-?M4}1J2Br<3eRm8BG_1=_O-&tPeu)9a(L5C0DrzdAX~6=M zo##-=OefA5by|r=046KI(x}L=y)MJ{Nl79R#i97Ybx>|(`iEBcP{@iLb?sK@Cy-3lN2W>ML{#8Rq#Q;{jXjg9T3L&Nfc9G(DFAx zSt{bCHCFxC#T)>WRY^>)$>igU?be3a$h!kjJNF3#o?c%A)j#q3u*kVFONmHvxYA9i zfdX-m2K|->S1n8it#C(#W!Bb($QD6$jK&=Y0>8>m@OZ`!wNq|suCUQSN)CrihK8a2*&T#H}qpYO!s?K`D0%PVK;Rx+Z* z+0ToHlTlxVl9K=g@JA(lk~8UzP-pc3)elC0W((0>q^D6h zgL69d4OcRBryW38`QZr`ZhnrHY>Uw+{Di%2W#7Dr^TeQZvcSo;8`Oa(`ELhwsygfN zo~cZw{x~JcqAdi_d%j>a$Sw!KRtblCb~OgQp7LlXr$x9?OOBP#Z_kxB!*mX zH1yAYUjbSzgBRv%bbLlHBG&i*q?R%wCJWCo^ z#j?;%c0|gJ6k%5=E`F3xUaQh}z=%H#=h&SQ-zyP}b4<M<06zjZsIt(-M9EbqKM=W_n52eZyNhuRj4BtS~1NTi0Q=HowmQgt#Kc`pjW zjr|4iNldZdpvxqEgqVkG8R>oRdjMDRQk9)9#@r!o3Zzz|>iq_hnHIvEh`J{549|Jn zJW?4&=l3`8N_(kLf7G&kS3XdV5DvT#9ewKS>3Y-?94OSF<1jD>Z755ST|Ud7d9-!n z$N?sbwp8+2*EsH3K+!!_Wa4v`t=Fz<9YQH8J(x;Qf8guta!FKlfaDywrwm~z`Tf*~ z^-<<3&a=?J#D4$QQxWz2>B^CtDo9WDS~9mP$pO|(=>v_Zm_T-z%;qAB=o%D-QnGI5 zVVNP14K3(EX;?e-*h@G-eQQds)jE@0J{&_a^N{krYN`@TV|~5Nf#=XUJcgsPVyJ+amBo%8MF~V| zYQ6EIvKQU839-ZB>90P=yUjo|gPX+Gyc8G*;mHbW-KLpxF}#NU2u1AGGd)+%)J28w zCHHePE8yrdBNiKjKy@PerUq5o+`O^MW5wXiP{F8$Q{y?F86atOeA<3AIHOk*JD<4{ z>=a<+z8bK*W3l&r0cl21EDF~t@O`luE>K@z)4J&+^F$`eI5azFs7$t;&Em`KP~VuK z{?UPF*v~I6QB==~)?G1DbOG9g<`1KnOCXY8)|rU=trbM4B&x-xf%M}0J9aqvIG1uf?sxm{OHwxO2Qf7(L;g*znyzo*D0@u0wl`@2f_SBTG>*6xUp#gxAI zLqly3@{e^-(q6G9vR)B5;}>BPlX@sfRS>xMMF=%HZsh%`Pz0eo>~i{&HRCK`HFy?3 z;<-(EMRtIQ3^}PPXiA$VyD(M`54{4N)?ObiJ$zB4y-;YaLs7=Nmlf5ZqU)H6`1d&0 z(ij&=E>&jB35`=K{wVg}DuaR8pp2W>>rI){XNg|R^-SqWcuHUoepfIEb_g2B0CK&tmFbYANWuZF!1>77<%3 zd}&m79lxxSe$R=TaZdGw?@_LEK(UV$>C^f6yy~hy&QLF>a%?1D1LbO@ z1|cy-yd+Hd*zQUL%qs;pc30S)c5hg{N-*joxQY&*6d~lj86xm24xZ}7kPD|vvnlRV z;`%1`ZwNJ9+L;f1v6qAmUwbFc0GKv}ashAJwd zfi!%zB*)oyq`f1+i7Jai?piw{7w=Qe{IUR|VekoX1cp|T^%dVNmL2tqOw_e>tzrUc zg)nfM5hW94&#Ed3&n&6a^p_e+R8stJLpq+DH508dixV&zF%P8Ww~bQ-7Aw`6N!D|W zUa}(dSIm2}6SfJjDyo-`y%)4vI4Xq9)CF9Y4a$pr7}1p4W$rHdh;W?qiL`eSib_R3 zr;^^m(q1n4+EO)zp0}H&-jo~!j!O^MqgE9kjrJGX4e-OxIG^FaEqx_Y5FivS>PTps zPWd3x=s~({ai366#K2!l^HIK!50J;mCq7#@=>A4rILyQLQlY{ZRjB-cJU+eKS#rZ5 zQ&w-4qA%vgg0REPm}A;Y%o>w0)2jm$OD&IYSR#Ky*&7v2Gl%T8(E?LZs!>i_jeqh}x1tcO z4)9#!&83EyU8$xAJMHdE#0g&}@tzT)p%Iv(SJZP)a+Zi4^ekyD-E3;WYt;*jJEai8 zNx;*voNTXM*|=%g)np$gy;imOB~s8NEi{V_iloQyq|By(MrBV`o*_0X>EILombOMp`*~A~R5|qSxvp@{ zhrzn-R;2+qxvsRIxh`1_f^n5ejc)TajXce7&M?~RcZE@{%xRjUw2aA)kAlisvrUf~?_5v4ZyZ78PM2pEsK`Lzb&x}0lCDp{+>|{{Gb(fZ zy*lWJ6hGScI~1cjsYhIz%;tjt>3Y#Y=?8+#K~g|Au+tfvVPbbCUOhOg=X z>p7P!Ww8ZUFKr5pU;{>vcJ!F%J@k%$ylD{K%Xz)B5*n@*^o`CX~uxeVC~iaP-O*1Iv)w1RT?P`L+^p` zT&v)%NM;)YiChXZ{wteQ7$-l;IIH}^b#~NL*>qxrrhNFp!Xu~7hI2no=ktA0ujoC3 zq9O|gO;9m8|NI4w&F@uYGP6Z6vQq&<27AbwbT z+wa;bEeuLSiCYf_q1gQ5Ar@`&{(yb_M zlG<)QrjvTT8G2L1kM~5pN)DUzn|C#7LzOJfs5MJ@Ce^rDF!5`4-8nb*p%s8ZH0Ue>E zQTAaWDNeRc!j?7bSc2`&Z%JxG&IA4MLuEZSP?`4Sd_SRR9^`2ixzWwSuv*@I+Y7(ojy3-j^qMcbvLPB#~x+LM98fw7Yca45yBG$Eb;xp zgi;T)!W%?;ooQDckX}=bvu!Jo=bW+x9>yZ+%wD%k+iuMJ_cK&vG`tttr}$p2#O~cC zpnztzw9W$@pYCAhei4;>1`K_nj1y5lyhEVU>wB{xNAiQ;^vgvZ>-Zacltw}}Bh^ty z(LBm(-6=;{5KdfinU6%9y1KdmlnT^J3%(4sr22yci&*nbT$LSHoK*k%2U#dz;&4%21sDBwK~oDH@x6uQH9}GEJiegTx))3nRb7S z2CqW}NCbC@^MZ|n8ChxCP1eix!{V3GM?AoBtH@0@t`(&$bJ0(|0!JGR`W@~C#7>Xu zN6g}HYMFOPR_9b>db151GsDWAMU*p3YddI(K#=LfoLy1u4yc{nnm^563cjSY&RFrZ19am4^#SLT=Tj0BxLW$~mB63(*Wu7J8~4 zsT&zw$^fJo#Sq1$^=!$%B`004bnF%vHHvDDZ%ZrQGbuJ~<)UqRDPb*Q^sS<777EQ; zAXy~7dXOUHmUe(^+-ud5G>|MPays?fJi}aZoa-s@AZ)q#exDswRNI4E3k#zBg}qLx z2ln_ZAhjM!*Q;w{_yv1B;IMxPv+29QmSeuZ#h61wW=zB%u5xVET&uJYyn>7VV8*P~|<);#xJv9v9k^_iYZu}@>wo6FO&qUqP)HR&RZKnPlS*m}3 zDts_+jqlkrLQ_n}+q>jBjwy?t;9fOQxY5SLxihBGsIl|r5^Xg;P!Z-iHAd8Gy-$sw zkcgNMte03|1V0aIf?Kh zmoMXl$9L((goMIR!oCSC-)+Hg$!(Px{W^)9iA0L!s*Hpz>fs=DfKR@C$hWnNXh6816v6C+soT5|* zR*G&@hK8H4;AfS*y^G517g^=)oYFf7c4eP?I&~81TJbMf4bzA?)xzKEc$`iUE{#r7 zy8G2M@unJRynEcxyS0g9cf|L z@+~KiiLtSQrEpKDxdyA>0vkI+Jr&utOPn(T)AULD&G4z#wxS|e&fUAHB>Y+kk)BS0 z^c0ue+SpXAP05JQ^4&^RtEz+OW0d#O*#BG5*|pVjl9ee)Fk^SR5JVTb+0m<=yAsN|ofQMSOe9BCxx?zDa% z-;t<$epcc6i~B0^(hgGhxTwvHeOWqOFfFyW1Ww`U4jKWWv|BBg8k9&caa)mkOtxiNYEZpzl5*a!QRIunm`$gK=DXyL<2Ntldf2*% z9bcT|O213KqT_zBNAxd$xJ;3Q*u^Q!JPkp@rjA^`)gn!ihzz;_yV59^oj7^c9B0g# z^ZV{mv|0@6DB%;*6^6b@*-iOlIhElo$0$RugY`_MS&Soj4>if^>j0k{v0Oz{=W&?) zbhr91Fyt!b@;n)I{AXJa{`vE~%WpkmoG5=16?Oiv$+PbTd4dti?CM;C3O>BIO)5GE zkETN<4g0Cwe|tZNPp7!=%l#xGb$+Q~BNNw)i5{>i|kEd{X`fV81%$SJO=l;t%ypqzxNLlK7Q=^TQjm^n+r8` z;@7;{izLVNWlz7D`DEmYT6(q2wv=; z_H5ymN1I7I)mE?b908NG5^0Rl!TaS}hm$XKmK4n6N ziUe=*L@&gVFdH-`y*?zQ7GRTPsh-tFJQH+vy=I3%-6|R zyq&wq`WNxB;|l}D#hHe3dho;vw&V8&F>yCY6wj31cXT8Gw!I?&f>XiPUvTIB>CV~n zhkT+mji3ZMpX%YiHYxI9%w>N9w`4P53zQN)5kd|!x(BJ==nV;{!UqDk7@z(o(Zr*x zR-!|C#cHr$Bi|AWwl57EqG0rE2`-blf82Z;zNL%$&p-1gKD8&LvD$f4rA3qm= z9XNc53l#wnua<>(Gx=R3HABpeO?}2LnP30L}67 zaeC&%?!TaTKtANxRE&N?rn~}we&GL_KfL45gG=}WA;q&y|M?^OiBI6a`cW4-;6=X} zSp0Q9{&jf#e9ql}{A5WkL?7@84`_Hda`msn_kZ|QewN2Dqba=To68Rm{R>wS zGb`Nq)FFH|Hvd2rzx;tdy8Z=Tlu4%c$gh8?e{6esrNhVcIa!VUM}NNC=YP94ygwok z=KYJ4KWmBnFE)E@@-fKORcfKE`vtBr|Lp_22bW>w6&kw#>PY@Y|91Vs?~Hzh$&oBU z6#wl5`1xP>_eJ^(k72k-pNV}?iPBR4ExP5jFJ{a>oaHoUIFFm1 z(dbGK@Zcy;_p)(t(9&Y_FV&~6@j1^bz`n}LL4Nn{jmrHprf5Ch{)pRm7kn38&b?tV z?lW#_iaZ{?_=^sSf1LmS2@hURLrzGxCX2)W@l=2L-)3$ATq}|{j`#_y@;|+o|LXny z^ex^+SWeg% z>7)*Xf8{lshm=%l+&RDh3n5}MDZtX%8&TMQB|`l77X5W6(!aOpKTgR1?MeE7_`ZK{ z(O-Br{reXE=d150;--J!qQ4M6{QDODi7WM=f7HK$?mwf`pM>TS5b|%J`+vCo|F6gM zU$rP**{dTbY1LrX#Z}l4=2dk(}X$uLI<>x0L&P{@_S{z$!EU}*o1ZVs{*=fGh1cnr zVZ=uj7;ZkIng!Nzh_KAo&JK|%s%UCjfZ9)`+|vWG83mhxhQ2&=>W&yb;~<1aRdMyu zv0Ef24(IkE~i$J z8ZcnB20*Ua1AfNlo12?xPAT8!JC6hin~~;0SA<9kj=WhZ$yELGEp<}dHScNXbt-82 z5@DrPihdHxTEE%ie_89H`O3u8MBeb!gR3qIYfV_sZ5hnKPK(f;7e617N5mjwBgYo> zUJm4Fy!V`(nCJt}f{b2+G6%|L;cHSb5b~;hxe?Xk6CPEx4Mmz99r2bN`?C<{5FkAV}8x{xRk!LgsBzpxht(oHHFs8Dx-i`fi@Nb&jx5M19368s6%sr|4(4 zj$OKRX&te_s9&hZH zF-UGX{Dn80T@;rULOIsg_d1@oH#m3IHOoODYot>sYb`D9l|%OFpIcBcvc@(&2|Xm6 zeT4ozElR&Ii3sJxR0YQVlg7W#yccnqCuFl$0Xt3O$iCE#XfG&Je{N{V22ox+$B(v~WWA7hsJ<4Gc`M|w!aObh zOT`1BX%b2cFL((eP_-~dI_T;Wh>i(+S9^EhxJBW3=t6IjC?e6H11W84aa8Z&e0*jz z0txHi&%>=@VvM))6Dw%7sD;2|kQ2D@%f_RdG(Ye^i zr?Np(^nU+Pj88a|T=d-FTC~@m3mbSwa2DNr5e$-Q$3Yik&=wnD zxhE8|nV?owgRihdSfNU~rYZO|W<#!g{W-54o5uPFCRUr{5bBILs1@9YUnO&T?>djU z;15>Z(7Mxsnw|VTecwi7lF@eW%cAR9mqnk}?ftHIr}48TZ4+mUju~#kQ=iS#y?1%S zlU6#znvr9G)``ZVdF$N7UR<1Zm4H!}sd)e?wmH=|RM6`+$G#;#O?$_~7dOMbvl!a@ z@i9(SGqZ9cu=vw`|K-%&NY+-DP3f=8ls|JlzP=aRxt@d>UD&=jn2=|VmDxLuc_Y$| zQf!&rU0I?wQQ0tUb#&B|@q;JdEcXsWSL}d*r^0uU zc3ugRBdnC)g*X~0?&ZDi0;*(Q3gPSX^?ZO7oZRXwh^P^h6+cla_+9{OhH_DS@X5}w zQeV^1(?a23N>6Qi;RLM+B){~#s1YpQ1=0z&kh~417wO6ymzg=-Sy5qNY zNvb^6T14sYId7%e73N2U;9JX?yI!)=f}=73mY2my_4CB*Mjsdex6gws|*!ECC z9Pxv*spuL{V-pu2T0NEK!JM%(Z{?MPSVbv6nA%9B_1B7)C~=88RnSdadn3f--DVSy zO6Dq)IPH!sPIah{tgP?7g*vSfeUl$w=4#_Ji>1jA6rSVlTngn_FQWb;-NWH}`rVID z%2y_2b2k^YO;PT$N=1S0UD@v)P8xCT536H-R0LKy$9qrNmS5xT@K;qmyAWmKA${j3 zRsy;YkLA+2C-Bd@IVY%=IyReO1jczVyqgE$oK%}0S18qY#EGe7=;6L`FH^glUXq-h zWOL}5>{82IYl|Ix&9#S>x;#MrV%wYZ*-yZZj{%St4HOflQzAYdU^o3 zrxHOK`DUk$CHGk#y4oEa!uyUhMe3ry4muLCig%NZocPfh74OlySO<=88ItpLh*J{$ z7l%?Q3-KVhVQu8itQE3J7?_BAO1{E&br|*!yDy&vSah;{O&1}&J2~|}B(tTPk97V$ zQz&u6&i`~5i}v?2w1=a5rhx&HJDROFh?1GpuqvVr>D| ztVbExzg!{t9Y>F|O46MG(j5`(aF7t?_gJY=_N<&%F`}<;@$rby!S7G$p98Op0dRbh zC|H9)`hhwgqo!~@l=cG1U}kUPGA0_~z&G1^q-0~06{9o(GIqnOKCc=;56N6u^<9L$ z*f2x4(Eo@^bF}WtP+{eL)TkFWQ$6M;etsbgqv2{Ki9=0fsITFg-B!+HN~el-HJlk~ zlkqNgI{R--bsE^($AK>)7vS=Lt!VxSBVk583}+`B1WfV+9eOro;TShFSK-K2Z;i1qU#22yG-doCAvNn#8BuYCL}OCc zi?}=~m!0d{8@kf`rsCR>R3^aaYao(Ifl{i6vv_W#YqR1ggW7`!BaGQImRG?egrwGF z6LEm^{jB7q#UAF0oO+;OwL~2Cs}K<@7W|!3j>e3+Nt4^nN5#TvW-j-Pqcijq=os-< zLuH(JE8uSD<*5@CC1EUrJEl@IQ%~g{X|b)S-hvcfZc{x^I?K|60IPAO_ z$K9VB+s7zap0TSS-s$TrDfIl^lPT*u>$-~>tDn$wInrXPJB(;z>M2B@aC|TjP3aDi zG)3PRr~a7HTI^7i%ah_PtOg2U|DC`f@jd75u{Uz@%8HI9mmi0_t<4x_lx?L#0JQqO zd(Q`4XVVhPZ&FfH;wL|p4-G)loJ3pR3|RHJmb$)&&qtFA2X8IxCc|@&cQ&)SB$v#W zv72PAy)(W##avkH++4r6z4l?P>N}ld4-a9$t7ayF#DQZy zq|PTnyyiw|d47Dz%EP!;(SdG8^g(*gnoTL}?Ky_4{;FK0a*kE)*9~Pf-{e;tiP{wkf*P@OO7Q9k`ccG{wK z2m*-Ctv{tI;HUnZDUEv83$V6wUD`;Tdu(F*adwj}iEUxNq||*-`V?2pN%oE^oAf}ylz zCaa1Z;oGPIF{Z)RX!U9z@3z*<%&o6sxr75+Ij38KTYk72#nC$uN2bPfOQwh-Y0iD& zx{=;v=({yyWD-sF#Atzu=mdStJZPUvA>IS7qqFwk${+hmq3p0-q~-aQk<%4d#M_b^b!WNfg4C$& zo<@AkxXRj5@R7MyHER`rxoiG2k4nY^IChq1&PMDngoFwj?^-WY9g@xM5{ah9E0U%~ zZbmn|jmGP`h?AdGTK{U7RBpI3RMZiiz9CX{R-$S4cb)@3Z%D>?{BXQP)0WqootLLa zsp!{z;*d}%`sF~X6Sq~bpj=OUuoYRY;JA0{VII}7HrwK___a@VK4zqKI#!KIVhsP^ zih%@7B$^luL>D!~TaILKSD+{Vy60tWYNPV~id*#X$B z8Y<4uu9Z)Yr&|I_w}3<^0yygRA;zd+1&GK+RfVmY+1MH>UnD&=gHll@Mr89 zw^bHST^epuGJ6P1p%{riv9~LNh^MH;8?TViv+L_nr)2r~_~>4{7HgO8nC@5reB}s! z^H3IddkA(MHZy!Wnl}vq2`~C?jq#=D5t?*`lK6;{{H^`{99mn(F?a^H|Ca@t%A@@@&^kDmUEb7 zoJ;n22kt_yjb=V)9k5RGeVtlEAox7H4m#T6QNLpO({j=Y=JHq_34K=Kd`RVsrVHA* zsb^@m&5Edi^J4U5-e1WANkHKmc)$rx5ECNEx8lf$v4q}QnRi!h;>{n&^;Ud?Uv6?? z=>2z)2Nb!L_hl@Q*3{IjgU0o+!-qph>Fr;FEqotH$taFwPDfjRI&ic=GB2agSm^Uj zNu#B7(&n#r*-(1X=7KV~6GDUMpMDS@`y)nhKx*UGCFnq!$$q;s=d>~s)e$b!Rl1|!XCb8DS8w&It05q z61TnxhE+O?ecdiSknc0#!4Gh?Y=6(K+sbdyEidpS%buD&*%pK?Ql#JCJvCsyRzf3a zsrk+oV_BFmJ(#iAywVz0)|Bi8B0sl+vIa=B)<;|`F^Q}aO`Y=@)qENCWpAQ!h)2$f z!gT|~*5}c0KyAV!YD~*-HrAKWXAWthv0ilTM`i7sadJW+n9MIpR}?MoII>$ue+vHJ zw-01XT^~$mB2smRx8J)i%x)@cm!B_6f8QT7RWxgM?eDm(AVOR}?5X3|rRLEVHmebI z@OTd&Lk6kLiEfU+gED7@kf*r5ZqkerxVF+V{& z%z>8n8{~FMAMH!x87HWAgYyL*bDp4T*<4`RcBmZkS^9shy>(R6e;+n(0ZIr8h=>S& zEqa82bSR<{BHbz7o!bN@1OZVANdf7O5hEro4bol0=pF;cw%>c-`}dsZoaf*B{?DW5 z=y2QXbG@$XdR^D5YzK7bF_|DvaN~sD5tFfVmW%k$iiteXNJb4?NqYws=^^-Y=~->Y zZ9jWXI(vNYtS}Lu*=JJb6XLy%8P_;E%VMOXH z=g;B)L*OX zq;${jC}MLqfBrshw6rBEZo-GEJ9ln+^e?0;WBMdc6m7xH8J=d#FqI&@rIlEn<9UPW z?_|E-(o)eZSW2w*dh5sz0A4V+-+v{fn{>q0n`uv|vnYaX6a|S#$ka)A@t}}BqWP^n{VE{LAI1MMdJHh+8Mik?n;n7)Os*n zlwVh@c0c$JXQ5hp>j>|{J6W=E&inhILdNra{DLRf;mWN44uaH7w-Nj(WP|hm4tQ{T zH2G8d(=d@4HGrw=1yThr1@W8AZBQ@a&-9I@xIp$7>TDUp_d!Hb zN<84t%SRJwgu_QnQLHIBrUl?$s=O=k-5_T8$cGC-`sVkL-HNyVIj_QYZhM2Xl$5CH zWo8RYBo@hP1xFD;8(A1jJFDXm*x)=Jbpk87?7AsK_7(1SBU2fS3#*9WqB!Y7X0yUw zdyr`Km`sg}`qfy_g_umoGZ2?hZeP+cy1##2>Sv36(OGHG+Y#+(5Y}If-~B=!LK9Nv+H?!2B3{>nGMK(a~+n~XB=QaoJol?;|vukLX?Rv zn{LhKP0f*!_lza2_S}{E-oR>k|3l`=6 zTPd#4G(%~imGc(_f0xUEaC%oAcd*-ygQo4Z74R&AdJU!NSO(0h~e6 zUsAItfMlSB=2+p|uqe=4^09c%<@eoC8*McPU1$>-Q;l@sLu1gAo9&*jHth1o^Z*co zx>>YxAL64$H=`BgIzb~`xK5kOkkE7dKf(Ik0n&zjPnM{?@8A!fp`UG2ifayrJ|Zm~ zqPJlW+o+U0V$Eelexk06%#A~H0Pd}G*P0cQ>o+hG^>aG4E|F2ikA_km78Y`Rt_6vp z*}tAjIcF+h^FZ0)h*Uo}J&2I1s>-7qwK)N`V_P9CP8_1cM%}}I3D2#LZ&vA!%b;85vE=2QrS{vZ2K+gam6 z!q?w(d<>UQ$B2?kjkSMbUYf0=A5n>01Juz7B>A!J7fxjZwDyi~EU#Z2Cx@;AR1g!} z+=lf$RMmZhQt5VFl`!z}C$-}GmqZ=mD^tMpyAzYf@bh-b@kW=4I}+w;GFsbjO&-cv#etj;nSfn9RTKXf51*OQu`EbFw(6J;T3}s2@Fb z4fg*E@c)HEI*gRn0=;zn)0i-UCh3*llh&1bFDL#xcYZsKOifZFId1%rGKWLYr5iy$3eUVhsq+O3S`fs?Hcpw zM&(C97s&McARjOBB^*!5PR;ODuNaghiK0i`d7QU%%4%&#ai97#N5)vjTzQBDX3+)! z?F*N^a>zVaP|)wos{TWf*e3*)A)da4j@!AIShEk=Cu-@}szFOw#EIpb>XuYbs7IemOAVo4qLUWV%G zi_Jm>btx`BUoTuJL9TOc0D6Zi06gpCJV728(rfG1r9Lix41i?Ob+x24;O5W9kUY>A%Q;|!{Q&-Q6}l?UlT6W`$iR@bg|HoJAJMv8C~v`NBkVBF&onFwPD@GYi=3^a@%zQs zOmetTjAv(aM8X)u&wO=V-PPjI>1o4i$65|*&A??!U#*uQbIRUuA)(PmjEvSUMf@s! zi%U}H{0dT9^X9Z$21?=*{RvXFO!){;=TbR(g0}^5Dwn#EZ za`J7Bald+W`jG-Id-38}2FoA!r|Ct0QD++_#BzX=+qB*!AfsL?;EJskD>*KU-ri2; zxP&c%;|uCw!`V>Xid4}_8H8tWJ*SVTKB$Ly^Uz0cEN_&Nmoi9$Jvsc-od1rLs9_2l zrR0$u6gjpA%cbS`@IIH(1rHwfWCe2r{`uN}cfN|3P&Up2s%J(@w%YThV5i+1iuxX zl^vAe89=$EF<3hgN_KdrR$BS$`1`k98Ydh01Bb@D&_@V=%w97z2kfi0jmdoxr*2%7 zkLpPYUp1MeWyt;r9RYsjta93HyYbM2slsW+*Aw*uOgk=+)kxPN#H#sPV zK3g@#Zk@R9n^jdpNZY*crZDUz;=dA2E+-%n7q$+z7 zwWu6VzlM$jO_ow8W+WrWQ(`~whp}rDWzx}V>3F$)knN!Ca`H}l+(`#L^t?Lp-F5rm zCc#@_eDOUX@n&xQgFxuhgo3)Oyo&$B>w{bg5&&1N~z= zAg~Tu`YQMdw~I!gHelkeG>bAG|72GR&dTF3TnExG%}U+JGB)V|MKcY`i8{axZ2@t^ zL#`}8(=-M2;nvD>L_VS%6I)5JP`)e1MJl?aTGy2Qe8FFn;r9`oh=r3f4wwiWN@R*T z@_8Q*j3<@~^BnWGj$NLCyrWVH;|aThqD>&Dc**%vI;y|;+Ls2Qq|{zr52U!W`Y^A- zM$)j^QGZKop?fmBnG;&-QqxEqrH<1X_&&J?Sc=#u&2< z=*^K!0Z@1*Sdp7wWojCHho-$+rt-E+i@&?~^Wsli0E1yq!sg$1U4wl9nKj9pMEfBM zl)A8Qg50O}2`(G`jvq_Ii0q6Fl{iH(WT*;pwtRk>dM0lA{7pQTtlcJG*`vcMB*VYnL__Z@IV> zngmY9%YTOYg7AaxOEI`LWHAF>4!;8Q{x2r7dan96V_}myK}*dF3urhE8HAg9BCW(l zsEL2fJF1m;U83kNN?W8)O`XJwkhqm0`HB01K- zL0p|5`1x?iSp~!|dZ3)raTu=>xUjDCZ+vyY$%b10KPmR` zC{M_s)B{61H+b`gO7_Aj1vJ^kJA2mXR%%MAyqM7GS=nYSjgAri58uKd7fonMLHMa3 zvSZaZlTNK6Gq)rYmp%C&vQSk*tF#JZ;Ois+G;gm$i$m+@*H5hi@uA%0jMIu%)rz;;Sou5LgF+Dmls&oFw20=FB+j=gPUWSHS#SdZYcE+l9jN{-B# z+2tQMs#=~pf@NW)ItP`r+F-&aFc`|!+z-ceVtB?d8Amw>j8azc-ZkG6>~#zqrtCiG zr(8XOh&H4ZtWHkDiTLjNrGkC}i6}f7S(D-VrPq<^*yeu+6gb(8;oiIfMRw1(3UR;D zJVnM{r4F5m0S2eba9%8WtbpP7ZMl^NmqW0CHY?86;7Skr$HJ%0K#`!bE*D9awp|BgZb zu}#Ls(rSq69UXN=4FXDIc*}$IxY!#u)25+RYvgI%npR;WEm&1r6M|O6(7NKub|Abded>D2uJP-=&dMA)*i1VU@Pg^XS%~v zB(vH-nn6U~t`BCLHtmM{@agu^R?fM9BXLJhs#M3d<^!?yhT&LM>NNH5P*=lJc*jjmQM({Qf*82nCp=9*8b|odNpm-pVDS^=;aCk zq<-Jkqr zgb`FtmNgR;+9Q`nD^$khKqT3p2Q~fAo-T$0OI%Q%mWf#{8{AMNSFO&j;bx>()kSJ`AgUxScmyvJ2e@)K<0V9M9I@jw$r6yW}ABFR9LrR6D?1jIP|i zw%}gCOzL_HtUdkwR3W`{@95s(V>l0E(NJ{*SmO~y#oMmW=mgnjoQ}UUKt+Z%0R%Uu zhvu-sj+=tjxH$y$8Iq4l%aIBx;*?aNNR>}biou+DEVnR>bjm<$9sJEQRbULhkBerl zxl+bPGEMoD+ZvihA^VnMHB`mgpvf)$5#aF~9YlTW@$bXEb5dVH%;qB#spBHpvJ#}> zt>42n>0DeUt(|rjK;5R9FGbVAvyhVa=Oz}x-Z-JEZz1fL*YwHaKoH2=@&qSd8m zldl^h+NmT*-F0?)DOq*WOz?M1^4)lCm>V_0(1 zls}i}EtE3GTRknfU0YIIx3gh$68`TTzcD)tdO4O;r}k2br}H1-(W4Yhhpr!7u3)VX z&yLvkD8~j%rB_`CFh-{(zwLrFUR(x0eA(}?x?W_YVJeg+(MRcSb>EPW`F#SSV&sZu zai8FM>WlwFmi^@eIvR6h;f?p>L>U>WaYZsNYvG+cR5EvNCdJ*rITtMx_Cs)RT!b5% z409$6z%(a)W&P?`)D$pKo=j|e5Ak9vj{Ilnlr_}KE<`|Whi&6^R}YYz??xgTg_h43 z^70*O6}nbS6}6N~1nt%PrcEU4j4sm-gGA*y*-*3Uj;h*tHpF)eMg697lOR_awS?MZ z*tv7GA74I`(*&8|B||`VwFvBm?`Brb9PQ296Hc|oslClFHw&f@uw9kA29YdjtZjXjV8~Iw<70Kii%jdWvFy{BgecZ|_3GpIY@&Ev|21 z4ht3mA4av)jN!Z5b?(1=B#MB1=|&27@Ix*Kt-GHo-yc4h&dxjtNZEB}yPdV$HsdwL zE6IJcaleb(sHXfO$Ke{NmAJZc61dWvR3}ojN3wiwgGOtaf=Lu(U)EPVx%Pq*@NR-i9?<+K+W1JO7da=fH0IhyvHMjy{-GCSNc~*Z({4(1N5;sv`vm1S zd$mL<|D#IRrFK0lt85Z#cWS_BOU%E!_^;J%oYEYW9t1=-;oe!3jofkjeb;gn2m12H zNx)P-5hJO_zd;45H-(=Lr3Lxfv3-50;&!)}GDdqIUbD)ayT(QNS~Cfw5D3;|d?gk4 zumBf>>Vs3|C!i5$6Hr~=2bD6EGZ=*}b-<$_rKNvF(*a~^Iz#dJwOIuzrqgqCd=MCX z1c%B_GJg4>wtVD<8jU?+It;Cb8d%M(B-CrJY4OwPsBQmau{**T&la;rWX>_WvdkP& z+kd3v#w-lyC;=)F@PBDe|3iT=k{3pc-{)GeR(~8;n|;b{cCdbwa`=%BznyAiS-24W7YH)&V%mWAR$GZzvBzDc5wAiqk-jCzL@rI-y2u7mX$e}v&tr~H+V{9GEOKj=|~KA zT&^VSQh0vB`~JYs={{h@NiMLjgl`Y}Sr0epLYF`Yh!Ay0Acx z>93x0lEA*XIWi{Y1^6!5n=x%n;H}s$Ln`D|2IT@;(^cjIw0b26o&L^m%HUbB;5h)> z+#uIWu~cAfV=GWgdj;NP}1zHPM^e$?4)tOja3$9qO z>6tDskf@c)PsJSy5jPZ=yqE0ar8P|!`WB)^SpnJ8G)I1DMg~31%2!}}Jvhg5D9VR9 zXaTvRrR~TC;BG6ZYEGEi41m$u)H~5^gaDsW#dKPSUZ1yxxk-s3k&wx6UDOf(%*6Td zAQM$Rj(cwZ$Nd?<*x7@ZDxa8I>mNGD2yeLOBBqwsO~tU$B9PSUAD%15D~*C+V8BDi z7O0Ehg}DZI{v`vw(mfoaPyZkyT;*AfGuY&z8gCk+hd z^MdCQ@_xb`iRBigj8EM=LypSFw-PVlPGTA?P&#$4c$?C;qtTOJp3L#U%;HSd5x=rZ7Aw;7FVFE4yE8WjdiR#( zshD^;{Lhd5-R3;^dV!xZ=gqOJr_z((n?L}pa`|EGkwWRK4ker6*llNG1%>bNv+Rsv z1$4O}-`$dtzu-E}8=yS`pQCG2z{gR5KyeA{`On^C158upy%`!cjF|x|=F&rnnNC0# z*5h-#>cNy0uLAFRnrk~VsoqzNGFYASNq+s}#V;9XvFU8a^?aAH{czeSKhTu58ASC@ z9udX6da?5{5?p-5U9qJqF~DW83zJQ8{p^eftM%lBbqUTcDD4iu=+`Ku@%W#F!grix zD$6S?NP9@aHEY@P6_i!#oRBcFzKo`yo0|^)!17T9EGr}OuooT;F z3u^D?*2qyc+R;CdTLiZj*`MWu^Yb4&j1L6gz_4Nzk|=V~}ya zDzU^Xb3*}lgT@(q7e{HKIbI&*=6|@l5Y&tJ%<$y+1S)6JZ$RF@Ilv#>7l(sN&FX(8 z+PAFvNv;7xlOR zpz7Gs2vtb4u+-k2df|&_bOxkx4#gcG_RFue-+5_8$lt;=U4^4Td$$fg4RM}l zV9Fa{LRdgrpn>+qq@_U98LjwtX_FS>O+QY)p5(361rNMrkuI{KIJ&HJ{e z6y#s`2Xr%<(zWYa-Q&unCuvFtXme%Jd{6#6vbv=8-8uwQDZ2qFRjM!{3B zeY?MjzTU#J5s!g^W8ADbaoY$P8XSQ#79BlcuP=IgOSMfpn$~>OzdTj6(d1gcC%BoQ zktY8^AVfeKZ)zT3M_0vk$Yh+KZr3%1aNSg+D}a!VS21npu{ zukj(VM{7eJWFp)@#kF4LBeaOuQUGoKUH&IM<4pXSgj>D%y21Jq#R71D#I98b$16QH z9F$0!Gp@IPfK-D(*!aVinzs(%7vy3r)cGUHAYK&C!dC^f3F4xrH!-TcT7rISqkruC_8hn?VVIrPvhbRmzobhKi!KfA@e`XieY(tm!S^c)r{ad+`TV>a>*{x!uaD@R`H$_p1_!_!Sl#e{<}Er=SwWqAp$yTDHNwO2B9aUO#ICBlsXeo z>bJYDe3gj8Q`*fk09Dk<8;Q7c96Em!-QXGn{Dj8*vsP#sgNXARZl>t^fNZMbt6UD* z7r|v>(?=Z+Wl{qKN7{uo5$!dgNFnUU`bdjW5-5a6h|*tm4ky3#T;~+5cy;V`0JjW3 zkGjp=GYcpk6*+k>;L9loCUk$NCxg+znEfwY0?+(Jbc;6^<=&eYKZ1faGtNs(KT+Jc zDe9D5@O4$OJC4^#H+qE)02&c9`LiVNjO7h;zkGxMv)03~6A}zU%bVF!GWT~!u+5@- zfkLIql%S)j`Ih9yO53~;!Fa1!{Y{cKE8A@?V~!koLcoh6c^%N3S*$R|{Sj!Y9xPYC z>pM5iJv0PP(<4AJlT|lCf*@X2pMIIU*6@08M` zm@0<}L8fy+R2e9~@R}A-lK++f2uh!8`0?WxC~~NK#PLL#92NS7T*e;Im;bIv3#Hj7&`b1$R_>aMnYKW!eTC{QRjq9vIX8>EIlQt>ZWLea&w7JHUucjHC8PeSj zyYrzsR=Fi_9K9#kqqQZoVVr@Bhb+$+bSI(X$96#7?t3z00e?qy>4s;JH9i@^q4+9yX91s38`aY?%R}o;}a{nzG11*^M z6St(_X2@>2zbKDAb>c}|ouQ4ebJRyi1NMnLcr)hs$zSZ;UHr7UM?M(0VJY?mm zu(bwWIfcSki6twrP~sdx8_ zmi^znt!8U;8mzHh&ic1cI3xGbwPKLMv*j|s;eGG54H6Tq|XRaH0ef+coz95h)KV8CYb>j@C0 zBlf1Tr1}x@lFUF*BK-uExp$e5nuW677&CNNK}-_ybHp}@xs$#c&{?=Nvjg+?^uzy} znj;(?FGJvZ%Co=)c8|5o4YaSfgNwKB!4MhL5u&6GSgpog@M8t$6)6^LhuNYHoK7hG zQPAeNMRX*v|Cg}Ny#~v%Prv^xJ;|X~zr?y@BZ`7GKax4=JpL2ksHr>)dWJ2)Le}Qu z-M3~q4^~ibYS1|Xni-Ry0Q+9J=P>cO$6A_Rk=0XE!1q0kNEoL^_OK3TJ1{N}t`6nA zJ_A2|6zTOBjp{koE-!*Z%G@Y#k=?IpXZMSd>-p=OK$?>Py5tSi=}1XFPCrFYl;8B% zJ0IZPj>rQ)viG8*%;_7W$S_77LxHPee?Nm4FBNX_r&!*y84!h^k|C(G$g$YSfDbo z(a8~2wQ0969d!jG;u8Q|HR5X(X?O=rs$q(*(C4uYaKdb#UCDL^{>yKG+dTC;X21eF z76MbFEAT>h5YPIF3eFto6wbzkzL zwELg}6JvMd4s<7?es*1{c!Oj(b4^`2`Hr@YlfkdOF6$HDXw_-lk3DXKz}^@NfhUm8 z--8q2eu0yWA>mE$DVR2TY<*{vK^q^Y0J0q%VV}fjUs(41Y=IUY1}Z@7XORBusfpZ9 zf2H+Ae#D@Cjvkc1j>#%$R3ssZQSdbLZUr}ndQKU~hSLY-gU}P82C%Um|Dsp~l4#VX z`*7UrfJOQ}ObNUpp%NJQJHV~Gy>&J7_WE}~bHqOHsdy84n6jUEysm?qv|_u(+_`bL zB!UP0BgKDi^(3U^A%OJWYX z?Ab%>G+?-?x%M3Jvzy1HI=uFt+|?g*WUg1I9$)*TDq6SQg0~I4k7@15T4zj4k-J;^j~oRn0{|&Hg@{poR;|1vxSN&Y zoVD>5S}rtlos2%Itp6Y$b@l)_?&wh`z0Qlj??rE_3*fd$`&Kv_3-H89He_g|0a4(K zVA))6G#H(NVrMMC3+L{u+pHUoFLzEIs({2o^UFQ3`W*3f;9@%5egW8IKV7`~NB6qEpdEc9 zhl#~`g+n9O()adHe}6%-bj@8Gi93r*L&3Yg%(+_iCF@D}e`Ga2X^@F*;&w8gA(q8& zu?Rhq)?{^l`(sX>yLG_RE81*h^BOdi=WJUHzFp|Esk0LyHk1a@uITY&`?Oq5c;y+Z z!G;uX$NS33l#7=|1dhm@;Y2pzXJ2Sr3pp(cls--1_E%*bM%IrrnHuWKx2}xrWwkr7 zac`eBto!gu9PQ)HM`+K=d)=Z9OEr2@%I3W_N4gqZOea)mBP>P5DksaC2#9$JdweC6 z6HyNlb^gMo%XI9r@6P=fzpyb5jF}4H4QV*JIKt|46jIU_K?~`*P}G-8P0ie(QdrrY zca4|IEp(+ni8b1|MyV&ImfhXHEd@od6gg4m6%!JgM(kh~*z0r8#~A42+QK4fqpq>s zxycJX)yeS|Rs-xc`0ZAGiaG5fY5RSPz2g!YUDguT-_t=o5RPsQ6!EPx{B+c<^4QQ7 zy`z2P7`k3r7Qf9Z^hipb6+$svIq@jMD}Jfpn7Hh-H)!8Ixai*69@?5DB9S5PIBgOY zkwD4=XIViv8Q@MZv~Z@{q#P0>}QHxdi>N(D7S(qGGxbt(JnS!lDY3|U^3WCoNLz= zU@HX6QcIz4R^lChDq`4IsIT_%4+E&$v62L#-do%Bc}q8emd4ha9~sQ<$Jwdrk{&!Y zG4r`Pw_2wsqfCzq`LMDuQZw7S1 zhrh!Xj{U9>*znBZ;R>tG+0L8De!l(Ha*D+_3j2)Cy|!T+CW3^NDA2jT#^~Gu=a&9%4u_HP*tD^c%fvC7~k zf=p{p!F%ILy4VSSH&eg!SbyI*=5C*!U%6DI6A_a?=6s-$(Vx2|J`)fkkXAESI&M1B z2Y=~`9oKW+gyeWIH%od?o0uQTG)}L1-TFS5(rA2A9(hK16Bl5s3=8dQ>|2VKF{Va~ zlP2j6ExVnqWxMxX|L=(_AVU<$*~d^XvI_j|bq?&R z$3~!{89;6h zP}{Ich4vlM(zA@!`p0Dc%L9|XFJtO@w;GC(l;*`Wy*nH)YNxeG?GEC->P4mbFg1_SVd≀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 + + + 4.0.0 + + org.apache.xtable + xtable + 0.2.0-SNAPSHOT + + + xtable-service + + + + org.apache.xtable + xtable-core_${scala.binary.version} + ${project.version} + + + + org.apache.hadoop + hadoop-aws + + + + + org.apache.spark + spark-core_${scala.binary.version} + provided + + + org.apache.spark + spark-sql_${scala.binary.version} + provided + + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-resteasy-reactive + + + io.quarkus + quarkus-resteasy-reactive-jackson + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + + + + + + + + + diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionResource.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionResource.java new file mode 100644 index 000000000..82df8cba8 --- /dev/null +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionResource.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service; + +import org.apache.xtable.service.models.ConvertTableRequest; +import org.apache.xtable.service.models.ConvertTableResponse; + +import io.smallrye.common.annotation.Blocking; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +@Path("/v1/conversion") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class ConversionResource { + + @Inject ConversionService conversionService; + + @POST + @Path("/table") + @Blocking + public ConvertTableResponse runSync(ConvertTableRequest req) { + return conversionService.runSync(req); + } +} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java new file mode 100644 index 000000000..5f7f7fcbb --- /dev/null +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service; + +import static org.apache.xtable.model.storage.TableFormat.DELTA; +import static org.apache.xtable.model.storage.TableFormat.HUDI; +import static org.apache.xtable.model.storage.TableFormat.ICEBERG; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.lang3.tuple.Pair; +import org.apache.hadoop.conf.Configuration; +import org.apache.hudi.common.table.timeline.HoodieInstant; + +import org.apache.iceberg.BaseTable; +import org.apache.iceberg.SchemaParser; +import org.apache.iceberg.Snapshot; + +import org.apache.iceberg.Table; +import org.apache.iceberg.TableMetadata; +import org.apache.iceberg.TableOperations; +import org.apache.iceberg.hadoop.HadoopTables; +import org.apache.xtable.conversion.ConversionConfig; +import org.apache.xtable.conversion.ConversionController; +import org.apache.xtable.conversion.ConversionSourceProvider; +import org.apache.xtable.conversion.SourceTable; +import org.apache.xtable.conversion.TargetTable; +import org.apache.xtable.delta.DeltaConversionSourceProvider; +import org.apache.xtable.hudi.HudiConversionSourceProvider; +import org.apache.xtable.iceberg.IcebergConversionSourceProvider; +import org.apache.xtable.service.models.ConvertTableRequest; +import org.apache.xtable.service.models.ConvertTableResponse; +import org.apache.xtable.service.models.InternalTable; +import org.apache.xtable.service.spark.SparkHolder; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class ConversionService { + @Inject SparkHolder sparkHolder; + + public ConvertTableResponse runSync(ConvertTableRequest request) { + ConversionController conversionController = + new ConversionController(sparkHolder.jsc().hadoopConfiguration()); + SourceTable sourceTable = + SourceTable.builder() + .name(request.getSourceTableName()) + .basePath(request.getSourceTablePath()) + .formatName(request.getSourceFormat()) + .build(); + + List targetTables = new ArrayList<>(); + for (String targetFormat : request.getTargetFormats()) { + TargetTable targetTable = + TargetTable.builder() + .name(request.getSourceTableName()) + .basePath(request.getSourceTablePath()) + .formatName(targetFormat) + .build(); + targetTables.add(targetTable); + } + ConversionConfig conversionConfig = + ConversionConfig.builder() + .sourceTable(sourceTable) + .targetTables(targetTables) + .build(); + ConversionSourceProvider conversionSourceProvider = + getConversionSourceProvider(request.getSourceFormat()); + conversionController.sync(conversionConfig, conversionSourceProvider); + + Pair responseFields = getIcebergSchemaAndMetadataPath(request.getSourceTablePath(), sparkHolder.jsc().hadoopConfiguration()); + + InternalTable internalTable = + new InternalTable( + "ICEBERG", + responseFields.getLeft(), responseFields.getRight()); + return new ConvertTableResponse(Collections.singletonList(internalTable)); + } + + private ConversionSourceProvider getConversionSourceProvider(String sourceTableFormat) { + if (sourceTableFormat.equalsIgnoreCase(HUDI)) { + ConversionSourceProvider hudiConversionSourceProvider = + new HudiConversionSourceProvider(); + hudiConversionSourceProvider.init(sparkHolder.jsc().hadoopConfiguration()); + return hudiConversionSourceProvider; + } else if (sourceTableFormat.equalsIgnoreCase(DELTA)) { + ConversionSourceProvider deltaConversionSourceProvider = + new DeltaConversionSourceProvider(); + deltaConversionSourceProvider.init(sparkHolder.jsc().hadoopConfiguration()); + return deltaConversionSourceProvider; + } else if (sourceTableFormat.equalsIgnoreCase(ICEBERG)) { + ConversionSourceProvider icebergConversionSourceProvider = + new IcebergConversionSourceProvider(); + icebergConversionSourceProvider.init(sparkHolder.jsc().hadoopConfiguration()); + return icebergConversionSourceProvider; + } else { + throw new IllegalArgumentException("Unsupported source format: " + sourceTableFormat); + } + } + + public static Pair getIcebergSchemaAndMetadataPath(String tableLocation, Configuration conf) { + HadoopTables tables = new HadoopTables(conf); + Table table = tables.load(tableLocation); + TableOperations ops = ((BaseTable) table).operations(); + TableMetadata current = ops.current(); + return Pair.of(current.metadataFileLocation(), SchemaParser.toJson(current.schema())); + } + +} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceConfig.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceConfig.java new file mode 100644 index 000000000..b45eaca30 --- /dev/null +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceConfig.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service; + +import io.smallrye.config.ConfigMapping; + +@ConfigMapping(prefix = "xtable.service") +public interface ConversionServiceConfig {} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceUtil.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceUtil.java new file mode 100644 index 000000000..5b5411bc9 --- /dev/null +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceUtil.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import org.apache.spark.SparkConf; +import org.apache.spark.serializer.KryoSerializer; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ConversionServiceUtil { + public static SparkConf getSparkConf() { + return new SparkConf() + .setMaster("local[4]") + .setAppName("xtable-service") + .set("spark.ui.enabled", "false") // disable Spark UI + .set("spark.driver.bindAddress", "127.0.0.1") + .set("spark.serializer", KryoSerializer.class.getName()) + .set("spark.sql.catalog.default_iceberg", "org.apache.iceberg.spark.SparkCatalog") + .set("spark.sql.catalog.default_iceberg.type", "hadoop") + .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer") + .set("parquet.avro.write-old-list-structure", "false") + // Needed for ignoring not nullable constraints on nested columns in Delta. + .set("spark.databricks.delta.constraints.allowUnenforcedNotNull.enabled", "true") + .set("spark.sql.shuffle.partitions", "1") + .set("spark.default.parallelism", "1") + .set("spark.sql.session.timeZone", "UTC") + .set("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") + .set("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog") + .set("spark.databricks.delta.retentionDurationCheck.enabled", "false") + .set("spark.databricks.delta.schema.autoMerge.enabled", "true"); + // .set("spark.sql.catalog.default_iceberg.warehouse", tempDir.toString()) add this back for + // iceberg + // .set("spark.sql.hive.convertMetastoreParquet", "false"); add this back for hudi + } +} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableRequest.java b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableRequest.java new file mode 100644 index 000000000..1ed53c330 --- /dev/null +++ b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableRequest.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; +import java.util.Map; + +public class ConvertTableRequest { + @JsonProperty("source-format") + private String sourceFormat; + + @JsonProperty("source-table-name") + private String sourceTableName; + + @JsonProperty("source-table-path") + private String sourceTablePath; + + @JsonProperty("target-formats") + private List targetFormats; + + @JsonProperty("configurations") + private Map configurations; + + public ConvertTableRequest() {} + + @JsonCreator + public ConvertTableRequest( + @JsonProperty("source-format") String sourceFormat, + @JsonProperty("source-table-name") String sourceTableName, + @JsonProperty("source-table-path") String sourceTablePath, + @JsonProperty("target-format") List targetFormat, + @JsonProperty("configurations") Map configurations) { + + this.sourceFormat = sourceFormat; + this.sourceTableName = sourceTableName; + this.sourceTablePath = sourceTablePath; + this.targetFormats = targetFormat; + this.configurations = configurations; + } + + public String getSourceTableName() { + return sourceTableName; + } + + public String getSourceFormat() { + return sourceFormat; + } + + public String getSourceTablePath() { + return sourceTablePath; + } + + public List getTargetFormats() { + return targetFormats; + } + + public Map getConfigurations() { + return configurations; + } +} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java new file mode 100644 index 000000000..287ede24e --- /dev/null +++ b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + + +public class ConvertTableResponse { + @JsonProperty("conversions") + private List conversions; + + @JsonCreator + public ConvertTableResponse(@JsonProperty List conversions) { + this.conversions = conversions; + } + + public List getConversions() { + return conversions; + } +} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/models/InternalTable.java b/xtable-service/src/main/java/org/apache/xtable/service/models/InternalTable.java new file mode 100644 index 000000000..728e616a2 --- /dev/null +++ b/xtable-service/src/main/java/org/apache/xtable/service/models/InternalTable.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class InternalTable { + @JsonProperty("target-format") + private String targetFormat; + + @JsonProperty("target-metadata-path") + private String targetMetadataPath; + + @JsonProperty("target-schema") + private String targetSchema; + + @JsonCreator + public InternalTable(@JsonProperty String targetFormat, + @JsonProperty String targetMetadataPath, + @JsonProperty String targetSchema) { + this.targetFormat = targetFormat; + this.targetMetadataPath = targetMetadataPath; + this.targetSchema = targetSchema; + } + + public String getTargetFormat() { + return targetFormat; + } + + public String getTargetMetadataPath() { + return targetMetadataPath; + } + + public String getTargetSchema() { + return targetSchema; + } +} \ No newline at end of file diff --git a/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkBootstrap.java b/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkBootstrap.java new file mode 100644 index 000000000..84a2e776e --- /dev/null +++ b/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkBootstrap.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service.spark; + +import org.eclipse.microprofile.context.ManagedExecutor; + +import io.quarkus.runtime.StartupEvent; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; + +@ApplicationScoped +public class SparkBootstrap { + @Inject ManagedExecutor executor; + @Inject SparkHolder holder; + + void onStart(@Observes StartupEvent ev) { + // Quarkus has already bound port 8080 by the time this runs. + executor.execute(holder::spark); + } +} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java b/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java new file mode 100644 index 000000000..1642804bb --- /dev/null +++ b/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service.spark; + +import java.io.InputStream; + +import org.apache.spark.api.java.JavaSparkContext; +import org.apache.spark.sql.SparkSession; + +import org.apache.xtable.service.ConversionServiceUtil; + +import io.quarkus.runtime.ShutdownEvent; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; + +@ApplicationScoped +public class SparkHolder { + + private volatile SparkSession spark; + private volatile JavaSparkContext jsc; + private static final String HADOOP_DEFAULTS_PATH = "xtable-hadoop-defaults.xml"; + + public SparkSession spark() { + if (spark == null) { + synchronized (this) { + if (spark == null) { + spark = + SparkSession.builder() + .config(ConversionServiceUtil.getSparkConf()) + .appName("xtable-conversion-service") + .getOrCreate(); + jsc = JavaSparkContext.fromSparkContext(spark.sparkContext()); + InputStream resourceStream = + SparkHolder.class.getClassLoader().getResourceAsStream(HADOOP_DEFAULTS_PATH); + if (resourceStream != null) { + spark.sparkContext().hadoopConfiguration().addResource(resourceStream); + } else { + throw new RuntimeException("Failed to load resource xtable-hadoop-defaults.xml"); + } + } + } + } + return spark; + } + + public JavaSparkContext jsc() { + // ensure spark() has run + spark(); + return jsc; + } + + // cleanly stop Spark when Quarkus shuts down + void onShutdown(@Observes ShutdownEvent ev) { + if (spark != null) { + spark.stop(); + } + } +} diff --git a/xtable-service/src/main/resources/application.properties b/xtable-service/src/main/resources/application.properties new file mode 100644 index 000000000..a4b397a25 --- /dev/null +++ b/xtable-service/src/main/resources/application.properties @@ -0,0 +1,17 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +quarkus.log.level=DEBUG \ No newline at end of file diff --git a/xtable-service/src/main/resources/xtable-hadoop-defaults.xml b/xtable-service/src/main/resources/xtable-hadoop-defaults.xml new file mode 100644 index 000000000..0262bd83b --- /dev/null +++ b/xtable-service/src/main/resources/xtable-hadoop-defaults.xml @@ -0,0 +1,91 @@ + + + + + + + fs.file.impl + org.apache.hadoop.fs.LocalFileSystem + + + + + fs.azure.account.auth.type + OAuth + + + fs.azure.account.oauth.provider.type + org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider + + + + + + + fs.s3.impl + org.apache.hadoop.fs.s3a.S3AFileSystem + + + fs.s3.aws.credentials.provider + software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider + + + fs.s3a.impl + org.apache.hadoop.fs.s3a.S3AFileSystem + + + fs.s3a.aws.credentials.provider + software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider + + + + + fs.gs.impl + com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem + + + fs.AbstractFileSystem.gs.impl + com.google.cloud.hadoop.fs.gcs.GoogleHadoopFS + + + + + spark.master + local[2] + + + + + parquet.avro.write-old-list-structure + false + + + diff --git a/xtable-service/src/test/java/org/apache/xtable/XTableResourceIT.java b/xtable-service/src/test/java/org/apache/xtable/XTableResourceIT.java new file mode 100644 index 000000000..fce94374d --- /dev/null +++ b/xtable-service/src/test/java/org/apache/xtable/XTableResourceIT.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +class XTableResourceIT extends XTableResourceTest { + // Execute the same tests but in packaged mode. +} diff --git a/xtable-service/src/test/java/org/apache/xtable/XTableResourceTest.java b/xtable-service/src/test/java/org/apache/xtable/XTableResourceTest.java new file mode 100644 index 000000000..9d2c441c8 --- /dev/null +++ b/xtable-service/src/test/java/org/apache/xtable/XTableResourceTest.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.is; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +class XTableResourceTest { + @Test + void testHelloEndpoint() { + given().when().get("/hello").then().statusCode(200).body(is("Hello from XTable Quarkus REST")); + } +} From 14bcb79457c407b85afaa05686f3dcafe3cf9a4e Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Thu, 1 May 2025 16:31:57 -0700 Subject: [PATCH 02/15] Use builder pattern, spotless fix --- .../xtable/service/ConversionResource.java | 4 +- .../xtable/service/ConversionService.java | 28 ++++---- .../service/models/ConvertTableRequest.java | 11 +-- .../service/models/ConvertTableResponse.java | 14 ++-- ...nternalTable.java => RestTargetTable.java} | 68 ++++++++++--------- .../org/apache/xtable/XTableResourceIT.java | 26 ------- .../org/apache/xtable/XTableResourceTest.java | 34 ---------- 7 files changed, 66 insertions(+), 119 deletions(-) rename xtable-service/src/main/java/org/apache/xtable/service/models/{InternalTable.java => RestTargetTable.java} (53%) delete mode 100644 xtable-service/src/test/java/org/apache/xtable/XTableResourceIT.java delete mode 100644 xtable-service/src/test/java/org/apache/xtable/XTableResourceTest.java diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionResource.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionResource.java index 82df8cba8..3174b92c4 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/ConversionResource.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionResource.java @@ -39,7 +39,7 @@ public class ConversionResource { @POST @Path("/table") @Blocking - public ConvertTableResponse runSync(ConvertTableRequest req) { - return conversionService.runSync(req); + public ConvertTableResponse convertTable(ConvertTableRequest req) { + return conversionService.convertTable(req); } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java index 5f7f7fcbb..85affec0d 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java @@ -28,16 +28,17 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.hadoop.conf.Configuration; + import org.apache.hudi.common.table.timeline.HoodieInstant; import org.apache.iceberg.BaseTable; import org.apache.iceberg.SchemaParser; import org.apache.iceberg.Snapshot; - import org.apache.iceberg.Table; import org.apache.iceberg.TableMetadata; import org.apache.iceberg.TableOperations; import org.apache.iceberg.hadoop.HadoopTables; + import org.apache.xtable.conversion.ConversionConfig; import org.apache.xtable.conversion.ConversionController; import org.apache.xtable.conversion.ConversionSourceProvider; @@ -48,7 +49,7 @@ import org.apache.xtable.iceberg.IcebergConversionSourceProvider; import org.apache.xtable.service.models.ConvertTableRequest; import org.apache.xtable.service.models.ConvertTableResponse; -import org.apache.xtable.service.models.InternalTable; +import org.apache.xtable.service.models.RestTargetTable; import org.apache.xtable.service.spark.SparkHolder; import jakarta.enterprise.context.ApplicationScoped; @@ -58,7 +59,7 @@ public class ConversionService { @Inject SparkHolder sparkHolder; - public ConvertTableResponse runSync(ConvertTableRequest request) { + public ConvertTableResponse convertTable(ConvertTableRequest request) { ConversionController conversionController = new ConversionController(sparkHolder.jsc().hadoopConfiguration()); SourceTable sourceTable = @@ -79,21 +80,18 @@ public ConvertTableResponse runSync(ConvertTableRequest request) { targetTables.add(targetTable); } ConversionConfig conversionConfig = - ConversionConfig.builder() - .sourceTable(sourceTable) - .targetTables(targetTables) - .build(); + ConversionConfig.builder().sourceTable(sourceTable).targetTables(targetTables).build(); ConversionSourceProvider conversionSourceProvider = getConversionSourceProvider(request.getSourceFormat()); conversionController.sync(conversionConfig, conversionSourceProvider); - Pair responseFields = getIcebergSchemaAndMetadataPath(request.getSourceTablePath(), sparkHolder.jsc().hadoopConfiguration()); + Pair responseFields = + getIcebergSchemaAndMetadataPath( + request.getSourceTablePath(), sparkHolder.jsc().hadoopConfiguration()); - InternalTable internalTable = - new InternalTable( - "ICEBERG", - responseFields.getLeft(), responseFields.getRight()); - return new ConvertTableResponse(Collections.singletonList(internalTable)); + RestTargetTable internalTable = + new RestTargetTable("ICEBERG", responseFields.getLeft(), responseFields.getRight()); + return new ConvertTableResponse(Collections.singletonList(internalTable)); } private ConversionSourceProvider getConversionSourceProvider(String sourceTableFormat) { @@ -117,12 +115,12 @@ private ConversionSourceProvider getConversionSourceProvider(String sourceTab } } - public static Pair getIcebergSchemaAndMetadataPath(String tableLocation, Configuration conf) { + public static Pair getIcebergSchemaAndMetadataPath( + String tableLocation, Configuration conf) { HadoopTables tables = new HadoopTables(conf); Table table = tables.load(tableLocation); TableOperations ops = ((BaseTable) table).operations(); TableMetadata current = ops.current(); return Pair.of(current.metadataFileLocation(), SchemaParser.toJson(current.schema())); } - } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableRequest.java b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableRequest.java index 1ed53c330..d683fdded 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableRequest.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableRequest.java @@ -18,12 +18,15 @@ package org.apache.xtable.service.models; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.List; import java.util.Map; +import lombok.Builder; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +@Builder public class ConvertTableRequest { @JsonProperty("source-format") private String sourceFormat; @@ -73,7 +76,7 @@ public List getTargetFormats() { return targetFormats; } - public Map getConfigurations() { + public Map getConfigurations() { return configurations; } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java index 287ede24e..087048915 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java @@ -18,22 +18,24 @@ package org.apache.xtable.service.models; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.List; +import lombok.Builder; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +@Builder public class ConvertTableResponse { @JsonProperty("conversions") - private List conversions; + private List conversions; @JsonCreator - public ConvertTableResponse(@JsonProperty List conversions) { + public ConvertTableResponse(@JsonProperty List conversions) { this.conversions = conversions; } - public List getConversions() { + public List getConversions() { return conversions; } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/models/InternalTable.java b/xtable-service/src/main/java/org/apache/xtable/service/models/RestTargetTable.java similarity index 53% rename from xtable-service/src/main/java/org/apache/xtable/service/models/InternalTable.java rename to xtable-service/src/main/java/org/apache/xtable/service/models/RestTargetTable.java index 728e616a2..b5f866087 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/models/InternalTable.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/models/RestTargetTable.java @@ -15,40 +15,44 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + package org.apache.xtable.service.models; +import lombok.Builder; + import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -public class InternalTable { - @JsonProperty("target-format") - private String targetFormat; - - @JsonProperty("target-metadata-path") - private String targetMetadataPath; - - @JsonProperty("target-schema") - private String targetSchema; - - @JsonCreator - public InternalTable(@JsonProperty String targetFormat, - @JsonProperty String targetMetadataPath, - @JsonProperty String targetSchema) { - this.targetFormat = targetFormat; - this.targetMetadataPath = targetMetadataPath; - this.targetSchema = targetSchema; - } - - public String getTargetFormat() { - return targetFormat; - } - - public String getTargetMetadataPath() { - return targetMetadataPath; - } - - public String getTargetSchema() { - return targetSchema; - } -} \ No newline at end of file +@Builder +public class RestTargetTable { + @JsonProperty("target-format") + private String targetFormat; + + @JsonProperty("target-metadata-path") + private String targetMetadataPath; + + @JsonProperty("target-schema") + private String targetSchema; + + @JsonCreator + public RestTargetTable( + @JsonProperty String targetFormat, + @JsonProperty String targetMetadataPath, + @JsonProperty String targetSchema) { + this.targetFormat = targetFormat; + this.targetMetadataPath = targetMetadataPath; + this.targetSchema = targetSchema; + } + + public String getTargetFormat() { + return targetFormat; + } + + public String getTargetMetadataPath() { + return targetMetadataPath; + } + + public String getTargetSchema() { + return targetSchema; + } +} diff --git a/xtable-service/src/test/java/org/apache/xtable/XTableResourceIT.java b/xtable-service/src/test/java/org/apache/xtable/XTableResourceIT.java deleted file mode 100644 index fce94374d..000000000 --- a/xtable-service/src/test/java/org/apache/xtable/XTableResourceIT.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.xtable; - -import io.quarkus.test.junit.QuarkusIntegrationTest; - -@QuarkusIntegrationTest -class XTableResourceIT extends XTableResourceTest { - // Execute the same tests but in packaged mode. -} diff --git a/xtable-service/src/test/java/org/apache/xtable/XTableResourceTest.java b/xtable-service/src/test/java/org/apache/xtable/XTableResourceTest.java deleted file mode 100644 index 9d2c441c8..000000000 --- a/xtable-service/src/test/java/org/apache/xtable/XTableResourceTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.xtable; - -import static io.restassured.RestAssured.given; -import static org.hamcrest.CoreMatchers.is; - -import org.junit.jupiter.api.Test; - -import io.quarkus.test.junit.QuarkusTest; - -@QuarkusTest -class XTableResourceTest { - @Test - void testHelloEndpoint() { - given().when().get("/hello").then().statusCode(200).body(is("Hello from XTable Quarkus REST")); - } -} From dae612927c2b13c378aec5ffd615d4b12219a8b2 Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Thu, 1 May 2025 16:32:36 -0700 Subject: [PATCH 03/15] Add unit test for conversion resource --- xtable-service/pom.xml | 17 ++-- .../service/TestConversionResource.java | 77 +++++++++++++++++++ 2 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java diff --git a/xtable-service/pom.xml b/xtable-service/pom.xml index 103323644..1c1a73003 100644 --- a/xtable-service/pom.xml +++ b/xtable-service/pom.xml @@ -75,17 +75,24 @@ quarkus-resteasy-reactive-jackson - io.quarkus - quarkus-junit5 + io.rest-assured + rest-assured test + + - io.rest-assured - rest-assured + org.mockito + mockito-core + test + + + org.mockito + mockito-junit-jupiter test - + diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java new file mode 100644 index 000000000..6ad0238a5 --- /dev/null +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import org.apache.xtable.service.models.ConvertTableRequest; +import org.apache.xtable.service.models.ConvertTableResponse; +import org.apache.xtable.service.models.RestTargetTable; + +@ExtendWith(MockitoExtension.class) +class TestConversionResource { + + private static final String SOURCE_TABLE_BASE_PATH = "s3://bucket/tables/users"; + private static final String TARGET_ICEBERG_METADATA_PATH = "s3://bucket/tables/users/metadata"; + + @Mock private ConversionService conversionService; + + @InjectMocks private ConversionResource resource; + + @Test + void convertTable_delegatesToService_andReturnsExpectedResponse() { + ConvertTableRequest req = + ConvertTableRequest.builder() + .sourceFormat("DELTA") + .sourceTableName("users") + .sourceTablePath(SOURCE_TABLE_BASE_PATH) + .targetFormats(Arrays.asList("ICEBERG")) + .build(); + + RestTargetTable icebergTable = + RestTargetTable.builder() + .targetFormat("ICEBERG") + .targetMetadataPath(TARGET_ICEBERG_METADATA_PATH) + .build(); + + ConvertTableResponse expected = + ConvertTableResponse.builder().conversions(Arrays.asList(icebergTable)).build(); + when(conversionService.convertTable(req)).thenReturn(expected); + ConvertTableResponse actual = resource.convertTable(req); + verify(conversionService).convertTable(req); + + assertNotNull(actual); + assertSame(expected, actual, "Resource should return the exact response from the service"); + + assertEquals(1, actual.getConversions().size()); + assertEquals("ICEBERG", actual.getConversions().get(0).getTargetFormat()); + assertEquals( + TARGET_ICEBERG_METADATA_PATH, actual.getConversions().get(0).getTargetMetadataPath()); + } +} From dcb4f630220feb34b0821efd858e824d97246aa4 Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Thu, 1 May 2025 17:56:01 -0700 Subject: [PATCH 04/15] Refactor code for easier testing, add unit test for service --- ....java => ConversionControllerFactory.java} | 14 +- .../xtable/service/ConversionService.java | 37 +++--- .../xtable/service/ConversionServiceUtil.java | 53 -------- .../xtable/service/spark/SparkHolder.java | 31 ++++- .../service/utils/IcebergMetadataUtil.java | 43 ++++++ .../service/TestConversionResource.java | 2 +- .../xtable/service/TestConversionService.java | 124 ++++++++++++++++++ 7 files changed, 225 insertions(+), 79 deletions(-) rename xtable-service/src/main/java/org/apache/xtable/service/{ConversionServiceConfig.java => ConversionControllerFactory.java} (72%) delete mode 100644 xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceUtil.java create mode 100644 xtable-service/src/main/java/org/apache/xtable/service/utils/IcebergMetadataUtil.java create mode 100644 xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceConfig.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionControllerFactory.java similarity index 72% rename from xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceConfig.java rename to xtable-service/src/main/java/org/apache/xtable/service/ConversionControllerFactory.java index b45eaca30..82210f94e 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceConfig.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionControllerFactory.java @@ -18,7 +18,15 @@ package org.apache.xtable.service; -import io.smallrye.config.ConfigMapping; +import org.apache.hadoop.conf.Configuration; -@ConfigMapping(prefix = "xtable.service") -public interface ConversionServiceConfig {} +import org.apache.xtable.conversion.ConversionController; + +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class ConversionControllerFactory { + public ConversionController create(Configuration conf) { + return new ConversionController(conf); + } +} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java index 85affec0d..b151a4322 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java @@ -31,13 +31,7 @@ import org.apache.hudi.common.table.timeline.HoodieInstant; -import org.apache.iceberg.BaseTable; -import org.apache.iceberg.SchemaParser; import org.apache.iceberg.Snapshot; -import org.apache.iceberg.Table; -import org.apache.iceberg.TableMetadata; -import org.apache.iceberg.TableOperations; -import org.apache.iceberg.hadoop.HadoopTables; import org.apache.xtable.conversion.ConversionConfig; import org.apache.xtable.conversion.ConversionController; @@ -51,17 +45,31 @@ import org.apache.xtable.service.models.ConvertTableResponse; import org.apache.xtable.service.models.RestTargetTable; import org.apache.xtable.service.spark.SparkHolder; +import org.apache.xtable.service.utils.IcebergMetadataUtil; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @ApplicationScoped public class ConversionService { - @Inject SparkHolder sparkHolder; + private final SparkHolder sparkHolder; + private final ConversionControllerFactory controllerFactory; + private final IcebergMetadataUtil icebergUtil; + + @Inject + public ConversionService( + SparkHolder sparkHolder, + ConversionControllerFactory controllerFactory, + IcebergMetadataUtil icebergUtil) { + this.sparkHolder = sparkHolder; + this.controllerFactory = controllerFactory; + this.icebergUtil = icebergUtil; + } public ConvertTableResponse convertTable(ConvertTableRequest request) { - ConversionController conversionController = - new ConversionController(sparkHolder.jsc().hadoopConfiguration()); + Configuration conf = sparkHolder.jsc().hadoopConfiguration(); + ConversionController conversionController = controllerFactory.create(conf); + SourceTable sourceTable = SourceTable.builder() .name(request.getSourceTableName()) @@ -86,7 +94,7 @@ public ConvertTableResponse convertTable(ConvertTableRequest request) { conversionController.sync(conversionConfig, conversionSourceProvider); Pair responseFields = - getIcebergSchemaAndMetadataPath( + icebergUtil.getIcebergSchemaAndMetadataPath( request.getSourceTablePath(), sparkHolder.jsc().hadoopConfiguration()); RestTargetTable internalTable = @@ -114,13 +122,4 @@ private ConversionSourceProvider getConversionSourceProvider(String sourceTab throw new IllegalArgumentException("Unsupported source format: " + sourceTableFormat); } } - - public static Pair getIcebergSchemaAndMetadataPath( - String tableLocation, Configuration conf) { - HadoopTables tables = new HadoopTables(conf); - Table table = tables.load(tableLocation); - TableOperations ops = ((BaseTable) table).operations(); - TableMetadata current = ops.current(); - return Pair.of(current.metadataFileLocation(), SchemaParser.toJson(current.schema())); - } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceUtil.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceUtil.java deleted file mode 100644 index 5b5411bc9..000000000 --- a/xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceUtil.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.xtable.service; - -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -import org.apache.spark.SparkConf; -import org.apache.spark.serializer.KryoSerializer; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class ConversionServiceUtil { - public static SparkConf getSparkConf() { - return new SparkConf() - .setMaster("local[4]") - .setAppName("xtable-service") - .set("spark.ui.enabled", "false") // disable Spark UI - .set("spark.driver.bindAddress", "127.0.0.1") - .set("spark.serializer", KryoSerializer.class.getName()) - .set("spark.sql.catalog.default_iceberg", "org.apache.iceberg.spark.SparkCatalog") - .set("spark.sql.catalog.default_iceberg.type", "hadoop") - .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer") - .set("parquet.avro.write-old-list-structure", "false") - // Needed for ignoring not nullable constraints on nested columns in Delta. - .set("spark.databricks.delta.constraints.allowUnenforcedNotNull.enabled", "true") - .set("spark.sql.shuffle.partitions", "1") - .set("spark.default.parallelism", "1") - .set("spark.sql.session.timeZone", "UTC") - .set("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") - .set("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog") - .set("spark.databricks.delta.retentionDurationCheck.enabled", "false") - .set("spark.databricks.delta.schema.autoMerge.enabled", "true"); - // .set("spark.sql.catalog.default_iceberg.warehouse", tempDir.toString()) add this back for - // iceberg - // .set("spark.sql.hive.convertMetastoreParquet", "false"); add this back for hudi - } -} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java b/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java index 1642804bb..ac109e84f 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java @@ -20,11 +20,11 @@ import java.io.InputStream; +import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaSparkContext; +import org.apache.spark.serializer.KryoSerializer; import org.apache.spark.sql.SparkSession; -import org.apache.xtable.service.ConversionServiceUtil; - import io.quarkus.runtime.ShutdownEvent; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Observes; @@ -42,7 +42,7 @@ public SparkSession spark() { if (spark == null) { spark = SparkSession.builder() - .config(ConversionServiceUtil.getSparkConf()) + .config(getSparkConf()) .appName("xtable-conversion-service") .getOrCreate(); jsc = JavaSparkContext.fromSparkContext(spark.sparkContext()); @@ -71,4 +71,29 @@ void onShutdown(@Observes ShutdownEvent ev) { spark.stop(); } } + + public SparkConf getSparkConf() { + return new SparkConf() + .setMaster("local[4]") + .setAppName("xtable-service") + .set("spark.ui.enabled", "false") // disable Spark UI + .set("spark.driver.bindAddress", "127.0.0.1") + .set("spark.serializer", KryoSerializer.class.getName()) + .set("spark.sql.catalog.default_iceberg", "org.apache.iceberg.spark.SparkCatalog") + .set("spark.sql.catalog.default_iceberg.type", "hadoop") + .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer") + .set("parquet.avro.write-old-list-structure", "false") + // Needed for ignoring not nullable constraints on nested columns in Delta. + .set("spark.databricks.delta.constraints.allowUnenforcedNotNull.enabled", "true") + .set("spark.sql.shuffle.partitions", "1") + .set("spark.default.parallelism", "1") + .set("spark.sql.session.timeZone", "UTC") + .set("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") + .set("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog") + .set("spark.databricks.delta.retentionDurationCheck.enabled", "false") + .set("spark.databricks.delta.schema.autoMerge.enabled", "true"); + // .set("spark.sql.catalog.default_iceberg.warehouse", tempDir.toString()) add this back for + // iceberg + // .set("spark.sql.hive.convertMetastoreParquet", "false"); add this back for hudi + } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/utils/IcebergMetadataUtil.java b/xtable-service/src/main/java/org/apache/xtable/service/utils/IcebergMetadataUtil.java new file mode 100644 index 000000000..bac0c4cd4 --- /dev/null +++ b/xtable-service/src/main/java/org/apache/xtable/service/utils/IcebergMetadataUtil.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service.utils; + +import org.apache.commons.lang3.tuple.Pair; +import org.apache.hadoop.conf.Configuration; + +import org.apache.iceberg.BaseTable; +import org.apache.iceberg.SchemaParser; +import org.apache.iceberg.Table; +import org.apache.iceberg.TableMetadata; +import org.apache.iceberg.TableOperations; +import org.apache.iceberg.hadoop.HadoopTables; + +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class IcebergMetadataUtil { + public Pair getIcebergSchemaAndMetadataPath( + String tableLocation, Configuration conf) { + HadoopTables tables = new HadoopTables(conf); + Table table = tables.load(tableLocation); + TableOperations ops = ((BaseTable) table).operations(); + TableMetadata current = ops.current(); + return Pair.of(current.metadataFileLocation(), SchemaParser.toJson(current.schema())); + } +} diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java index 6ad0238a5..a71db834e 100644 --- a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java @@ -45,7 +45,7 @@ class TestConversionResource { @InjectMocks private ConversionResource resource; @Test - void convertTable_delegatesToService_andReturnsExpectedResponse() { + void testConvertTableResource() { ConvertTableRequest req = ConvertTableRequest.builder() .sourceFormat("DELTA") diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java new file mode 100644 index 000000000..a9292dfa4 --- /dev/null +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Collections; + +import org.apache.commons.lang3.tuple.Pair; +import org.apache.hadoop.conf.Configuration; +import org.apache.spark.api.java.JavaSparkContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import org.apache.xtable.conversion.ConversionConfig; +import org.apache.xtable.conversion.ConversionController; +import org.apache.xtable.service.models.ConvertTableRequest; +import org.apache.xtable.service.models.ConvertTableResponse; +import org.apache.xtable.service.models.RestTargetTable; +import org.apache.xtable.service.spark.SparkHolder; +import org.apache.xtable.service.utils.IcebergMetadataUtil; + +@ExtendWith(MockitoExtension.class) +class TestConversionService { + + private static final String SOURCE_TABLE_NAME = "users"; + private static final String SOURCE_TABLE_BASE_PATH = "s3://bucket/tables/users"; + private static final String TARGET_ICEBERG_METADATA_PATH = + "s3://bucket/tables/users/metadata/v1.metadata.json"; + private static final String TARGET_SCHEMA = "{\"schema\":[]}"; + private final Configuration conf = new Configuration(); + + @Mock SparkHolder sparkHolder; + @Mock ConversionControllerFactory controllerFactory; + @Mock IcebergMetadataUtil icebergUtil; + @Mock ConversionController controller; + @Mock JavaSparkContext jsc; + + @InjectMocks ConversionService service; + + @BeforeEach + void setUp() { + when(sparkHolder.jsc()).thenReturn(jsc); + when(jsc.hadoopConfiguration()).thenReturn(conf); + when(controllerFactory.create(conf)).thenReturn(controller); + } + + @Test + void serviceConvertTableWithDeltaSourceAndTargetIceberg() { + when(icebergUtil.getIcebergSchemaAndMetadataPath(SOURCE_TABLE_BASE_PATH, conf)) + .thenReturn(Pair.of(TARGET_ICEBERG_METADATA_PATH, TARGET_SCHEMA)); + + ConvertTableRequest req = + ConvertTableRequest.builder() + .sourceFormat("DELTA") + .sourceTableName(SOURCE_TABLE_NAME) + .sourceTablePath(SOURCE_TABLE_BASE_PATH) + .targetFormats(Collections.singletonList("ICEBERG")) + .build(); + + ConvertTableResponse resp = service.convertTable(req); + verify(controller, times(1)).sync(any(ConversionConfig.class), any()); + + RestTargetTable restTargetTable = resp.getConversions().get(0); + assertEquals("ICEBERG", restTargetTable.getTargetFormat()); + assertEquals(TARGET_ICEBERG_METADATA_PATH, restTargetTable.getTargetMetadataPath()); + assertEquals(TARGET_SCHEMA, restTargetTable.getTargetSchema()); + } + + @Test + void serviceConvertTableWithInvalidFormats() { + ConvertTableRequest invalidRequest = + ConvertTableRequest.builder() + .sourceFormat("notRealSoureFormat") + .sourceTableName(SOURCE_TABLE_NAME) + .sourceTablePath(SOURCE_TABLE_BASE_PATH) + .targetFormats(Collections.singletonList("notRealTargetFormat")) + .build(); + assertThrows(IllegalArgumentException.class, () -> service.convertTable(invalidRequest)); + } +} From 5bd95b9b8054e11beaefa78f5b1cfaf60de8b00e Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Fri, 2 May 2025 11:54:33 -0700 Subject: [PATCH 05/15] Fix other failing modules tests by moving quarkus bom into xtable service --- pom.xml | 7 ------- xtable-service/pom.xml | 13 +++++++++++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index bd128c743..1338ca692 100644 --- a/pom.xml +++ b/pom.xml @@ -609,13 +609,6 @@ jettison 1.5.4 - - ${quarkus.platform.group-id} - ${quarkus.platform.artifact-id} - ${quarkus.platform.version} - pom - import - diff --git a/xtable-service/pom.xml b/xtable-service/pom.xml index 1c1a73003..d08c2a018 100644 --- a/xtable-service/pom.xml +++ b/xtable-service/pom.xml @@ -27,6 +27,19 @@ xtable-service + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + + org.apache.xtable From a7b6453ea03e574e8453012fd817d0dc9165ab6c Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Fri, 2 May 2025 17:08:50 -0700 Subject: [PATCH 06/15] Add metadata helper utils, test other formats --- pom.xml | 3 +- xtable-service/pom.xml | 6 ++ .../xtable/service/ConversionService.java | 44 +++++++++--- .../service/utils/DeltaMetadataUtil.java | 38 +++++++++++ .../xtable/service/utils/HudiMedataUtil.java | 67 +++++++++++++++++++ .../src/main/resources/application.properties | 2 +- 6 files changed, 149 insertions(+), 11 deletions(-) create mode 100644 xtable-service/src/main/java/org/apache/xtable/service/utils/DeltaMetadataUtil.java create mode 100644 xtable-service/src/main/java/org/apache/xtable/service/utils/HudiMedataUtil.java diff --git a/pom.xml b/pom.xml index 1338ca692..9e19ea3f6 100644 --- a/pom.xml +++ b/pom.xml @@ -102,6 +102,7 @@ io.quarkus.platform 3.2.12.Final 4.9.3 + 0.16 false @@ -472,7 +473,7 @@ org.openjdk.jol jol-core - 0.16 + ${jol.core.version} test diff --git a/xtable-service/pom.xml b/xtable-service/pom.xml index d08c2a018..4d7bec70d 100644 --- a/xtable-service/pom.xml +++ b/xtable-service/pom.xml @@ -104,6 +104,12 @@ mockito-junit-jupiter test + + org.openjdk.jol + jol-core + ${jol.core.version} + runtime + diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java index b151a4322..22e683ff1 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java @@ -23,7 +23,6 @@ import static org.apache.xtable.model.storage.TableFormat.ICEBERG; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import org.apache.commons.lang3.tuple.Pair; @@ -45,6 +44,8 @@ import org.apache.xtable.service.models.ConvertTableResponse; import org.apache.xtable.service.models.RestTargetTable; import org.apache.xtable.service.spark.SparkHolder; +import org.apache.xtable.service.utils.DeltaMetadataUtil; +import org.apache.xtable.service.utils.HudiMedataUtil; import org.apache.xtable.service.utils.IcebergMetadataUtil; import jakarta.enterprise.context.ApplicationScoped; @@ -55,15 +56,21 @@ public class ConversionService { private final SparkHolder sparkHolder; private final ConversionControllerFactory controllerFactory; private final IcebergMetadataUtil icebergUtil; + private final HudiMedataUtil hudiUtil; + private final DeltaMetadataUtil deltaUtil; @Inject public ConversionService( SparkHolder sparkHolder, ConversionControllerFactory controllerFactory, - IcebergMetadataUtil icebergUtil) { + IcebergMetadataUtil icebergUtil, + HudiMedataUtil hudiUtil, + DeltaMetadataUtil deltaUtil) { this.sparkHolder = sparkHolder; this.controllerFactory = controllerFactory; this.icebergUtil = icebergUtil; + this.hudiUtil = hudiUtil; + this.deltaUtil = deltaUtil; } public ConvertTableResponse convertTable(ConvertTableRequest request) { @@ -93,13 +100,32 @@ public ConvertTableResponse convertTable(ConvertTableRequest request) { getConversionSourceProvider(request.getSourceFormat()); conversionController.sync(conversionConfig, conversionSourceProvider); - Pair responseFields = - icebergUtil.getIcebergSchemaAndMetadataPath( - request.getSourceTablePath(), sparkHolder.jsc().hadoopConfiguration()); - - RestTargetTable internalTable = - new RestTargetTable("ICEBERG", responseFields.getLeft(), responseFields.getRight()); - return new ConvertTableResponse(Collections.singletonList(internalTable)); + List restTargetTables = new ArrayList<>(); + for (String targetFormat : request.getTargetFormats()) { + if (targetFormat.equals("ICEBERG")) { + Pair responseFields = + icebergUtil.getIcebergSchemaAndMetadataPath( + request.getSourceTablePath(), sparkHolder.jsc().hadoopConfiguration()); + RestTargetTable icebergTable = + new RestTargetTable("ICEBERG", responseFields.getLeft(), responseFields.getRight()); + restTargetTables.add(icebergTable); + } else if (targetFormat.equals("HUDI")) { + Pair responseFields = + hudiUtil.getHudiSchemaAndMetadataPath( + request.getSourceTablePath(), sparkHolder.jsc().hadoopConfiguration()); + RestTargetTable hudiTable = + new RestTargetTable("HUDI", responseFields.getLeft(), responseFields.getRight()); + restTargetTables.add(hudiTable); + } else if(targetFormat.equals("DELTA")){ + Pair responseFields = + deltaUtil.getDeltaSchemaAndMetadataPath( + request.getSourceTablePath(), sparkHolder.spark()); + RestTargetTable deltaTable = + new RestTargetTable("DELTA", responseFields.getLeft(), responseFields.getRight()); + restTargetTables.add(deltaTable); + } + } + return new ConvertTableResponse(restTargetTables); } private ConversionSourceProvider getConversionSourceProvider(String sourceTableFormat) { diff --git a/xtable-service/src/main/java/org/apache/xtable/service/utils/DeltaMetadataUtil.java b/xtable-service/src/main/java/org/apache/xtable/service/utils/DeltaMetadataUtil.java new file mode 100644 index 000000000..80aad1dc9 --- /dev/null +++ b/xtable-service/src/main/java/org/apache/xtable/service/utils/DeltaMetadataUtil.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service.utils; + +import jakarta.enterprise.context.ApplicationScoped; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.spark.sql.SparkSession; +import org.apache.spark.sql.delta.DeltaLog; +import org.apache.spark.sql.delta.Snapshot; +import org.apache.spark.sql.types.StructType; + +@ApplicationScoped +public class DeltaMetadataUtil { + public Pair getDeltaSchemaAndMetadataPath(String basePath, SparkSession sparkSession) { + DeltaLog deltaLog = DeltaLog.forTable(sparkSession, basePath); + Snapshot snapshot = deltaLog.snapshot(); + StructType schema = snapshot.metadata().schema(); + String metadataPath = snapshot.path().toString(); + String schemaStr = schema.json(); + return Pair.of(metadataPath, schemaStr); + } +} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/utils/HudiMedataUtil.java b/xtable-service/src/main/java/org/apache/xtable/service/utils/HudiMedataUtil.java new file mode 100644 index 000000000..afde10ae7 --- /dev/null +++ b/xtable-service/src/main/java/org/apache/xtable/service/utils/HudiMedataUtil.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service.utils; + +import jakarta.enterprise.context.ApplicationScoped; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.hadoop.conf.Configuration; +import org.apache.hudi.common.model.HoodieCommitMetadata; +import org.apache.hudi.common.table.HoodieTableMetaClient; +import org.apache.hudi.common.table.timeline.HoodieInstant; +import org.apache.hudi.common.table.timeline.HoodieTimeline; +import org.apache.hudi.common.util.Option; + +import java.io.IOException; + +@ApplicationScoped +public class HudiMedataUtil { + public Pair getHudiSchemaAndMetadataPath(String basePath, Configuration hadoopConf) { + // Get latest commit + HoodieTableMetaClient metaClient = HoodieTableMetaClient.builder() + .setBasePath(basePath) + .setConf(hadoopConf) + .build(); + HoodieTimeline commits = metaClient.getActiveTimeline() + .getCommitsTimeline() + .filterCompletedInstants(); + if (commits.empty()) { + throw new IllegalStateException("No completed commits found in " + basePath); + } + HoodieInstant lastInstant = commits.lastInstant().get(); + String metaDir = metaClient.getMetaPath(); + String fileName = lastInstant.getFileName(); + String hudiLatestCommitPath = String.join("/", basePath, metaDir, fileName); + + // Get latest schema + Option raw = metaClient.getActiveTimeline() + .getInstantDetails(lastInstant); + HoodieCommitMetadata commitMetadata; + try { + commitMetadata = HoodieCommitMetadata + .fromBytes(raw.get(), HoodieCommitMetadata.class); + } catch (IOException e) { + throw new RuntimeException(e); + } + String hudiSchemaStr = commitMetadata.getMetadata(HoodieCommitMetadata.SCHEMA_KEY); + if (hudiSchemaStr == null) { + throw new IllegalStateException("Commit " + lastInstant + " does not contain a schema"); + } + return Pair.of(hudiLatestCommitPath, hudiSchemaStr); + } +} diff --git a/xtable-service/src/main/resources/application.properties b/xtable-service/src/main/resources/application.properties index a4b397a25..f00ee7c8c 100644 --- a/xtable-service/src/main/resources/application.properties +++ b/xtable-service/src/main/resources/application.properties @@ -14,4 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -quarkus.log.level=DEBUG \ No newline at end of file +quarkus.log.level=INFO \ No newline at end of file From b6ef8e74b6bd7b9121c8aa45d8c118c3a47e4ac0 Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Tue, 6 May 2025 22:01:12 -0700 Subject: [PATCH 07/15] Address Vinish intial set of comments --- pom.xml | 10 -- xtable-service/pom.xml | 11 +- .../xtable/service/ConversionResource.java | 4 +- .../xtable/service/ConversionService.java | 149 +++++++++--------- ...tory.java => ConversionServiceConfig.java} | 16 +- .../service/models/ConvertTableResponse.java | 12 +- ...stTargetTable.java => ConvertedTable.java} | 4 +- .../xtable/service/spark/SparkHolder.java | 29 +++- .../service/utils/ConversionServiceUtil.java | 124 +++++++++++++++ .../service/utils/DeltaMetadataUtil.java | 38 ----- .../xtable/service/utils/HudiMedataUtil.java | 67 -------- .../service/utils/IcebergMetadataUtil.java | 43 ----- .../service/TestConversionResource.java | 14 +- .../xtable/service/TestConversionService.java | 21 +-- 14 files changed, 267 insertions(+), 275 deletions(-) rename xtable-service/src/main/java/org/apache/xtable/service/{ConversionControllerFactory.java => ConversionServiceConfig.java} (71%) rename xtable-service/src/main/java/org/apache/xtable/service/models/{RestTargetTable.java => ConvertedTable.java} (96%) create mode 100644 xtable-service/src/main/java/org/apache/xtable/service/utils/ConversionServiceUtil.java delete mode 100644 xtable-service/src/main/java/org/apache/xtable/service/utils/DeltaMetadataUtil.java delete mode 100644 xtable-service/src/main/java/org/apache/xtable/service/utils/HudiMedataUtil.java delete mode 100644 xtable-service/src/main/java/org/apache/xtable/service/utils/IcebergMetadataUtil.java diff --git a/pom.xml b/pom.xml index 9e19ea3f6..f4655f68d 100644 --- a/pom.xml +++ b/pom.xml @@ -358,16 +358,6 @@ ${spark.version} provided - - org.antlr - antlr4-runtime - ${antlr4.version} - - - org.scala-lang - scala-reflect - ${scala.version} - commons-cli diff --git a/xtable-service/pom.xml b/xtable-service/pom.xml index 4d7bec70d..46b0f08c8 100644 --- a/xtable-service/pom.xml +++ b/xtable-service/pom.xml @@ -27,7 +27,6 @@ xtable-service - @@ -37,6 +36,16 @@ pom import + + org.antlr + antlr4-runtime + ${antlr4.version} + + + org.scala-lang + scala-reflect + ${scala.version} + diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionResource.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionResource.java index 3174b92c4..ba70b0409 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/ConversionResource.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionResource.java @@ -39,7 +39,7 @@ public class ConversionResource { @POST @Path("/table") @Blocking - public ConvertTableResponse convertTable(ConvertTableRequest req) { - return conversionService.convertTable(req); + public ConvertTableResponse convertTable(ConvertTableRequest convertTableRequest) { + return conversionService.convertTable(convertTableRequest); } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java index 22e683ff1..158aaedcc 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java @@ -26,126 +26,131 @@ import java.util.List; import org.apache.commons.lang3.tuple.Pair; -import org.apache.hadoop.conf.Configuration; -import org.apache.hudi.common.table.timeline.HoodieInstant; - -import org.apache.iceberg.Snapshot; +import com.google.common.annotations.VisibleForTesting; import org.apache.xtable.conversion.ConversionConfig; import org.apache.xtable.conversion.ConversionController; import org.apache.xtable.conversion.ConversionSourceProvider; import org.apache.xtable.conversion.SourceTable; import org.apache.xtable.conversion.TargetTable; -import org.apache.xtable.delta.DeltaConversionSourceProvider; -import org.apache.xtable.hudi.HudiConversionSourceProvider; -import org.apache.xtable.iceberg.IcebergConversionSourceProvider; import org.apache.xtable.service.models.ConvertTableRequest; import org.apache.xtable.service.models.ConvertTableResponse; -import org.apache.xtable.service.models.RestTargetTable; +import org.apache.xtable.service.models.ConvertedTable; import org.apache.xtable.service.spark.SparkHolder; -import org.apache.xtable.service.utils.DeltaMetadataUtil; -import org.apache.xtable.service.utils.HudiMedataUtil; -import org.apache.xtable.service.utils.IcebergMetadataUtil; +import org.apache.xtable.service.utils.ConversionServiceUtil; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; +/** + * Service for managing table format conversions. + * + *

It supports formats such as ICEBERG, HUDI, and DELTA. The conversion process involves creating + * a source table, generating target tables, and then executing the conversion via a designated + * conversion controller. + */ @ApplicationScoped public class ConversionService { private final SparkHolder sparkHolder; - private final ConversionControllerFactory controllerFactory; - private final IcebergMetadataUtil icebergUtil; - private final HudiMedataUtil hudiUtil; - private final DeltaMetadataUtil deltaUtil; + private final ConversionController conversionController; + private final ConversionServiceUtil conversionServiceUtil; + /** + * Constructs a ConversionService instance with required dependencies. + * + * @param sparkHolder the Spark holder instance containing the Spark context and configuration + * @param conversionServiceUtil utility for handling metadata operations + */ @Inject + public ConversionService(SparkHolder sparkHolder, ConversionServiceUtil conversionServiceUtil) { + this.sparkHolder = sparkHolder; + this.conversionServiceUtil = conversionServiceUtil; + this.conversionController = new ConversionController(sparkHolder.jsc().hadoopConfiguration()); + } + + /** + * Constructs a ConversionService instance using dependency injection for testing. + * + * @param sparkHolder the Spark holder instance + * @param conversionController a preconfigured conversion controller + * @param conversionServiceUtil utility for handling metadata operations + */ + @VisibleForTesting public ConversionService( SparkHolder sparkHolder, - ConversionControllerFactory controllerFactory, - IcebergMetadataUtil icebergUtil, - HudiMedataUtil hudiUtil, - DeltaMetadataUtil deltaUtil) { + ConversionServiceUtil conversionServiceUtil, + ConversionController conversionController) { this.sparkHolder = sparkHolder; - this.controllerFactory = controllerFactory; - this.icebergUtil = icebergUtil; - this.hudiUtil = hudiUtil; - this.deltaUtil = deltaUtil; + this.conversionController = conversionController; + this.conversionServiceUtil = conversionServiceUtil; } - public ConvertTableResponse convertTable(ConvertTableRequest request) { - Configuration conf = sparkHolder.jsc().hadoopConfiguration(); - ConversionController conversionController = controllerFactory.create(conf); - + /** + * Converts a source table to one or more target table formats. + * + *

The method builds a SourceTable based on the request parameters and constructs corresponding + * TargetTable instances for each target format. It then performs a synchronous conversion through + * the conversion controller. After conversion, it retrieves schema and metadata paths for each + * target table. + * + * @param convertTableRequest the conversion request containing source table details and target + * formats + * @return a response containing details of converted target tables + */ + public ConvertTableResponse convertTable(ConvertTableRequest convertTableRequest) { SourceTable sourceTable = SourceTable.builder() - .name(request.getSourceTableName()) - .basePath(request.getSourceTablePath()) - .formatName(request.getSourceFormat()) + .name(convertTableRequest.getSourceTableName()) + .basePath(convertTableRequest.getSourceTablePath()) + .formatName(convertTableRequest.getSourceFormat()) .build(); List targetTables = new ArrayList<>(); - for (String targetFormat : request.getTargetFormats()) { + for (String targetFormat : convertTableRequest.getTargetFormats()) { TargetTable targetTable = TargetTable.builder() - .name(request.getSourceTableName()) - .basePath(request.getSourceTablePath()) + .name(convertTableRequest.getSourceTableName()) + .basePath(convertTableRequest.getSourceTablePath()) .formatName(targetFormat) .build(); targetTables.add(targetTable); } + ConversionConfig conversionConfig = ConversionConfig.builder().sourceTable(sourceTable).targetTables(targetTables).build(); + ConversionSourceProvider conversionSourceProvider = - getConversionSourceProvider(request.getSourceFormat()); + conversionServiceUtil.getConversionSourceProvider( + convertTableRequest.getSourceFormat(), sparkHolder.jsc().hadoopConfiguration()); + conversionController.sync(conversionConfig, conversionSourceProvider); - List restTargetTables = new ArrayList<>(); - for (String targetFormat : request.getTargetFormats()) { - if (targetFormat.equals("ICEBERG")) { + List restTargetTables = new ArrayList<>(); + for (String targetFormat : convertTableRequest.getTargetFormats()) { + if (targetFormat.equals(ICEBERG)) { Pair responseFields = - icebergUtil.getIcebergSchemaAndMetadataPath( - request.getSourceTablePath(), sparkHolder.jsc().hadoopConfiguration()); - RestTargetTable icebergTable = - new RestTargetTable("ICEBERG", responseFields.getLeft(), responseFields.getRight()); + conversionServiceUtil.getIcebergSchemaAndMetadataPath( + convertTableRequest.getSourceTablePath(), sparkHolder.jsc().hadoopConfiguration()); + ConvertedTable icebergTable = + new ConvertedTable(ICEBERG, responseFields.getLeft(), responseFields.getRight()); restTargetTables.add(icebergTable); - } else if (targetFormat.equals("HUDI")) { + } else if (targetFormat.equals(HUDI)) { Pair responseFields = - hudiUtil.getHudiSchemaAndMetadataPath( - request.getSourceTablePath(), sparkHolder.jsc().hadoopConfiguration()); - RestTargetTable hudiTable = - new RestTargetTable("HUDI", responseFields.getLeft(), responseFields.getRight()); + conversionServiceUtil.getHudiSchemaAndMetadataPath( + convertTableRequest.getSourceTablePath(), sparkHolder.jsc().hadoopConfiguration()); + ConvertedTable hudiTable = + new ConvertedTable(HUDI, responseFields.getLeft(), responseFields.getRight()); restTargetTables.add(hudiTable); - } else if(targetFormat.equals("DELTA")){ + } else if (targetFormat.equals(DELTA)) { Pair responseFields = - deltaUtil.getDeltaSchemaAndMetadataPath( - request.getSourceTablePath(), sparkHolder.spark()); - RestTargetTable deltaTable = - new RestTargetTable("DELTA", responseFields.getLeft(), responseFields.getRight()); + conversionServiceUtil.getDeltaSchemaAndMetadataPath( + convertTableRequest.getSourceTablePath(), sparkHolder.spark()); + ConvertedTable deltaTable = + new ConvertedTable(DELTA, responseFields.getLeft(), responseFields.getRight()); restTargetTables.add(deltaTable); } } return new ConvertTableResponse(restTargetTables); } - - private ConversionSourceProvider getConversionSourceProvider(String sourceTableFormat) { - if (sourceTableFormat.equalsIgnoreCase(HUDI)) { - ConversionSourceProvider hudiConversionSourceProvider = - new HudiConversionSourceProvider(); - hudiConversionSourceProvider.init(sparkHolder.jsc().hadoopConfiguration()); - return hudiConversionSourceProvider; - } else if (sourceTableFormat.equalsIgnoreCase(DELTA)) { - ConversionSourceProvider deltaConversionSourceProvider = - new DeltaConversionSourceProvider(); - deltaConversionSourceProvider.init(sparkHolder.jsc().hadoopConfiguration()); - return deltaConversionSourceProvider; - } else if (sourceTableFormat.equalsIgnoreCase(ICEBERG)) { - ConversionSourceProvider icebergConversionSourceProvider = - new IcebergConversionSourceProvider(); - icebergConversionSourceProvider.init(sparkHolder.jsc().hadoopConfiguration()); - return icebergConversionSourceProvider; - } else { - throw new IllegalArgumentException("Unsupported source format: " + sourceTableFormat); - } - } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionControllerFactory.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceConfig.java similarity index 71% rename from xtable-service/src/main/java/org/apache/xtable/service/ConversionControllerFactory.java rename to xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceConfig.java index 82210f94e..1da7c0594 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/ConversionControllerFactory.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionServiceConfig.java @@ -18,15 +18,19 @@ package org.apache.xtable.service; -import org.apache.hadoop.conf.Configuration; - -import org.apache.xtable.conversion.ConversionController; +import org.eclipse.microprofile.config.inject.ConfigProperty; import jakarta.enterprise.context.ApplicationScoped; @ApplicationScoped -public class ConversionControllerFactory { - public ConversionController create(Configuration conf) { - return new ConversionController(conf); +public class ConversionServiceConfig { + + public static final String HADOOP_DEFAULTS_XML = "xtable-hadoop-defaults.xml"; + + @ConfigProperty(name = "xtable.hadoop-config-path", defaultValue = HADOOP_DEFAULTS_XML) + private String hadoopConfigPath; + + public String getHadoopConfigPath() { + return hadoopConfigPath; } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java index 087048915..3aab96cd1 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java @@ -27,15 +27,15 @@ @Builder public class ConvertTableResponse { - @JsonProperty("conversions") - private List conversions; + @JsonProperty("convertedTables") + private List convertedTables; @JsonCreator - public ConvertTableResponse(@JsonProperty List conversions) { - this.conversions = conversions; + public ConvertTableResponse(@JsonProperty List convertedTables) { + this.convertedTables = convertedTables; } - public List getConversions() { - return conversions; + public List getConvertedTables() { + return convertedTables; } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/models/RestTargetTable.java b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertedTable.java similarity index 96% rename from xtable-service/src/main/java/org/apache/xtable/service/models/RestTargetTable.java rename to xtable-service/src/main/java/org/apache/xtable/service/models/ConvertedTable.java index b5f866087..329691949 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/models/RestTargetTable.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertedTable.java @@ -24,7 +24,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @Builder -public class RestTargetTable { +public class ConvertedTable { @JsonProperty("target-format") private String targetFormat; @@ -35,7 +35,7 @@ public class RestTargetTable { private String targetSchema; @JsonCreator - public RestTargetTable( + public ConvertedTable( @JsonProperty String targetFormat, @JsonProperty String targetMetadataPath, @JsonProperty String targetSchema) { diff --git a/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java b/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java index ac109e84f..627de7d91 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java @@ -18,23 +18,31 @@ package org.apache.xtable.service.spark; +import static org.apache.xtable.service.ConversionServiceConfig.HADOOP_DEFAULTS_XML; + import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaSparkContext; import org.apache.spark.serializer.KryoSerializer; import org.apache.spark.sql.SparkSession; +import org.apache.xtable.service.ConversionServiceConfig; + import io.quarkus.runtime.ShutdownEvent; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; @ApplicationScoped public class SparkHolder { private volatile SparkSession spark; private volatile JavaSparkContext jsc; - private static final String HADOOP_DEFAULTS_PATH = "xtable-hadoop-defaults.xml"; + + @Inject private ConversionServiceConfig conversionServiceConfig; public SparkSession spark() { if (spark == null) { @@ -46,12 +54,19 @@ public SparkSession spark() { .appName("xtable-conversion-service") .getOrCreate(); jsc = JavaSparkContext.fromSparkContext(spark.sparkContext()); - InputStream resourceStream = - SparkHolder.class.getClassLoader().getResourceAsStream(HADOOP_DEFAULTS_PATH); - if (resourceStream != null) { - spark.sparkContext().hadoopConfiguration().addResource(resourceStream); - } else { - throw new RuntimeException("Failed to load resource xtable-hadoop-defaults.xml"); + + // Load user-provided Hadoop XML file if available, otherwise load the default + try (InputStream configStream = + !conversionServiceConfig.getHadoopConfigPath().equals(HADOOP_DEFAULTS_XML) + ? Files.newInputStream(Paths.get(conversionServiceConfig.getHadoopConfigPath())) + : SparkHolder.class.getClassLoader().getResourceAsStream(HADOOP_DEFAULTS_XML)) { + if (configStream != null) { + spark.sparkContext().hadoopConfiguration().addResource(configStream); + } else { + throw new RuntimeException("Failed to load Hadoop configuration file"); + } + } catch (Exception e) { + throw new RuntimeException("Error loading Hadoop configuration file", e); } } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/utils/ConversionServiceUtil.java b/xtable-service/src/main/java/org/apache/xtable/service/utils/ConversionServiceUtil.java new file mode 100644 index 000000000..f7a3937dd --- /dev/null +++ b/xtable-service/src/main/java/org/apache/xtable/service/utils/ConversionServiceUtil.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service.utils; + +import java.io.IOException; + +import org.apache.commons.lang3.tuple.Pair; +import org.apache.hadoop.conf.Configuration; +import org.apache.spark.sql.SparkSession; +import org.apache.spark.sql.types.StructType; + +import org.apache.hudi.common.model.HoodieCommitMetadata; +import org.apache.hudi.common.table.HoodieTableMetaClient; +import org.apache.hudi.common.table.timeline.HoodieInstant; +import org.apache.hudi.common.table.timeline.HoodieTimeline; +import org.apache.hudi.common.util.Option; + +import org.apache.iceberg.BaseTable; +import org.apache.iceberg.SchemaParser; +import org.apache.iceberg.Table; +import org.apache.iceberg.TableMetadata; +import org.apache.iceberg.TableOperations; +import org.apache.iceberg.hadoop.HadoopTables; + +import org.apache.spark.sql.delta.DeltaLog; +import org.apache.spark.sql.delta.Snapshot; + +import jakarta.enterprise.context.ApplicationScoped; +import org.apache.xtable.conversion.ConversionSourceProvider; +import org.apache.xtable.delta.DeltaConversionSourceProvider; +import org.apache.xtable.hudi.HudiConversionSourceProvider; +import org.apache.xtable.iceberg.IcebergConversionSourceProvider; + +import static org.apache.xtable.model.storage.TableFormat.DELTA; +import static org.apache.xtable.model.storage.TableFormat.HUDI; +import static org.apache.xtable.model.storage.TableFormat.ICEBERG; + +@ApplicationScoped +public class ConversionServiceUtil { + + public Pair getDeltaSchemaAndMetadataPath( + String basePath, SparkSession sparkSession) { + DeltaLog deltaLog = DeltaLog.forTable(sparkSession, basePath); + Snapshot snapshot = deltaLog.snapshot(); + StructType schema = snapshot.metadata().schema(); + String metadataPath = snapshot.path().toString(); + String schemaStr = schema.json(); + return Pair.of(metadataPath, schemaStr); + } + + public Pair getHudiSchemaAndMetadataPath( + String basePath, Configuration hadoopConf) { + HoodieTableMetaClient metaClient = + HoodieTableMetaClient.builder().setBasePath(basePath).setConf(hadoopConf).build(); + HoodieTimeline commits = + metaClient.getActiveTimeline().getCommitsTimeline().filterCompletedInstants(); + if (commits.empty()) { + throw new IllegalStateException("No completed commits found in " + basePath); + } + HoodieInstant lastInstant = commits.lastInstant().get(); + String metaDir = metaClient.getMetaPath(); + String fileName = lastInstant.getFileName(); + String hudiLatestCommitPath = String.join("/", basePath, metaDir, fileName); + + Option raw = metaClient.getActiveTimeline().getInstantDetails(lastInstant); + HoodieCommitMetadata commitMetadata; + try { + commitMetadata = HoodieCommitMetadata.fromBytes(raw.get(), HoodieCommitMetadata.class); + } catch (IOException e) { + throw new RuntimeException(e); + } + String hudiSchemaStr = commitMetadata.getMetadata(HoodieCommitMetadata.SCHEMA_KEY); + if (hudiSchemaStr == null) { + throw new IllegalStateException("Commit " + lastInstant + " does not contain a schema"); + } + return Pair.of(hudiLatestCommitPath, hudiSchemaStr); + } + + public Pair getIcebergSchemaAndMetadataPath( + String tableLocation, Configuration conf) { + HadoopTables tables = new HadoopTables(conf); + Table table = tables.load(tableLocation); + TableOperations ops = ((BaseTable) table).operations(); + TableMetadata current = ops.current(); + return Pair.of(current.metadataFileLocation(), SchemaParser.toJson(current.schema())); + } + + public ConversionSourceProvider getConversionSourceProvider(String sourceTableFormat, Configuration hadoopConf) { + if (sourceTableFormat.equalsIgnoreCase(HUDI)) { + ConversionSourceProvider hudiConversionSourceProvider = + new HudiConversionSourceProvider(); + hudiConversionSourceProvider.init(hadoopConf); + return hudiConversionSourceProvider; + } else if (sourceTableFormat.equalsIgnoreCase(DELTA)) { + ConversionSourceProvider deltaConversionSourceProvider = + new DeltaConversionSourceProvider(); + deltaConversionSourceProvider.init(hadoopConf); + return deltaConversionSourceProvider; + } else if (sourceTableFormat.equalsIgnoreCase(ICEBERG)) { + ConversionSourceProvider icebergConversionSourceProvider = + new IcebergConversionSourceProvider(); + icebergConversionSourceProvider.init(hadoopConf); + return icebergConversionSourceProvider; + } else { + throw new IllegalArgumentException("Unsupported source format: " + sourceTableFormat); + } + } +} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/utils/DeltaMetadataUtil.java b/xtable-service/src/main/java/org/apache/xtable/service/utils/DeltaMetadataUtil.java deleted file mode 100644 index 80aad1dc9..000000000 --- a/xtable-service/src/main/java/org/apache/xtable/service/utils/DeltaMetadataUtil.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.xtable.service.utils; - -import jakarta.enterprise.context.ApplicationScoped; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.spark.sql.SparkSession; -import org.apache.spark.sql.delta.DeltaLog; -import org.apache.spark.sql.delta.Snapshot; -import org.apache.spark.sql.types.StructType; - -@ApplicationScoped -public class DeltaMetadataUtil { - public Pair getDeltaSchemaAndMetadataPath(String basePath, SparkSession sparkSession) { - DeltaLog deltaLog = DeltaLog.forTable(sparkSession, basePath); - Snapshot snapshot = deltaLog.snapshot(); - StructType schema = snapshot.metadata().schema(); - String metadataPath = snapshot.path().toString(); - String schemaStr = schema.json(); - return Pair.of(metadataPath, schemaStr); - } -} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/utils/HudiMedataUtil.java b/xtable-service/src/main/java/org/apache/xtable/service/utils/HudiMedataUtil.java deleted file mode 100644 index afde10ae7..000000000 --- a/xtable-service/src/main/java/org/apache/xtable/service/utils/HudiMedataUtil.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.xtable.service.utils; - -import jakarta.enterprise.context.ApplicationScoped; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.hadoop.conf.Configuration; -import org.apache.hudi.common.model.HoodieCommitMetadata; -import org.apache.hudi.common.table.HoodieTableMetaClient; -import org.apache.hudi.common.table.timeline.HoodieInstant; -import org.apache.hudi.common.table.timeline.HoodieTimeline; -import org.apache.hudi.common.util.Option; - -import java.io.IOException; - -@ApplicationScoped -public class HudiMedataUtil { - public Pair getHudiSchemaAndMetadataPath(String basePath, Configuration hadoopConf) { - // Get latest commit - HoodieTableMetaClient metaClient = HoodieTableMetaClient.builder() - .setBasePath(basePath) - .setConf(hadoopConf) - .build(); - HoodieTimeline commits = metaClient.getActiveTimeline() - .getCommitsTimeline() - .filterCompletedInstants(); - if (commits.empty()) { - throw new IllegalStateException("No completed commits found in " + basePath); - } - HoodieInstant lastInstant = commits.lastInstant().get(); - String metaDir = metaClient.getMetaPath(); - String fileName = lastInstant.getFileName(); - String hudiLatestCommitPath = String.join("/", basePath, metaDir, fileName); - - // Get latest schema - Option raw = metaClient.getActiveTimeline() - .getInstantDetails(lastInstant); - HoodieCommitMetadata commitMetadata; - try { - commitMetadata = HoodieCommitMetadata - .fromBytes(raw.get(), HoodieCommitMetadata.class); - } catch (IOException e) { - throw new RuntimeException(e); - } - String hudiSchemaStr = commitMetadata.getMetadata(HoodieCommitMetadata.SCHEMA_KEY); - if (hudiSchemaStr == null) { - throw new IllegalStateException("Commit " + lastInstant + " does not contain a schema"); - } - return Pair.of(hudiLatestCommitPath, hudiSchemaStr); - } -} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/utils/IcebergMetadataUtil.java b/xtable-service/src/main/java/org/apache/xtable/service/utils/IcebergMetadataUtil.java deleted file mode 100644 index bac0c4cd4..000000000 --- a/xtable-service/src/main/java/org/apache/xtable/service/utils/IcebergMetadataUtil.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.xtable.service.utils; - -import org.apache.commons.lang3.tuple.Pair; -import org.apache.hadoop.conf.Configuration; - -import org.apache.iceberg.BaseTable; -import org.apache.iceberg.SchemaParser; -import org.apache.iceberg.Table; -import org.apache.iceberg.TableMetadata; -import org.apache.iceberg.TableOperations; -import org.apache.iceberg.hadoop.HadoopTables; - -import jakarta.enterprise.context.ApplicationScoped; - -@ApplicationScoped -public class IcebergMetadataUtil { - public Pair getIcebergSchemaAndMetadataPath( - String tableLocation, Configuration conf) { - HadoopTables tables = new HadoopTables(conf); - Table table = tables.load(tableLocation); - TableOperations ops = ((BaseTable) table).operations(); - TableMetadata current = ops.current(); - return Pair.of(current.metadataFileLocation(), SchemaParser.toJson(current.schema())); - } -} diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java index a71db834e..e0e86ee91 100644 --- a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java @@ -32,7 +32,7 @@ import org.apache.xtable.service.models.ConvertTableRequest; import org.apache.xtable.service.models.ConvertTableResponse; -import org.apache.xtable.service.models.RestTargetTable; +import org.apache.xtable.service.models.ConvertedTable; @ExtendWith(MockitoExtension.class) class TestConversionResource { @@ -54,14 +54,14 @@ void testConvertTableResource() { .targetFormats(Arrays.asList("ICEBERG")) .build(); - RestTargetTable icebergTable = - RestTargetTable.builder() + ConvertedTable icebergTable = + ConvertedTable.builder() .targetFormat("ICEBERG") .targetMetadataPath(TARGET_ICEBERG_METADATA_PATH) .build(); ConvertTableResponse expected = - ConvertTableResponse.builder().conversions(Arrays.asList(icebergTable)).build(); + ConvertTableResponse.builder().convertedTables(Arrays.asList(icebergTable)).build(); when(conversionService.convertTable(req)).thenReturn(expected); ConvertTableResponse actual = resource.convertTable(req); verify(conversionService).convertTable(req); @@ -69,9 +69,9 @@ void testConvertTableResource() { assertNotNull(actual); assertSame(expected, actual, "Resource should return the exact response from the service"); - assertEquals(1, actual.getConversions().size()); - assertEquals("ICEBERG", actual.getConversions().get(0).getTargetFormat()); + assertEquals(1, actual.getConvertedTables().size()); + assertEquals("ICEBERG", actual.getConvertedTables().get(0).getTargetFormat()); assertEquals( - TARGET_ICEBERG_METADATA_PATH, actual.getConversions().get(0).getTargetMetadataPath()); + TARGET_ICEBERG_METADATA_PATH, actual.getConvertedTables().get(0).getTargetMetadataPath()); } } diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java index a9292dfa4..4490f34f1 100644 --- a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java @@ -48,7 +48,6 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.hadoop.conf.Configuration; import org.apache.spark.api.java.JavaSparkContext; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -59,9 +58,9 @@ import org.apache.xtable.conversion.ConversionController; import org.apache.xtable.service.models.ConvertTableRequest; import org.apache.xtable.service.models.ConvertTableResponse; -import org.apache.xtable.service.models.RestTargetTable; +import org.apache.xtable.service.models.ConvertedTable; import org.apache.xtable.service.spark.SparkHolder; -import org.apache.xtable.service.utils.IcebergMetadataUtil; +import org.apache.xtable.service.utils.ConversionServiceUtil; @ExtendWith(MockitoExtension.class) class TestConversionService { @@ -74,23 +73,17 @@ class TestConversionService { private final Configuration conf = new Configuration(); @Mock SparkHolder sparkHolder; - @Mock ConversionControllerFactory controllerFactory; - @Mock IcebergMetadataUtil icebergUtil; + @Mock ConversionServiceUtil conversionServiceUtil; @Mock ConversionController controller; @Mock JavaSparkContext jsc; @InjectMocks ConversionService service; - @BeforeEach - void setUp() { - when(sparkHolder.jsc()).thenReturn(jsc); - when(jsc.hadoopConfiguration()).thenReturn(conf); - when(controllerFactory.create(conf)).thenReturn(controller); - } - @Test void serviceConvertTableWithDeltaSourceAndTargetIceberg() { - when(icebergUtil.getIcebergSchemaAndMetadataPath(SOURCE_TABLE_BASE_PATH, conf)) + when(sparkHolder.jsc()).thenReturn(jsc); + when(jsc.hadoopConfiguration()).thenReturn(conf); + when(conversionServiceUtil.getIcebergSchemaAndMetadataPath(SOURCE_TABLE_BASE_PATH, conf)) .thenReturn(Pair.of(TARGET_ICEBERG_METADATA_PATH, TARGET_SCHEMA)); ConvertTableRequest req = @@ -104,7 +97,7 @@ void serviceConvertTableWithDeltaSourceAndTargetIceberg() { ConvertTableResponse resp = service.convertTable(req); verify(controller, times(1)).sync(any(ConversionConfig.class), any()); - RestTargetTable restTargetTable = resp.getConversions().get(0); + ConvertedTable restTargetTable = resp.getConvertedTables().get(0); assertEquals("ICEBERG", restTargetTable.getTargetFormat()); assertEquals(TARGET_ICEBERG_METADATA_PATH, restTargetTable.getTargetMetadataPath()); assertEquals(TARGET_SCHEMA, restTargetTable.getTargetSchema()); From 85d3b62332189769b08607f8085390a52c142bec Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Wed, 7 May 2025 15:47:26 -0700 Subject: [PATCH 08/15] add unit test for util --- .../service/TestConversionServiceUtil.java | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 xtable-service/src/test/java/org/apache/xtable/service/TestConversionServiceUtil.java diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionServiceUtil.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionServiceUtil.java new file mode 100644 index 000000000..0502de92b --- /dev/null +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionServiceUtil.java @@ -0,0 +1,211 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.xtable.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +import java.nio.charset.StandardCharsets; + +import org.apache.commons.lang3.tuple.Pair; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hudi.common.table.timeline.HoodieActiveTimeline; +import org.apache.hudi.common.table.timeline.HoodieTimeline; +import org.apache.iceberg.BaseTable; +import org.apache.iceberg.SchemaParser; +import org.apache.iceberg.TableMetadata; +import org.apache.iceberg.TableOperations; +import org.apache.iceberg.hadoop.HadoopTables; +import org.apache.hudi.common.model.HoodieCommitMetadata; +import org.apache.hudi.common.table.HoodieTableMetaClient; +import org.apache.hudi.common.table.timeline.HoodieInstant; +import org.apache.hudi.common.util.Option; +import org.apache.spark.sql.SparkSession; +import org.apache.spark.sql.types.DataTypes; +import org.apache.spark.sql.types.StructType; +import org.apache.spark.sql.delta.DeltaLog; +import org.apache.spark.sql.delta.Snapshot; +import org.apache.xtable.model.storage.TableFormat; +import org.apache.xtable.service.utils.ConversionServiceUtil; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.MockedConstruction; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; +import org.apache.xtable.conversion.ConversionSourceProvider; +import org.apache.xtable.delta.DeltaConversionSourceProvider; +import org.apache.xtable.hudi.HudiConversionSourceProvider; +import org.apache.xtable.iceberg.IcebergConversionSourceProvider; +import org.apache.spark.sql.delta.actions.Metadata; + +@ExtendWith(MockitoExtension.class) +class TestConversionServiceUtil { + private static final String DELTA_BASE_PATH = "/tmp/delta-table"; + private static final String DELTA_METADATA_JSON = "/_delta_log/000000000.json"; + + private static final String HUDI_BASE_PATH = "/tmp/hudi-table"; + private static final String HUDI_METADATA_DIR = ".hoodie"; + private static final String HUDI_INSTANT_FILE = "20250506.commit"; + private static final String HUDI_SCHEMA = + "{\n" + + " \"type\": \"record\",\n" + + " \"name\": \"user\",\n" + + " \"namespace\": \"example.hudi\",\n" + + " \"fields\": [\n" + + " { \"name\": \"id\", \"type\": \"string\" },\n" + + " ]\n" + + "}"; + + private static final String ICEBERG_BASE_PATH = "/tmp/iceberg-table"; + private static final String ICEBERG_METADATA_JSON = "/metadata/v1.json"; + private static final String ICEBERG_SCHEMA = + "{\n" + + " \"type\": \"struct\",\n" + + " \"fields\": [\n" + + " { \"id\": 1, \"name\": \"id\", \"required\": true, \"type\": \"string\" },\n" + + " ]\n" + + "}"; + + @Mock SparkSession sparkSession; + @Mock Configuration hadoopConf; + + private final ConversionServiceUtil util = new ConversionServiceUtil(); + + @Test + void testGetDeltaSchemaAndMetadataPath() { + StructType testSchema = new StructType().add("id", DataTypes.IntegerType); + Path testPath = new Path(DELTA_BASE_PATH + DELTA_METADATA_JSON); + + try (MockedStatic deltaStatic = mockStatic(DeltaLog.class)) { + DeltaLog mockLog = mock(DeltaLog.class); + Snapshot mockSnap = mock(Snapshot.class); + Metadata mockMetadata = mock(Metadata.class); + + deltaStatic.when(() -> DeltaLog.forTable(sparkSession, DELTA_BASE_PATH)) + .thenReturn(mockLog); + when(mockLog.snapshot()).thenReturn(mockSnap); + when(mockSnap.metadata()).thenReturn(mockMetadata); + when(mockMetadata.schema()).thenReturn(testSchema); + when(mockSnap.path()).thenReturn(testPath); + + Pair result = util.getDeltaSchemaAndMetadataPath(DELTA_BASE_PATH, sparkSession); + assertEquals(testPath.toString(), result.getLeft()); + assertEquals(testSchema.json(), result.getRight()); + } + } + + @Test + void testGetHudiSchemaAndMetadataPath() { + try (MockedStatic clientStatic = mockStatic(HoodieTableMetaClient.class); + MockedStatic commitStatic = mockStatic(HoodieCommitMetadata.class)) { + + HoodieTableMetaClient.Builder builder = mock(HoodieTableMetaClient.Builder.class); + HoodieTableMetaClient metaClient = mock(HoodieTableMetaClient.class); + + clientStatic.when(HoodieTableMetaClient::builder).thenReturn(builder); + when(builder.setBasePath(HUDI_BASE_PATH)).thenReturn(builder); + when(builder.setConf(hadoopConf)).thenReturn(builder); + when(builder.build()).thenReturn(metaClient); + + HoodieActiveTimeline activeTimeline = mock(HoodieActiveTimeline.class); + HoodieTimeline commitsTimeline = mock(HoodieTimeline.class); + HoodieInstant instant = mock(HoodieInstant.class); + + when(metaClient.getActiveTimeline()).thenReturn(activeTimeline); + when(activeTimeline.getCommitsTimeline()).thenReturn(commitsTimeline); + when(commitsTimeline.filterCompletedInstants()).thenReturn(commitsTimeline); + when(commitsTimeline.empty()).thenReturn(false); + when(commitsTimeline.lastInstant()).thenReturn(Option.of(instant)); + + when(metaClient.getMetaPath()).thenReturn(HUDI_METADATA_DIR); + when(instant.getFileName()).thenReturn(HUDI_INSTANT_FILE); + + byte[] rawBytes = "data".getBytes(StandardCharsets.UTF_8); + Option rawOption = Option.of(rawBytes); + when(activeTimeline.getInstantDetails(instant)).thenReturn(rawOption); + + HoodieCommitMetadata commitMetadata = mock(HoodieCommitMetadata.class); + commitStatic.when(() -> HoodieCommitMetadata.fromBytes(rawBytes, HoodieCommitMetadata.class)) + .thenReturn(commitMetadata); + when(commitMetadata.getMetadata(HoodieCommitMetadata.SCHEMA_KEY)) + .thenReturn(HUDI_SCHEMA); + + Pair result = + util.getHudiSchemaAndMetadataPath(HUDI_BASE_PATH, hadoopConf); + + assertEquals(HUDI_BASE_PATH + "/" + HUDI_METADATA_DIR + "/" + HUDI_INSTANT_FILE, + result.getLeft()); + assertEquals(HUDI_SCHEMA, + result.getRight()); + } + } + + @Test + void testGetIcebergSchemaAndMetadataPath() { + try (MockedConstruction tablesCons = + mockConstruction(HadoopTables.class, + (mockTables, ctx) -> { + BaseTable mockTable = mock(BaseTable.class); + TableOperations ops = mock(TableOperations.class); + TableMetadata meta = mock(TableMetadata.class); + + when(mockTables.load(ICEBERG_BASE_PATH)).thenReturn(mockTable); + when(mockTable.operations()).thenReturn(ops); + when(ops.current()).thenReturn(meta); + when(meta.metadataFileLocation()).thenReturn(ICEBERG_BASE_PATH + ICEBERG_METADATA_JSON); + }); + MockedStatic parserStatic = + mockStatic(SchemaParser.class)) { + parserStatic.when(() -> SchemaParser.toJson(any())) + .thenReturn(ICEBERG_SCHEMA); + + Pair result = + util.getIcebergSchemaAndMetadataPath(ICEBERG_BASE_PATH, hadoopConf); + + assertEquals(ICEBERG_BASE_PATH + ICEBERG_METADATA_JSON, result.getLeft()); + assertEquals(ICEBERG_SCHEMA, result.getRight()); + } + } + + @Test + void testGetConversionSourceProvider() { + ConversionSourceProvider hudiProvider = + util.getConversionSourceProvider(TableFormat.HUDI, hadoopConf); + assertTrue(hudiProvider instanceof HudiConversionSourceProvider); + + ConversionSourceProvider deltaProvider = + util.getConversionSourceProvider(TableFormat.DELTA, hadoopConf); + assertTrue(deltaProvider instanceof DeltaConversionSourceProvider); + + ConversionSourceProvider icebergProvider = + util.getConversionSourceProvider(TableFormat.ICEBERG, hadoopConf); + assertTrue(icebergProvider instanceof IcebergConversionSourceProvider); + + assertThrows(IllegalArgumentException.class, + () -> util.getConversionSourceProvider("SomeFormat", hadoopConf)); + } +} \ No newline at end of file From 6f483e10240740a881f42c54967c26c3f1369f33 Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Wed, 7 May 2025 16:08:52 -0700 Subject: [PATCH 09/15] minor fix for other unit test --- .../xtable/service/TestConversionResource.java | 12 +++++++----- .../apache/xtable/service/TestConversionService.java | 7 ++++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java index e0e86ee91..75b45e5b7 100644 --- a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java @@ -24,6 +24,7 @@ import java.util.Arrays; +import org.apache.xtable.model.storage.TableFormat; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -37,6 +38,7 @@ @ExtendWith(MockitoExtension.class) class TestConversionResource { + private static final String SOURCE_TABLE_NAME = "users"; private static final String SOURCE_TABLE_BASE_PATH = "s3://bucket/tables/users"; private static final String TARGET_ICEBERG_METADATA_PATH = "s3://bucket/tables/users/metadata"; @@ -48,15 +50,15 @@ class TestConversionResource { void testConvertTableResource() { ConvertTableRequest req = ConvertTableRequest.builder() - .sourceFormat("DELTA") - .sourceTableName("users") + .sourceFormat(TableFormat.DELTA) + .sourceTableName(SOURCE_TABLE_NAME) .sourceTablePath(SOURCE_TABLE_BASE_PATH) - .targetFormats(Arrays.asList("ICEBERG")) + .targetFormats(Arrays.asList(TableFormat.ICEBERG)) .build(); ConvertedTable icebergTable = ConvertedTable.builder() - .targetFormat("ICEBERG") + .targetFormat(TableFormat.ICEBERG) .targetMetadataPath(TARGET_ICEBERG_METADATA_PATH) .build(); @@ -70,7 +72,7 @@ void testConvertTableResource() { assertSame(expected, actual, "Resource should return the exact response from the service"); assertEquals(1, actual.getConvertedTables().size()); - assertEquals("ICEBERG", actual.getConvertedTables().get(0).getTargetFormat()); + assertEquals(TableFormat.ICEBERG, actual.getConvertedTables().get(0).getTargetFormat()); assertEquals( TARGET_ICEBERG_METADATA_PATH, actual.getConvertedTables().get(0).getTargetMetadataPath()); } diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java index 4490f34f1..5b2d5249e 100644 --- a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java @@ -69,7 +69,12 @@ class TestConversionService { private static final String SOURCE_TABLE_BASE_PATH = "s3://bucket/tables/users"; private static final String TARGET_ICEBERG_METADATA_PATH = "s3://bucket/tables/users/metadata/v1.metadata.json"; - private static final String TARGET_SCHEMA = "{\"schema\":[]}"; + private static final String TARGET_SCHEMA = "{\n" + + " \"type\": \"struct\",\n" + + " \"fields\": [\n" + + " { \"id\": 1, \"name\": \"id\", \"required\": true, \"type\": \"string\" },\n" + + " ]\n" + + "}";; private final Configuration conf = new Configuration(); @Mock SparkHolder sparkHolder; From 481394dd1c98250765b977780e0aecba78b180ba Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Wed, 7 May 2025 16:29:40 -0700 Subject: [PATCH 10/15] spotless --- xtable-service/pom.xml | 17 + .../service/utils/ConversionServiceUtil.java | 18 +- .../service/TestConversionResource.java | 2 +- .../xtable/service/TestConversionService.java | 6 +- .../service/TestConversionServiceUtil.java | 290 +++++++++--------- 5 files changed, 179 insertions(+), 154 deletions(-) diff --git a/xtable-service/pom.xml b/xtable-service/pom.xml index 46b0f08c8..97a1e76a8 100644 --- a/xtable-service/pom.xml +++ b/xtable-service/pom.xml @@ -102,6 +102,23 @@ test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params + test + + + org.junit.jupiter + junit-jupiter-engine + test + + org.mockito diff --git a/xtable-service/src/main/java/org/apache/xtable/service/utils/ConversionServiceUtil.java b/xtable-service/src/main/java/org/apache/xtable/service/utils/ConversionServiceUtil.java index f7a3937dd..4351c71b4 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/utils/ConversionServiceUtil.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/utils/ConversionServiceUtil.java @@ -18,6 +18,10 @@ package org.apache.xtable.service.utils; +import static org.apache.xtable.model.storage.TableFormat.DELTA; +import static org.apache.xtable.model.storage.TableFormat.HUDI; +import static org.apache.xtable.model.storage.TableFormat.ICEBERG; + import java.io.IOException; import org.apache.commons.lang3.tuple.Pair; @@ -41,15 +45,12 @@ import org.apache.spark.sql.delta.DeltaLog; import org.apache.spark.sql.delta.Snapshot; -import jakarta.enterprise.context.ApplicationScoped; import org.apache.xtable.conversion.ConversionSourceProvider; import org.apache.xtable.delta.DeltaConversionSourceProvider; import org.apache.xtable.hudi.HudiConversionSourceProvider; import org.apache.xtable.iceberg.IcebergConversionSourceProvider; -import static org.apache.xtable.model.storage.TableFormat.DELTA; -import static org.apache.xtable.model.storage.TableFormat.HUDI; -import static org.apache.xtable.model.storage.TableFormat.ICEBERG; +import jakarta.enterprise.context.ApplicationScoped; @ApplicationScoped public class ConversionServiceUtil { @@ -101,20 +102,21 @@ public Pair getIcebergSchemaAndMetadataPath( return Pair.of(current.metadataFileLocation(), SchemaParser.toJson(current.schema())); } - public ConversionSourceProvider getConversionSourceProvider(String sourceTableFormat, Configuration hadoopConf) { + public ConversionSourceProvider getConversionSourceProvider( + String sourceTableFormat, Configuration hadoopConf) { if (sourceTableFormat.equalsIgnoreCase(HUDI)) { ConversionSourceProvider hudiConversionSourceProvider = - new HudiConversionSourceProvider(); + new HudiConversionSourceProvider(); hudiConversionSourceProvider.init(hadoopConf); return hudiConversionSourceProvider; } else if (sourceTableFormat.equalsIgnoreCase(DELTA)) { ConversionSourceProvider deltaConversionSourceProvider = - new DeltaConversionSourceProvider(); + new DeltaConversionSourceProvider(); deltaConversionSourceProvider.init(hadoopConf); return deltaConversionSourceProvider; } else if (sourceTableFormat.equalsIgnoreCase(ICEBERG)) { ConversionSourceProvider icebergConversionSourceProvider = - new IcebergConversionSourceProvider(); + new IcebergConversionSourceProvider(); icebergConversionSourceProvider.init(hadoopConf); return icebergConversionSourceProvider; } else { diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java index 75b45e5b7..5591db869 100644 --- a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionResource.java @@ -24,13 +24,13 @@ import java.util.Arrays; -import org.apache.xtable.model.storage.TableFormat; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.apache.xtable.model.storage.TableFormat; import org.apache.xtable.service.models.ConvertTableRequest; import org.apache.xtable.service.models.ConvertTableResponse; import org.apache.xtable.service.models.ConvertedTable; diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java index 5b2d5249e..f18c7b929 100644 --- a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java @@ -69,12 +69,14 @@ class TestConversionService { private static final String SOURCE_TABLE_BASE_PATH = "s3://bucket/tables/users"; private static final String TARGET_ICEBERG_METADATA_PATH = "s3://bucket/tables/users/metadata/v1.metadata.json"; - private static final String TARGET_SCHEMA = "{\n" + private static final String TARGET_SCHEMA = + "{\n" + " \"type\": \"struct\",\n" + " \"fields\": [\n" + " { \"id\": 1, \"name\": \"id\", \"required\": true, \"type\": \"string\" },\n" + " ]\n" - + "}";; + + "}"; + ; private final Configuration conf = new Configuration(); @Mock SparkHolder sparkHolder; diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionServiceUtil.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionServiceUtil.java index 0502de92b..31779ae51 100644 --- a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionServiceUtil.java +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionServiceUtil.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + package org.apache.xtable.service; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -32,45 +32,49 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; -import org.apache.hudi.common.table.timeline.HoodieActiveTimeline; -import org.apache.hudi.common.table.timeline.HoodieTimeline; -import org.apache.iceberg.BaseTable; -import org.apache.iceberg.SchemaParser; -import org.apache.iceberg.TableMetadata; -import org.apache.iceberg.TableOperations; -import org.apache.iceberg.hadoop.HadoopTables; -import org.apache.hudi.common.model.HoodieCommitMetadata; -import org.apache.hudi.common.table.HoodieTableMetaClient; -import org.apache.hudi.common.table.timeline.HoodieInstant; -import org.apache.hudi.common.util.Option; import org.apache.spark.sql.SparkSession; import org.apache.spark.sql.types.DataTypes; import org.apache.spark.sql.types.StructType; -import org.apache.spark.sql.delta.DeltaLog; -import org.apache.spark.sql.delta.Snapshot; -import org.apache.xtable.model.storage.TableFormat; -import org.apache.xtable.service.utils.ConversionServiceUtil; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.MockedConstruction; import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; + +import org.apache.hudi.common.model.HoodieCommitMetadata; +import org.apache.hudi.common.table.HoodieTableMetaClient; +import org.apache.hudi.common.table.timeline.HoodieActiveTimeline; +import org.apache.hudi.common.table.timeline.HoodieInstant; +import org.apache.hudi.common.table.timeline.HoodieTimeline; +import org.apache.hudi.common.util.Option; + +import org.apache.iceberg.BaseTable; +import org.apache.iceberg.SchemaParser; +import org.apache.iceberg.TableMetadata; +import org.apache.iceberg.TableOperations; +import org.apache.iceberg.hadoop.HadoopTables; + +import org.apache.spark.sql.delta.DeltaLog; +import org.apache.spark.sql.delta.Snapshot; +import org.apache.spark.sql.delta.actions.Metadata; + import org.apache.xtable.conversion.ConversionSourceProvider; import org.apache.xtable.delta.DeltaConversionSourceProvider; import org.apache.xtable.hudi.HudiConversionSourceProvider; import org.apache.xtable.iceberg.IcebergConversionSourceProvider; -import org.apache.spark.sql.delta.actions.Metadata; +import org.apache.xtable.model.storage.TableFormat; +import org.apache.xtable.service.utils.ConversionServiceUtil; @ExtendWith(MockitoExtension.class) class TestConversionServiceUtil { - private static final String DELTA_BASE_PATH = "/tmp/delta-table"; - private static final String DELTA_METADATA_JSON = "/_delta_log/000000000.json"; + private static final String DELTA_BASE_PATH = "/tmp/delta-table"; + private static final String DELTA_METADATA_JSON = "/_delta_log/000000000.json"; - private static final String HUDI_BASE_PATH = "/tmp/hudi-table"; - private static final String HUDI_METADATA_DIR = ".hoodie"; - private static final String HUDI_INSTANT_FILE = "20250506.commit"; - private static final String HUDI_SCHEMA = + private static final String HUDI_BASE_PATH = "/tmp/hudi-table"; + private static final String HUDI_METADATA_DIR = ".hoodie"; + private static final String HUDI_INSTANT_FILE = "20250506.commit"; + private static final String HUDI_SCHEMA = "{\n" + " \"type\": \"record\",\n" + " \"name\": \"user\",\n" @@ -80,132 +84,132 @@ class TestConversionServiceUtil { + " ]\n" + "}"; - private static final String ICEBERG_BASE_PATH = "/tmp/iceberg-table"; - private static final String ICEBERG_METADATA_JSON = "/metadata/v1.json"; - private static final String ICEBERG_SCHEMA = - "{\n" - + " \"type\": \"struct\",\n" - + " \"fields\": [\n" - + " { \"id\": 1, \"name\": \"id\", \"required\": true, \"type\": \"string\" },\n" - + " ]\n" - + "}"; - - @Mock SparkSession sparkSession; - @Mock Configuration hadoopConf; - - private final ConversionServiceUtil util = new ConversionServiceUtil(); - - @Test - void testGetDeltaSchemaAndMetadataPath() { - StructType testSchema = new StructType().add("id", DataTypes.IntegerType); - Path testPath = new Path(DELTA_BASE_PATH + DELTA_METADATA_JSON); - - try (MockedStatic deltaStatic = mockStatic(DeltaLog.class)) { - DeltaLog mockLog = mock(DeltaLog.class); - Snapshot mockSnap = mock(Snapshot.class); - Metadata mockMetadata = mock(Metadata.class); - - deltaStatic.when(() -> DeltaLog.forTable(sparkSession, DELTA_BASE_PATH)) - .thenReturn(mockLog); - when(mockLog.snapshot()).thenReturn(mockSnap); - when(mockSnap.metadata()).thenReturn(mockMetadata); - when(mockMetadata.schema()).thenReturn(testSchema); - when(mockSnap.path()).thenReturn(testPath); - - Pair result = util.getDeltaSchemaAndMetadataPath(DELTA_BASE_PATH, sparkSession); - assertEquals(testPath.toString(), result.getLeft()); - assertEquals(testSchema.json(), result.getRight()); - } - } + private static final String ICEBERG_BASE_PATH = "/tmp/iceberg-table"; + private static final String ICEBERG_METADATA_JSON = "/metadata/v1.json"; + private static final String ICEBERG_SCHEMA = + "{\n" + + " \"type\": \"struct\",\n" + + " \"fields\": [\n" + + " { \"id\": 1, \"name\": \"id\", \"required\": true, \"type\": \"string\" },\n" + + " ]\n" + + "}"; - @Test - void testGetHudiSchemaAndMetadataPath() { - try (MockedStatic clientStatic = mockStatic(HoodieTableMetaClient.class); - MockedStatic commitStatic = mockStatic(HoodieCommitMetadata.class)) { - - HoodieTableMetaClient.Builder builder = mock(HoodieTableMetaClient.Builder.class); - HoodieTableMetaClient metaClient = mock(HoodieTableMetaClient.class); - - clientStatic.when(HoodieTableMetaClient::builder).thenReturn(builder); - when(builder.setBasePath(HUDI_BASE_PATH)).thenReturn(builder); - when(builder.setConf(hadoopConf)).thenReturn(builder); - when(builder.build()).thenReturn(metaClient); - - HoodieActiveTimeline activeTimeline = mock(HoodieActiveTimeline.class); - HoodieTimeline commitsTimeline = mock(HoodieTimeline.class); - HoodieInstant instant = mock(HoodieInstant.class); - - when(metaClient.getActiveTimeline()).thenReturn(activeTimeline); - when(activeTimeline.getCommitsTimeline()).thenReturn(commitsTimeline); - when(commitsTimeline.filterCompletedInstants()).thenReturn(commitsTimeline); - when(commitsTimeline.empty()).thenReturn(false); - when(commitsTimeline.lastInstant()).thenReturn(Option.of(instant)); - - when(metaClient.getMetaPath()).thenReturn(HUDI_METADATA_DIR); - when(instant.getFileName()).thenReturn(HUDI_INSTANT_FILE); - - byte[] rawBytes = "data".getBytes(StandardCharsets.UTF_8); - Option rawOption = Option.of(rawBytes); - when(activeTimeline.getInstantDetails(instant)).thenReturn(rawOption); - - HoodieCommitMetadata commitMetadata = mock(HoodieCommitMetadata.class); - commitStatic.when(() -> HoodieCommitMetadata.fromBytes(rawBytes, HoodieCommitMetadata.class)) - .thenReturn(commitMetadata); - when(commitMetadata.getMetadata(HoodieCommitMetadata.SCHEMA_KEY)) - .thenReturn(HUDI_SCHEMA); - - Pair result = - util.getHudiSchemaAndMetadataPath(HUDI_BASE_PATH, hadoopConf); - - assertEquals(HUDI_BASE_PATH + "/" + HUDI_METADATA_DIR + "/" + HUDI_INSTANT_FILE, - result.getLeft()); - assertEquals(HUDI_SCHEMA, - result.getRight()); - } - } + @Mock SparkSession sparkSession; + @Mock Configuration hadoopConf; + + private final ConversionServiceUtil util = new ConversionServiceUtil(); - @Test - void testGetIcebergSchemaAndMetadataPath() { - try (MockedConstruction tablesCons = - mockConstruction(HadoopTables.class, - (mockTables, ctx) -> { - BaseTable mockTable = mock(BaseTable.class); - TableOperations ops = mock(TableOperations.class); - TableMetadata meta = mock(TableMetadata.class); - - when(mockTables.load(ICEBERG_BASE_PATH)).thenReturn(mockTable); - when(mockTable.operations()).thenReturn(ops); - when(ops.current()).thenReturn(meta); - when(meta.metadataFileLocation()).thenReturn(ICEBERG_BASE_PATH + ICEBERG_METADATA_JSON); - }); - MockedStatic parserStatic = - mockStatic(SchemaParser.class)) { - parserStatic.when(() -> SchemaParser.toJson(any())) - .thenReturn(ICEBERG_SCHEMA); - - Pair result = - util.getIcebergSchemaAndMetadataPath(ICEBERG_BASE_PATH, hadoopConf); - - assertEquals(ICEBERG_BASE_PATH + ICEBERG_METADATA_JSON, result.getLeft()); - assertEquals(ICEBERG_SCHEMA, result.getRight()); - } + @Test + void testGetDeltaSchemaAndMetadataPath() { + StructType testSchema = new StructType().add("id", DataTypes.IntegerType); + Path testPath = new Path(DELTA_BASE_PATH + DELTA_METADATA_JSON); + + try (MockedStatic deltaStatic = mockStatic(DeltaLog.class)) { + DeltaLog mockLog = mock(DeltaLog.class); + Snapshot mockSnap = mock(Snapshot.class); + Metadata mockMetadata = mock(Metadata.class); + + deltaStatic.when(() -> DeltaLog.forTable(sparkSession, DELTA_BASE_PATH)).thenReturn(mockLog); + when(mockLog.snapshot()).thenReturn(mockSnap); + when(mockSnap.metadata()).thenReturn(mockMetadata); + when(mockMetadata.schema()).thenReturn(testSchema); + when(mockSnap.path()).thenReturn(testPath); + + Pair result = + util.getDeltaSchemaAndMetadataPath(DELTA_BASE_PATH, sparkSession); + assertEquals(testPath.toString(), result.getLeft()); + assertEquals(testSchema.json(), result.getRight()); } + } + + @Test + void testGetHudiSchemaAndMetadataPath() { + try (MockedStatic clientStatic = + mockStatic(HoodieTableMetaClient.class); + MockedStatic commitStatic = mockStatic(HoodieCommitMetadata.class)) { + + HoodieTableMetaClient.Builder builder = mock(HoodieTableMetaClient.Builder.class); + HoodieTableMetaClient metaClient = mock(HoodieTableMetaClient.class); + + clientStatic.when(HoodieTableMetaClient::builder).thenReturn(builder); + when(builder.setBasePath(HUDI_BASE_PATH)).thenReturn(builder); + when(builder.setConf(hadoopConf)).thenReturn(builder); + when(builder.build()).thenReturn(metaClient); + + HoodieActiveTimeline activeTimeline = mock(HoodieActiveTimeline.class); + HoodieTimeline commitsTimeline = mock(HoodieTimeline.class); + HoodieInstant instant = mock(HoodieInstant.class); + + when(metaClient.getActiveTimeline()).thenReturn(activeTimeline); + when(activeTimeline.getCommitsTimeline()).thenReturn(commitsTimeline); + when(commitsTimeline.filterCompletedInstants()).thenReturn(commitsTimeline); + when(commitsTimeline.empty()).thenReturn(false); + when(commitsTimeline.lastInstant()).thenReturn(Option.of(instant)); + + when(metaClient.getMetaPath()).thenReturn(HUDI_METADATA_DIR); + when(instant.getFileName()).thenReturn(HUDI_INSTANT_FILE); + + byte[] rawBytes = "data".getBytes(StandardCharsets.UTF_8); + Option rawOption = Option.of(rawBytes); + when(activeTimeline.getInstantDetails(instant)).thenReturn(rawOption); + + HoodieCommitMetadata commitMetadata = mock(HoodieCommitMetadata.class); + commitStatic + .when(() -> HoodieCommitMetadata.fromBytes(rawBytes, HoodieCommitMetadata.class)) + .thenReturn(commitMetadata); + when(commitMetadata.getMetadata(HoodieCommitMetadata.SCHEMA_KEY)).thenReturn(HUDI_SCHEMA); + + Pair result = util.getHudiSchemaAndMetadataPath(HUDI_BASE_PATH, hadoopConf); + + assertEquals( + HUDI_BASE_PATH + "/" + HUDI_METADATA_DIR + "/" + HUDI_INSTANT_FILE, result.getLeft()); + assertEquals(HUDI_SCHEMA, result.getRight()); + } + } + + @Test + void testGetIcebergSchemaAndMetadataPath() { + try (MockedConstruction tablesCons = + mockConstruction( + HadoopTables.class, + (mockTables, ctx) -> { + BaseTable mockTable = mock(BaseTable.class); + TableOperations ops = mock(TableOperations.class); + TableMetadata meta = mock(TableMetadata.class); + + when(mockTables.load(ICEBERG_BASE_PATH)).thenReturn(mockTable); + when(mockTable.operations()).thenReturn(ops); + when(ops.current()).thenReturn(meta); + when(meta.metadataFileLocation()) + .thenReturn(ICEBERG_BASE_PATH + ICEBERG_METADATA_JSON); + }); + MockedStatic parserStatic = mockStatic(SchemaParser.class)) { + parserStatic.when(() -> SchemaParser.toJson(any())).thenReturn(ICEBERG_SCHEMA); + + Pair result = + util.getIcebergSchemaAndMetadataPath(ICEBERG_BASE_PATH, hadoopConf); + + assertEquals(ICEBERG_BASE_PATH + ICEBERG_METADATA_JSON, result.getLeft()); + assertEquals(ICEBERG_SCHEMA, result.getRight()); + } + } - @Test - void testGetConversionSourceProvider() { + @Test + void testGetConversionSourceProvider() { ConversionSourceProvider hudiProvider = util.getConversionSourceProvider(TableFormat.HUDI, hadoopConf); - assertTrue(hudiProvider instanceof HudiConversionSourceProvider); + assertTrue(hudiProvider instanceof HudiConversionSourceProvider); - ConversionSourceProvider deltaProvider = - util.getConversionSourceProvider(TableFormat.DELTA, hadoopConf); - assertTrue(deltaProvider instanceof DeltaConversionSourceProvider); + ConversionSourceProvider deltaProvider = + util.getConversionSourceProvider(TableFormat.DELTA, hadoopConf); + assertTrue(deltaProvider instanceof DeltaConversionSourceProvider); - ConversionSourceProvider icebergProvider = - util.getConversionSourceProvider(TableFormat.ICEBERG, hadoopConf); - assertTrue(icebergProvider instanceof IcebergConversionSourceProvider); + ConversionSourceProvider icebergProvider = + util.getConversionSourceProvider(TableFormat.ICEBERG, hadoopConf); + assertTrue(icebergProvider instanceof IcebergConversionSourceProvider); - assertThrows(IllegalArgumentException.class, - () -> util.getConversionSourceProvider("SomeFormat", hadoopConf)); - } -} \ No newline at end of file + assertThrows( + IllegalArgumentException.class, + () -> util.getConversionSourceProvider("SomeFormat", hadoopConf)); + } +} From 859e9308f98b677e34b5367e56554ec4f77a3bb0 Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Wed, 7 May 2025 16:58:08 -0700 Subject: [PATCH 11/15] fix dependency conflict to make unit tests run in ci --- pom.xml | 3 ++- xtable-service/pom.xml | 12 ++++++++++++ .../apache/xtable/service/TestConversionService.java | 12 ------------ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index f4655f68d..971e0cb90 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,7 @@ 1.11.4 2.22.0 5.11.4 + 1.11.4 1.18.36 1.18.20.0 3.4.1 @@ -489,7 +490,7 @@ org.junit.platform junit-platform-runner - 1.11.4 + ${junit.platform.runner.version} test diff --git a/xtable-service/pom.xml b/xtable-service/pom.xml index 97a1e76a8..12dff680a 100644 --- a/xtable-service/pom.xml +++ b/xtable-service/pom.xml @@ -118,6 +118,18 @@ junit-jupiter-engine test + + org.junit.platform + junit-platform-commons + ${junit.platform.runner.version} + test + + + org.junit.platform + junit-platform-engine + ${junit.platform.runner.version} + test + diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java index f18c7b929..3158d07ae 100644 --- a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java @@ -109,16 +109,4 @@ void serviceConvertTableWithDeltaSourceAndTargetIceberg() { assertEquals(TARGET_ICEBERG_METADATA_PATH, restTargetTable.getTargetMetadataPath()); assertEquals(TARGET_SCHEMA, restTargetTable.getTargetSchema()); } - - @Test - void serviceConvertTableWithInvalidFormats() { - ConvertTableRequest invalidRequest = - ConvertTableRequest.builder() - .sourceFormat("notRealSoureFormat") - .sourceTableName(SOURCE_TABLE_NAME) - .sourceTablePath(SOURCE_TABLE_BASE_PATH) - .targetFormats(Collections.singletonList("notRealTargetFormat")) - .build(); - assertThrows(IllegalArgumentException.class, () -> service.convertTable(invalidRequest)); - } } From f98f5690b3b90d7d082a80f369d588cbe56614b4 Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Wed, 7 May 2025 17:24:28 -0700 Subject: [PATCH 12/15] minor mvn fix --- pom.xml | 2 +- .../java/org/apache/xtable/service/TestConversionService.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 971e0cb90..bed4d63b4 100644 --- a/pom.xml +++ b/pom.xml @@ -102,7 +102,7 @@ quarkus-bom io.quarkus.platform 3.2.12.Final - 4.9.3 + 4.9.3 0.16 diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java index 3158d07ae..a634c5d13 100644 --- a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java @@ -37,7 +37,6 @@ */ import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; From 8871dc05487fd70fa9be9b103f9ca6505454dd13 Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Fri, 9 May 2025 01:20:46 -0700 Subject: [PATCH 13/15] Address Vinish remaining comments --- .../xtable/conversion/ConversionUtils.java | 34 +++ .../xtable/service/ConversionService.java | 138 ++++++---- .../xtable/service/spark/SparkBootstrap.java | 37 --- .../xtable/service/spark/SparkHolder.java | 114 --------- .../service/utils/ConversionServiceUtil.java | 126 --------- .../xtable/service/TestConversionService.java | 240 +++++++++++++----- .../service/TestConversionServiceUtil.java | 215 ---------------- 7 files changed, 304 insertions(+), 600 deletions(-) delete mode 100644 xtable-service/src/main/java/org/apache/xtable/service/spark/SparkBootstrap.java delete mode 100644 xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java delete mode 100644 xtable-service/src/main/java/org/apache/xtable/service/utils/ConversionServiceUtil.java delete mode 100644 xtable-service/src/test/java/org/apache/xtable/service/TestConversionServiceUtil.java diff --git a/xtable-core/src/main/java/org/apache/xtable/conversion/ConversionUtils.java b/xtable-core/src/main/java/org/apache/xtable/conversion/ConversionUtils.java index f21be6702..f6d366e57 100644 --- a/xtable-core/src/main/java/org/apache/xtable/conversion/ConversionUtils.java +++ b/xtable-core/src/main/java/org/apache/xtable/conversion/ConversionUtils.java @@ -18,6 +18,18 @@ package org.apache.xtable.conversion; +import static org.apache.xtable.model.storage.TableFormat.DELTA; +import static org.apache.xtable.model.storage.TableFormat.HUDI; +import static org.apache.xtable.model.storage.TableFormat.ICEBERG; + +import org.apache.hadoop.conf.Configuration; + +import org.apache.hudi.common.table.timeline.HoodieInstant; + +import org.apache.xtable.delta.DeltaConversionSourceProvider; +import org.apache.xtable.hudi.HudiConversionSourceProvider; +import org.apache.xtable.iceberg.IcebergConversionSourceProvider; + public class ConversionUtils { public static SourceTable convertToSourceTable(TargetTable table) { @@ -30,4 +42,26 @@ public static SourceTable convertToSourceTable(TargetTable table) { table.getCatalogConfig(), table.getAdditionalProperties()); } + + public static ConversionSourceProvider getConversionSourceProvider( + String sourceTableFormat, Configuration hadoopConf) { + if (sourceTableFormat.equalsIgnoreCase(HUDI)) { + ConversionSourceProvider hudiConversionSourceProvider = + new HudiConversionSourceProvider(); + hudiConversionSourceProvider.init(hadoopConf); + return hudiConversionSourceProvider; + } else if (sourceTableFormat.equalsIgnoreCase(DELTA)) { + ConversionSourceProvider deltaConversionSourceProvider = + new DeltaConversionSourceProvider(); + deltaConversionSourceProvider.init(hadoopConf); + return deltaConversionSourceProvider; + } else if (sourceTableFormat.equalsIgnoreCase(ICEBERG)) { + ConversionSourceProvider icebergConversionSourceProvider = + new IcebergConversionSourceProvider(); + icebergConversionSourceProvider.init(hadoopConf); + return icebergConversionSourceProvider; + } else { + throw new IllegalArgumentException("Unsupported source format: " + sourceTableFormat); + } + } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java index 158aaedcc..d14f7abca 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java @@ -18,27 +18,32 @@ package org.apache.xtable.service; -import static org.apache.xtable.model.storage.TableFormat.DELTA; -import static org.apache.xtable.model.storage.TableFormat.HUDI; -import static org.apache.xtable.model.storage.TableFormat.ICEBERG; +import static org.apache.xtable.conversion.ConversionUtils.convertToSourceTable; import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang3.tuple.Pair; +import lombok.extern.log4j.Log4j2; + +import org.apache.hadoop.conf.Configuration; + +import org.apache.iceberg.SchemaParser; import com.google.common.annotations.VisibleForTesting; +import org.apache.xtable.avro.AvroSchemaConverter; import org.apache.xtable.conversion.ConversionConfig; import org.apache.xtable.conversion.ConversionController; -import org.apache.xtable.conversion.ConversionSourceProvider; +import org.apache.xtable.conversion.ConversionUtils; import org.apache.xtable.conversion.SourceTable; import org.apache.xtable.conversion.TargetTable; +import org.apache.xtable.iceberg.IcebergSchemaExtractor; +import org.apache.xtable.model.InternalTable; +import org.apache.xtable.model.storage.TableFormat; +import org.apache.xtable.schema.SparkSchemaExtractor; import org.apache.xtable.service.models.ConvertTableRequest; import org.apache.xtable.service.models.ConvertTableResponse; import org.apache.xtable.service.models.ConvertedTable; -import org.apache.xtable.service.spark.SparkHolder; -import org.apache.xtable.service.utils.ConversionServiceUtil; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -50,40 +55,61 @@ * a source table, generating target tables, and then executing the conversion via a designated * conversion controller. */ +@Log4j2 @ApplicationScoped public class ConversionService { - private final SparkHolder sparkHolder; private final ConversionController conversionController; - private final ConversionServiceUtil conversionServiceUtil; + private final ConversionServiceConfig serviceConfig; + private final Configuration hadoopConf; /** * Constructs a ConversionService instance with required dependencies. * - * @param sparkHolder the Spark holder instance containing the Spark context and configuration - * @param conversionServiceUtil utility for handling metadata operations + * @param serviceConfig the conversion service configuration */ @Inject - public ConversionService(SparkHolder sparkHolder, ConversionServiceUtil conversionServiceUtil) { - this.sparkHolder = sparkHolder; - this.conversionServiceUtil = conversionServiceUtil; - this.conversionController = new ConversionController(sparkHolder.jsc().hadoopConfiguration()); + public ConversionService(ConversionServiceConfig serviceConfig) { + this.serviceConfig = serviceConfig; + this.hadoopConf = getHadoopConf(); + this.conversionController = new ConversionController(hadoopConf); + } + + private Configuration getHadoopConf() { + Configuration conf = new Configuration(); + String hadoopConfigPath = serviceConfig.getHadoopConfigPath(); + try { + // Load configuration from the specified XML file + conf.addResource(hadoopConfigPath); + + // If the resource wasn’t found, log a warning + if (conf.size() == 0) { + log.warn( + "Could not load Hadoop configuration from: {}. Using default Hadoop configuration.", + hadoopConfigPath); + } + } catch (Exception e) { + log.error( + "Error loading Hadoop configuration from: {}. Exception: {}", + hadoopConfigPath, + e.getMessage(), + e); + } + return conf; } /** * Constructs a ConversionService instance using dependency injection for testing. * - * @param sparkHolder the Spark holder instance * @param conversionController a preconfigured conversion controller - * @param conversionServiceUtil utility for handling metadata operations */ @VisibleForTesting public ConversionService( - SparkHolder sparkHolder, - ConversionServiceUtil conversionServiceUtil, - ConversionController conversionController) { - this.sparkHolder = sparkHolder; + ConversionServiceConfig serviceConfig, + ConversionController conversionController, + Configuration hadoopConf) { + this.serviceConfig = serviceConfig; this.conversionController = conversionController; - this.conversionServiceUtil = conversionServiceUtil; + this.hadoopConf = hadoopConf; } /** @@ -120,37 +146,47 @@ public ConvertTableResponse convertTable(ConvertTableRequest convertTableRequest ConversionConfig conversionConfig = ConversionConfig.builder().sourceTable(sourceTable).targetTables(targetTables).build(); - ConversionSourceProvider conversionSourceProvider = - conversionServiceUtil.getConversionSourceProvider( - convertTableRequest.getSourceFormat(), sparkHolder.jsc().hadoopConfiguration()); + conversionController.sync( + conversionConfig, + ConversionUtils.getConversionSourceProvider( + convertTableRequest.getSourceFormat(), hadoopConf)); - conversionController.sync(conversionConfig, conversionSourceProvider); - - List restTargetTables = new ArrayList<>(); - for (String targetFormat : convertTableRequest.getTargetFormats()) { - if (targetFormat.equals(ICEBERG)) { - Pair responseFields = - conversionServiceUtil.getIcebergSchemaAndMetadataPath( - convertTableRequest.getSourceTablePath(), sparkHolder.jsc().hadoopConfiguration()); - ConvertedTable icebergTable = - new ConvertedTable(ICEBERG, responseFields.getLeft(), responseFields.getRight()); - restTargetTables.add(icebergTable); - } else if (targetFormat.equals(HUDI)) { - Pair responseFields = - conversionServiceUtil.getHudiSchemaAndMetadataPath( - convertTableRequest.getSourceTablePath(), sparkHolder.jsc().hadoopConfiguration()); - ConvertedTable hudiTable = - new ConvertedTable(HUDI, responseFields.getLeft(), responseFields.getRight()); - restTargetTables.add(hudiTable); - } else if (targetFormat.equals(DELTA)) { - Pair responseFields = - conversionServiceUtil.getDeltaSchemaAndMetadataPath( - convertTableRequest.getSourceTablePath(), sparkHolder.spark()); - ConvertedTable deltaTable = - new ConvertedTable(DELTA, responseFields.getLeft(), responseFields.getRight()); - restTargetTables.add(deltaTable); + List convertedTables = new ArrayList<>(); + for (TargetTable targetTable : targetTables) { + InternalTable internalTable = + ConversionUtils.getConversionSourceProvider(targetTable.getFormatName(), hadoopConf) + .getConversionSourceInstance(convertToSourceTable(targetTable)) + .getCurrentTable(); + String schemaString; + switch (targetTable.getFormatName()) { + case TableFormat.HUDI: + schemaString = + AvroSchemaConverter.getInstance() + .fromInternalSchema(internalTable.getReadSchema()) + .toString(); + break; + case TableFormat.ICEBERG: + org.apache.iceberg.Schema iceSchema = + IcebergSchemaExtractor.getInstance().toIceberg(internalTable.getReadSchema()); + schemaString = SchemaParser.toJson(iceSchema); + break; + case TableFormat.DELTA: + schemaString = + SparkSchemaExtractor.getInstance() + .fromInternalSchema(internalTable.getReadSchema()) + .json(); + break; + default: + throw new UnsupportedOperationException( + "Unsupported table format: " + targetTable.getFormatName()); } + convertedTables.add( + ConvertedTable.builder() + .targetFormat(internalTable.getName()) + .targetSchema(schemaString) + .targetMetadataPath(internalTable.getLatestMetdataPath()) + .build()); } - return new ConvertTableResponse(restTargetTables); + return new ConvertTableResponse(convertedTables); } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkBootstrap.java b/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkBootstrap.java deleted file mode 100644 index 84a2e776e..000000000 --- a/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkBootstrap.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.xtable.service.spark; - -import org.eclipse.microprofile.context.ManagedExecutor; - -import io.quarkus.runtime.StartupEvent; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.event.Observes; -import jakarta.inject.Inject; - -@ApplicationScoped -public class SparkBootstrap { - @Inject ManagedExecutor executor; - @Inject SparkHolder holder; - - void onStart(@Observes StartupEvent ev) { - // Quarkus has already bound port 8080 by the time this runs. - executor.execute(holder::spark); - } -} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java b/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java deleted file mode 100644 index 627de7d91..000000000 --- a/xtable-service/src/main/java/org/apache/xtable/service/spark/SparkHolder.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.xtable.service.spark; - -import static org.apache.xtable.service.ConversionServiceConfig.HADOOP_DEFAULTS_XML; - -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Paths; - -import org.apache.spark.SparkConf; -import org.apache.spark.api.java.JavaSparkContext; -import org.apache.spark.serializer.KryoSerializer; -import org.apache.spark.sql.SparkSession; - -import org.apache.xtable.service.ConversionServiceConfig; - -import io.quarkus.runtime.ShutdownEvent; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.event.Observes; -import jakarta.inject.Inject; - -@ApplicationScoped -public class SparkHolder { - - private volatile SparkSession spark; - private volatile JavaSparkContext jsc; - - @Inject private ConversionServiceConfig conversionServiceConfig; - - public SparkSession spark() { - if (spark == null) { - synchronized (this) { - if (spark == null) { - spark = - SparkSession.builder() - .config(getSparkConf()) - .appName("xtable-conversion-service") - .getOrCreate(); - jsc = JavaSparkContext.fromSparkContext(spark.sparkContext()); - - // Load user-provided Hadoop XML file if available, otherwise load the default - try (InputStream configStream = - !conversionServiceConfig.getHadoopConfigPath().equals(HADOOP_DEFAULTS_XML) - ? Files.newInputStream(Paths.get(conversionServiceConfig.getHadoopConfigPath())) - : SparkHolder.class.getClassLoader().getResourceAsStream(HADOOP_DEFAULTS_XML)) { - if (configStream != null) { - spark.sparkContext().hadoopConfiguration().addResource(configStream); - } else { - throw new RuntimeException("Failed to load Hadoop configuration file"); - } - } catch (Exception e) { - throw new RuntimeException("Error loading Hadoop configuration file", e); - } - } - } - } - return spark; - } - - public JavaSparkContext jsc() { - // ensure spark() has run - spark(); - return jsc; - } - - // cleanly stop Spark when Quarkus shuts down - void onShutdown(@Observes ShutdownEvent ev) { - if (spark != null) { - spark.stop(); - } - } - - public SparkConf getSparkConf() { - return new SparkConf() - .setMaster("local[4]") - .setAppName("xtable-service") - .set("spark.ui.enabled", "false") // disable Spark UI - .set("spark.driver.bindAddress", "127.0.0.1") - .set("spark.serializer", KryoSerializer.class.getName()) - .set("spark.sql.catalog.default_iceberg", "org.apache.iceberg.spark.SparkCatalog") - .set("spark.sql.catalog.default_iceberg.type", "hadoop") - .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer") - .set("parquet.avro.write-old-list-structure", "false") - // Needed for ignoring not nullable constraints on nested columns in Delta. - .set("spark.databricks.delta.constraints.allowUnenforcedNotNull.enabled", "true") - .set("spark.sql.shuffle.partitions", "1") - .set("spark.default.parallelism", "1") - .set("spark.sql.session.timeZone", "UTC") - .set("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") - .set("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog") - .set("spark.databricks.delta.retentionDurationCheck.enabled", "false") - .set("spark.databricks.delta.schema.autoMerge.enabled", "true"); - // .set("spark.sql.catalog.default_iceberg.warehouse", tempDir.toString()) add this back for - // iceberg - // .set("spark.sql.hive.convertMetastoreParquet", "false"); add this back for hudi - } -} diff --git a/xtable-service/src/main/java/org/apache/xtable/service/utils/ConversionServiceUtil.java b/xtable-service/src/main/java/org/apache/xtable/service/utils/ConversionServiceUtil.java deleted file mode 100644 index 4351c71b4..000000000 --- a/xtable-service/src/main/java/org/apache/xtable/service/utils/ConversionServiceUtil.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.xtable.service.utils; - -import static org.apache.xtable.model.storage.TableFormat.DELTA; -import static org.apache.xtable.model.storage.TableFormat.HUDI; -import static org.apache.xtable.model.storage.TableFormat.ICEBERG; - -import java.io.IOException; - -import org.apache.commons.lang3.tuple.Pair; -import org.apache.hadoop.conf.Configuration; -import org.apache.spark.sql.SparkSession; -import org.apache.spark.sql.types.StructType; - -import org.apache.hudi.common.model.HoodieCommitMetadata; -import org.apache.hudi.common.table.HoodieTableMetaClient; -import org.apache.hudi.common.table.timeline.HoodieInstant; -import org.apache.hudi.common.table.timeline.HoodieTimeline; -import org.apache.hudi.common.util.Option; - -import org.apache.iceberg.BaseTable; -import org.apache.iceberg.SchemaParser; -import org.apache.iceberg.Table; -import org.apache.iceberg.TableMetadata; -import org.apache.iceberg.TableOperations; -import org.apache.iceberg.hadoop.HadoopTables; - -import org.apache.spark.sql.delta.DeltaLog; -import org.apache.spark.sql.delta.Snapshot; - -import org.apache.xtable.conversion.ConversionSourceProvider; -import org.apache.xtable.delta.DeltaConversionSourceProvider; -import org.apache.xtable.hudi.HudiConversionSourceProvider; -import org.apache.xtable.iceberg.IcebergConversionSourceProvider; - -import jakarta.enterprise.context.ApplicationScoped; - -@ApplicationScoped -public class ConversionServiceUtil { - - public Pair getDeltaSchemaAndMetadataPath( - String basePath, SparkSession sparkSession) { - DeltaLog deltaLog = DeltaLog.forTable(sparkSession, basePath); - Snapshot snapshot = deltaLog.snapshot(); - StructType schema = snapshot.metadata().schema(); - String metadataPath = snapshot.path().toString(); - String schemaStr = schema.json(); - return Pair.of(metadataPath, schemaStr); - } - - public Pair getHudiSchemaAndMetadataPath( - String basePath, Configuration hadoopConf) { - HoodieTableMetaClient metaClient = - HoodieTableMetaClient.builder().setBasePath(basePath).setConf(hadoopConf).build(); - HoodieTimeline commits = - metaClient.getActiveTimeline().getCommitsTimeline().filterCompletedInstants(); - if (commits.empty()) { - throw new IllegalStateException("No completed commits found in " + basePath); - } - HoodieInstant lastInstant = commits.lastInstant().get(); - String metaDir = metaClient.getMetaPath(); - String fileName = lastInstant.getFileName(); - String hudiLatestCommitPath = String.join("/", basePath, metaDir, fileName); - - Option raw = metaClient.getActiveTimeline().getInstantDetails(lastInstant); - HoodieCommitMetadata commitMetadata; - try { - commitMetadata = HoodieCommitMetadata.fromBytes(raw.get(), HoodieCommitMetadata.class); - } catch (IOException e) { - throw new RuntimeException(e); - } - String hudiSchemaStr = commitMetadata.getMetadata(HoodieCommitMetadata.SCHEMA_KEY); - if (hudiSchemaStr == null) { - throw new IllegalStateException("Commit " + lastInstant + " does not contain a schema"); - } - return Pair.of(hudiLatestCommitPath, hudiSchemaStr); - } - - public Pair getIcebergSchemaAndMetadataPath( - String tableLocation, Configuration conf) { - HadoopTables tables = new HadoopTables(conf); - Table table = tables.load(tableLocation); - TableOperations ops = ((BaseTable) table).operations(); - TableMetadata current = ops.current(); - return Pair.of(current.metadataFileLocation(), SchemaParser.toJson(current.schema())); - } - - public ConversionSourceProvider getConversionSourceProvider( - String sourceTableFormat, Configuration hadoopConf) { - if (sourceTableFormat.equalsIgnoreCase(HUDI)) { - ConversionSourceProvider hudiConversionSourceProvider = - new HudiConversionSourceProvider(); - hudiConversionSourceProvider.init(hadoopConf); - return hudiConversionSourceProvider; - } else if (sourceTableFormat.equalsIgnoreCase(DELTA)) { - ConversionSourceProvider deltaConversionSourceProvider = - new DeltaConversionSourceProvider(); - deltaConversionSourceProvider.init(hadoopConf); - return deltaConversionSourceProvider; - } else if (sourceTableFormat.equalsIgnoreCase(ICEBERG)) { - ConversionSourceProvider icebergConversionSourceProvider = - new IcebergConversionSourceProvider(); - icebergConversionSourceProvider.init(hadoopConf); - return icebergConversionSourceProvider; - } else { - throw new IllegalArgumentException("Unsupported source format: " + sourceTableFormat); - } - } -} diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java index a634c5d13..a30c2205f 100644 --- a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java @@ -18,94 +18,220 @@ package org.apache.xtable.service; -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; import java.util.Collections; -import org.apache.commons.lang3.tuple.Pair; +import org.apache.avro.Schema; import org.apache.hadoop.conf.Configuration; -import org.apache.spark.api.java.JavaSparkContext; +import org.apache.spark.sql.types.StructType; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; +import org.apache.iceberg.SchemaParser; + +import org.apache.xtable.avro.AvroSchemaConverter; import org.apache.xtable.conversion.ConversionConfig; import org.apache.xtable.conversion.ConversionController; +import org.apache.xtable.conversion.ConversionSourceProvider; +import org.apache.xtable.conversion.ConversionUtils; +import org.apache.xtable.iceberg.IcebergSchemaExtractor; +import org.apache.xtable.model.InternalTable; +import org.apache.xtable.model.schema.InternalSchema; +import org.apache.xtable.model.storage.TableFormat; +import org.apache.xtable.schema.SparkSchemaExtractor; import org.apache.xtable.service.models.ConvertTableRequest; import org.apache.xtable.service.models.ConvertTableResponse; import org.apache.xtable.service.models.ConvertedTable; -import org.apache.xtable.service.spark.SparkHolder; -import org.apache.xtable.service.utils.ConversionServiceUtil; +import org.apache.xtable.spi.extractor.ConversionSource; @ExtendWith(MockitoExtension.class) class TestConversionService { - - private static final String SOURCE_TABLE_NAME = "users"; - private static final String SOURCE_TABLE_BASE_PATH = "s3://bucket/tables/users"; - private static final String TARGET_ICEBERG_METADATA_PATH = + private static final String SOURCE_NAME = "users"; + private static final String SOURCE_PATH = "s3://bucket/tables/users"; + private static final String HUDI_META_PATH = "s3://bucket/tables/users/.hoodie"; + private static final String ICEBERG_META_PATH = "s3://bucket/tables/users/metadata/v1.metadata.json"; - private static final String TARGET_SCHEMA = + private static final String DELTA_META_PATH = "s3://bucket/tables/users/delta_log"; + + private static final String HUDI_SCHEMA_JSON = "{\n" - + " \"type\": \"struct\",\n" - + " \"fields\": [\n" - + " { \"id\": 1, \"name\": \"id\", \"required\": true, \"type\": \"string\" },\n" - + " ]\n" + + " \"type\":\"record\",\n" + + " \"name\":\"Users\",\n" + + " \"fields\":[{\"name\":\"id\",\"type\":\"string\"}]\n" + "}"; - ; - private final Configuration conf = new Configuration(); - @Mock SparkHolder sparkHolder; - @Mock ConversionServiceUtil conversionServiceUtil; - @Mock ConversionController controller; - @Mock JavaSparkContext jsc; + private static final String ICEBERG_JSON = + "{\"type\":\"record\",\"name\":\"Users\"," + + "\"fields\":[{\"name\":\"id\",\"type\":\"string\",\"field-id\":1}]}"; + + private static final String DELTA_JSON = + "{\"type\":\"struct\",\"fields\":[" + + "{\"name\":\"id\",\"type\":\"string\",\"nullable\":false,\"metadata\":{}}]}"; + + @Mock private ConversionServiceConfig serviceConfig; + + @Mock private ConversionController controller; - @InjectMocks ConversionService service; + @Mock ConversionSourceProvider provider; + + @Mock ConversionSource conversionSrc; + + @Mock InternalTable internalTbl; + + @Mock InternalSchema internalSchema; + + private ConversionService service; + private Configuration conf; + + @BeforeEach + void setUp() { + this.conf = new Configuration(); + this.service = new ConversionService(serviceConfig, controller, this.conf); + } @Test - void serviceConvertTableWithDeltaSourceAndTargetIceberg() { - when(sparkHolder.jsc()).thenReturn(jsc); - when(jsc.hadoopConfiguration()).thenReturn(conf); - when(conversionServiceUtil.getIcebergSchemaAndMetadataPath(SOURCE_TABLE_BASE_PATH, conf)) - .thenReturn(Pair.of(TARGET_ICEBERG_METADATA_PATH, TARGET_SCHEMA)); + void convertToTargetHudi() { + // build request + ConvertTableRequest req = + ConvertTableRequest.builder() + .sourceFormat(TableFormat.DELTA) + .sourceTableName(SOURCE_NAME) + .sourceTablePath(SOURCE_PATH) + .targetFormats(Collections.singletonList(TableFormat.HUDI)) + .build(); + + Schema avroSchema = new Schema.Parser().parse(HUDI_SCHEMA_JSON); + try (MockedStatic utils = mockStatic(ConversionUtils.class); + MockedStatic avroConv = mockStatic(AvroSchemaConverter.class)) { + + utils + .when(() -> ConversionUtils.getConversionSourceProvider(TableFormat.DELTA, conf)) + .thenReturn(provider); + utils + .when(() -> ConversionUtils.getConversionSourceProvider(TableFormat.HUDI, conf)) + .thenReturn(provider); + + when(controller.sync(any(ConversionConfig.class), eq(provider))).thenReturn(null); + when(provider.getConversionSourceInstance(any())).thenReturn(conversionSrc); + when(conversionSrc.getCurrentTable()).thenReturn(internalTbl); + + when(internalTbl.getName()).thenReturn(TableFormat.HUDI); + when(internalTbl.getLatestMetdataPath()).thenReturn(HUDI_META_PATH); + when(internalTbl.getReadSchema()).thenReturn(internalSchema); + + AvroSchemaConverter converter = mock(AvroSchemaConverter.class); + avroConv.when(AvroSchemaConverter::getInstance).thenReturn(converter); + when(converter.fromInternalSchema(internalSchema)).thenReturn(avroSchema); + + ConvertTableResponse resp = service.convertTable(req); + + // verify & assert + verify(controller, times(1)).sync(any(ConversionConfig.class), eq(provider)); + assertEquals(1, resp.getConvertedTables().size()); + ConvertedTable ct = resp.getConvertedTables().get(0); + assertEquals(TableFormat.HUDI, ct.getTargetFormat()); + assertEquals(HUDI_META_PATH, ct.getTargetMetadataPath()); + assertEquals(avroSchema.toString(), ct.getTargetSchema()); + } + } + + @Test + void convertToTargetIceberg() { + ConvertTableRequest req = + ConvertTableRequest.builder() + .sourceFormat(TableFormat.DELTA) + .sourceTableName(SOURCE_NAME) + .sourceTablePath(SOURCE_PATH) + .targetFormats(Collections.singletonList(TableFormat.ICEBERG)) + .build(); + org.apache.iceberg.Schema icebergSchema = mock(org.apache.iceberg.Schema.class); + try (MockedStatic utils = mockStatic(ConversionUtils.class); + MockedStatic iceExt = mockStatic(IcebergSchemaExtractor.class); + MockedStatic parserMock = mockStatic(SchemaParser.class)) { + + utils + .when(() -> ConversionUtils.getConversionSourceProvider(TableFormat.DELTA, conf)) + .thenReturn(provider); + utils + .when(() -> ConversionUtils.getConversionSourceProvider(TableFormat.ICEBERG, conf)) + .thenReturn(provider); + + when(controller.sync(any(ConversionConfig.class), eq(provider))).thenReturn(null); + when(provider.getConversionSourceInstance(any())).thenReturn(conversionSrc); + when(conversionSrc.getCurrentTable()).thenReturn(internalTbl); + + when(internalTbl.getName()).thenReturn(TableFormat.ICEBERG); + when(internalTbl.getLatestMetdataPath()).thenReturn(ICEBERG_META_PATH); + when(internalTbl.getReadSchema()).thenReturn(internalSchema); + + IcebergSchemaExtractor extractor = mock(IcebergSchemaExtractor.class); + iceExt.when(IcebergSchemaExtractor::getInstance).thenReturn(extractor); + when(extractor.toIceberg(internalSchema)).thenReturn(icebergSchema); + + parserMock.when(() -> SchemaParser.toJson(icebergSchema)).thenReturn(ICEBERG_JSON); + + ConvertTableResponse resp = service.convertTable(req); + + verify(controller, times(1)).sync(any(ConversionConfig.class), eq(provider)); + assertEquals(1, resp.getConvertedTables().size()); + ConvertedTable ct = resp.getConvertedTables().get(0); + assertEquals(TableFormat.ICEBERG, ct.getTargetFormat()); + assertEquals(ICEBERG_META_PATH, ct.getTargetMetadataPath()); + assertEquals(ICEBERG_JSON, ct.getTargetSchema()); + } + } + + @Test + void convertToTargetDelta() { ConvertTableRequest req = ConvertTableRequest.builder() - .sourceFormat("DELTA") - .sourceTableName(SOURCE_TABLE_NAME) - .sourceTablePath(SOURCE_TABLE_BASE_PATH) - .targetFormats(Collections.singletonList("ICEBERG")) + .sourceFormat(TableFormat.ICEBERG) + .sourceTableName(SOURCE_NAME) + .sourceTablePath(SOURCE_PATH) + .targetFormats(Collections.singletonList(TableFormat.DELTA)) .build(); - ConvertTableResponse resp = service.convertTable(req); - verify(controller, times(1)).sync(any(ConversionConfig.class), any()); + StructType structType = mock(StructType.class); + try (MockedStatic utils = mockStatic(ConversionUtils.class); + MockedStatic sparkExt = mockStatic(SparkSchemaExtractor.class)) { + + utils + .when(() -> ConversionUtils.getConversionSourceProvider(TableFormat.ICEBERG, conf)) + .thenReturn(provider); + utils + .when(() -> ConversionUtils.getConversionSourceProvider(TableFormat.DELTA, conf)) + .thenReturn(provider); + + when(controller.sync(any(ConversionConfig.class), eq(provider))).thenReturn(null); + when(provider.getConversionSourceInstance(any())).thenReturn(conversionSrc); + when(conversionSrc.getCurrentTable()).thenReturn(internalTbl); + + when(internalTbl.getName()).thenReturn(TableFormat.DELTA); + when(internalTbl.getLatestMetdataPath()).thenReturn(DELTA_META_PATH); + when(internalTbl.getReadSchema()).thenReturn(internalSchema); + + SparkSchemaExtractor extractor = mock(SparkSchemaExtractor.class); + sparkExt.when(SparkSchemaExtractor::getInstance).thenReturn(extractor); + when(extractor.fromInternalSchema(internalSchema)).thenReturn(structType); + when(structType.json()).thenReturn(DELTA_JSON); + + ConvertTableResponse resp = service.convertTable(req); - ConvertedTable restTargetTable = resp.getConvertedTables().get(0); - assertEquals("ICEBERG", restTargetTable.getTargetFormat()); - assertEquals(TARGET_ICEBERG_METADATA_PATH, restTargetTable.getTargetMetadataPath()); - assertEquals(TARGET_SCHEMA, restTargetTable.getTargetSchema()); + verify(controller, times(1)).sync(any(ConversionConfig.class), eq(provider)); + assertEquals(1, resp.getConvertedTables().size()); + ConvertedTable ct = resp.getConvertedTables().get(0); + assertEquals(TableFormat.DELTA, ct.getTargetFormat()); + assertEquals(DELTA_META_PATH, ct.getTargetMetadataPath()); + assertEquals(DELTA_JSON, ct.getTargetSchema()); + } } } diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionServiceUtil.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionServiceUtil.java deleted file mode 100644 index 31779ae51..000000000 --- a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionServiceUtil.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.xtable.service; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockConstruction; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.when; - -import java.nio.charset.StandardCharsets; - -import org.apache.commons.lang3.tuple.Pair; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.Path; -import org.apache.spark.sql.SparkSession; -import org.apache.spark.sql.types.DataTypes; -import org.apache.spark.sql.types.StructType; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.MockedConstruction; -import org.mockito.MockedStatic; -import org.mockito.junit.jupiter.MockitoExtension; - -import org.apache.hudi.common.model.HoodieCommitMetadata; -import org.apache.hudi.common.table.HoodieTableMetaClient; -import org.apache.hudi.common.table.timeline.HoodieActiveTimeline; -import org.apache.hudi.common.table.timeline.HoodieInstant; -import org.apache.hudi.common.table.timeline.HoodieTimeline; -import org.apache.hudi.common.util.Option; - -import org.apache.iceberg.BaseTable; -import org.apache.iceberg.SchemaParser; -import org.apache.iceberg.TableMetadata; -import org.apache.iceberg.TableOperations; -import org.apache.iceberg.hadoop.HadoopTables; - -import org.apache.spark.sql.delta.DeltaLog; -import org.apache.spark.sql.delta.Snapshot; -import org.apache.spark.sql.delta.actions.Metadata; - -import org.apache.xtable.conversion.ConversionSourceProvider; -import org.apache.xtable.delta.DeltaConversionSourceProvider; -import org.apache.xtable.hudi.HudiConversionSourceProvider; -import org.apache.xtable.iceberg.IcebergConversionSourceProvider; -import org.apache.xtable.model.storage.TableFormat; -import org.apache.xtable.service.utils.ConversionServiceUtil; - -@ExtendWith(MockitoExtension.class) -class TestConversionServiceUtil { - private static final String DELTA_BASE_PATH = "/tmp/delta-table"; - private static final String DELTA_METADATA_JSON = "/_delta_log/000000000.json"; - - private static final String HUDI_BASE_PATH = "/tmp/hudi-table"; - private static final String HUDI_METADATA_DIR = ".hoodie"; - private static final String HUDI_INSTANT_FILE = "20250506.commit"; - private static final String HUDI_SCHEMA = - "{\n" - + " \"type\": \"record\",\n" - + " \"name\": \"user\",\n" - + " \"namespace\": \"example.hudi\",\n" - + " \"fields\": [\n" - + " { \"name\": \"id\", \"type\": \"string\" },\n" - + " ]\n" - + "}"; - - private static final String ICEBERG_BASE_PATH = "/tmp/iceberg-table"; - private static final String ICEBERG_METADATA_JSON = "/metadata/v1.json"; - private static final String ICEBERG_SCHEMA = - "{\n" - + " \"type\": \"struct\",\n" - + " \"fields\": [\n" - + " { \"id\": 1, \"name\": \"id\", \"required\": true, \"type\": \"string\" },\n" - + " ]\n" - + "}"; - - @Mock SparkSession sparkSession; - @Mock Configuration hadoopConf; - - private final ConversionServiceUtil util = new ConversionServiceUtil(); - - @Test - void testGetDeltaSchemaAndMetadataPath() { - StructType testSchema = new StructType().add("id", DataTypes.IntegerType); - Path testPath = new Path(DELTA_BASE_PATH + DELTA_METADATA_JSON); - - try (MockedStatic deltaStatic = mockStatic(DeltaLog.class)) { - DeltaLog mockLog = mock(DeltaLog.class); - Snapshot mockSnap = mock(Snapshot.class); - Metadata mockMetadata = mock(Metadata.class); - - deltaStatic.when(() -> DeltaLog.forTable(sparkSession, DELTA_BASE_PATH)).thenReturn(mockLog); - when(mockLog.snapshot()).thenReturn(mockSnap); - when(mockSnap.metadata()).thenReturn(mockMetadata); - when(mockMetadata.schema()).thenReturn(testSchema); - when(mockSnap.path()).thenReturn(testPath); - - Pair result = - util.getDeltaSchemaAndMetadataPath(DELTA_BASE_PATH, sparkSession); - assertEquals(testPath.toString(), result.getLeft()); - assertEquals(testSchema.json(), result.getRight()); - } - } - - @Test - void testGetHudiSchemaAndMetadataPath() { - try (MockedStatic clientStatic = - mockStatic(HoodieTableMetaClient.class); - MockedStatic commitStatic = mockStatic(HoodieCommitMetadata.class)) { - - HoodieTableMetaClient.Builder builder = mock(HoodieTableMetaClient.Builder.class); - HoodieTableMetaClient metaClient = mock(HoodieTableMetaClient.class); - - clientStatic.when(HoodieTableMetaClient::builder).thenReturn(builder); - when(builder.setBasePath(HUDI_BASE_PATH)).thenReturn(builder); - when(builder.setConf(hadoopConf)).thenReturn(builder); - when(builder.build()).thenReturn(metaClient); - - HoodieActiveTimeline activeTimeline = mock(HoodieActiveTimeline.class); - HoodieTimeline commitsTimeline = mock(HoodieTimeline.class); - HoodieInstant instant = mock(HoodieInstant.class); - - when(metaClient.getActiveTimeline()).thenReturn(activeTimeline); - when(activeTimeline.getCommitsTimeline()).thenReturn(commitsTimeline); - when(commitsTimeline.filterCompletedInstants()).thenReturn(commitsTimeline); - when(commitsTimeline.empty()).thenReturn(false); - when(commitsTimeline.lastInstant()).thenReturn(Option.of(instant)); - - when(metaClient.getMetaPath()).thenReturn(HUDI_METADATA_DIR); - when(instant.getFileName()).thenReturn(HUDI_INSTANT_FILE); - - byte[] rawBytes = "data".getBytes(StandardCharsets.UTF_8); - Option rawOption = Option.of(rawBytes); - when(activeTimeline.getInstantDetails(instant)).thenReturn(rawOption); - - HoodieCommitMetadata commitMetadata = mock(HoodieCommitMetadata.class); - commitStatic - .when(() -> HoodieCommitMetadata.fromBytes(rawBytes, HoodieCommitMetadata.class)) - .thenReturn(commitMetadata); - when(commitMetadata.getMetadata(HoodieCommitMetadata.SCHEMA_KEY)).thenReturn(HUDI_SCHEMA); - - Pair result = util.getHudiSchemaAndMetadataPath(HUDI_BASE_PATH, hadoopConf); - - assertEquals( - HUDI_BASE_PATH + "/" + HUDI_METADATA_DIR + "/" + HUDI_INSTANT_FILE, result.getLeft()); - assertEquals(HUDI_SCHEMA, result.getRight()); - } - } - - @Test - void testGetIcebergSchemaAndMetadataPath() { - try (MockedConstruction tablesCons = - mockConstruction( - HadoopTables.class, - (mockTables, ctx) -> { - BaseTable mockTable = mock(BaseTable.class); - TableOperations ops = mock(TableOperations.class); - TableMetadata meta = mock(TableMetadata.class); - - when(mockTables.load(ICEBERG_BASE_PATH)).thenReturn(mockTable); - when(mockTable.operations()).thenReturn(ops); - when(ops.current()).thenReturn(meta); - when(meta.metadataFileLocation()) - .thenReturn(ICEBERG_BASE_PATH + ICEBERG_METADATA_JSON); - }); - MockedStatic parserStatic = mockStatic(SchemaParser.class)) { - parserStatic.when(() -> SchemaParser.toJson(any())).thenReturn(ICEBERG_SCHEMA); - - Pair result = - util.getIcebergSchemaAndMetadataPath(ICEBERG_BASE_PATH, hadoopConf); - - assertEquals(ICEBERG_BASE_PATH + ICEBERG_METADATA_JSON, result.getLeft()); - assertEquals(ICEBERG_SCHEMA, result.getRight()); - } - } - - @Test - void testGetConversionSourceProvider() { - ConversionSourceProvider hudiProvider = - util.getConversionSourceProvider(TableFormat.HUDI, hadoopConf); - assertTrue(hudiProvider instanceof HudiConversionSourceProvider); - - ConversionSourceProvider deltaProvider = - util.getConversionSourceProvider(TableFormat.DELTA, hadoopConf); - assertTrue(deltaProvider instanceof DeltaConversionSourceProvider); - - ConversionSourceProvider icebergProvider = - util.getConversionSourceProvider(TableFormat.ICEBERG, hadoopConf); - assertTrue(icebergProvider instanceof IcebergConversionSourceProvider); - - assertThrows( - IllegalArgumentException.class, - () -> util.getConversionSourceProvider("SomeFormat", hadoopConf)); - } -} From f920984eb2d346a3d3bab5a424b882c7fd7c89a4 Mon Sep 17 00:00:00 2001 From: Rahil Chertara Date: Fri, 9 May 2025 15:50:15 -0700 Subject: [PATCH 14/15] Address Vinish comments --- .../xtable/conversion/ConversionUtils.java | 34 ---- .../xtable/service/ConversionService.java | 149 +++++++++++++----- .../service/models/ConvertTableRequest.java | 22 +-- .../service/models/ConvertTableResponse.java | 6 +- .../xtable/service/models/ConvertedTable.java | 14 +- .../xtable/service/TestConversionService.java | 61 +++---- 6 files changed, 139 insertions(+), 147 deletions(-) diff --git a/xtable-core/src/main/java/org/apache/xtable/conversion/ConversionUtils.java b/xtable-core/src/main/java/org/apache/xtable/conversion/ConversionUtils.java index f6d366e57..f21be6702 100644 --- a/xtable-core/src/main/java/org/apache/xtable/conversion/ConversionUtils.java +++ b/xtable-core/src/main/java/org/apache/xtable/conversion/ConversionUtils.java @@ -18,18 +18,6 @@ package org.apache.xtable.conversion; -import static org.apache.xtable.model.storage.TableFormat.DELTA; -import static org.apache.xtable.model.storage.TableFormat.HUDI; -import static org.apache.xtable.model.storage.TableFormat.ICEBERG; - -import org.apache.hadoop.conf.Configuration; - -import org.apache.hudi.common.table.timeline.HoodieInstant; - -import org.apache.xtable.delta.DeltaConversionSourceProvider; -import org.apache.xtable.hudi.HudiConversionSourceProvider; -import org.apache.xtable.iceberg.IcebergConversionSourceProvider; - public class ConversionUtils { public static SourceTable convertToSourceTable(TargetTable table) { @@ -42,26 +30,4 @@ public static SourceTable convertToSourceTable(TargetTable table) { table.getCatalogConfig(), table.getAdditionalProperties()); } - - public static ConversionSourceProvider getConversionSourceProvider( - String sourceTableFormat, Configuration hadoopConf) { - if (sourceTableFormat.equalsIgnoreCase(HUDI)) { - ConversionSourceProvider hudiConversionSourceProvider = - new HudiConversionSourceProvider(); - hudiConversionSourceProvider.init(hadoopConf); - return hudiConversionSourceProvider; - } else if (sourceTableFormat.equalsIgnoreCase(DELTA)) { - ConversionSourceProvider deltaConversionSourceProvider = - new DeltaConversionSourceProvider(); - deltaConversionSourceProvider.init(hadoopConf); - return deltaConversionSourceProvider; - } else if (sourceTableFormat.equalsIgnoreCase(ICEBERG)) { - ConversionSourceProvider icebergConversionSourceProvider = - new IcebergConversionSourceProvider(); - icebergConversionSourceProvider.init(hadoopConf); - return icebergConversionSourceProvider; - } else { - throw new IllegalArgumentException("Unsupported source format: " + sourceTableFormat); - } - } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java index d14f7abca..6ef822162 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java @@ -19,14 +19,21 @@ package org.apache.xtable.service; import static org.apache.xtable.conversion.ConversionUtils.convertToSourceTable; +import static org.apache.xtable.model.storage.TableFormat.DELTA; +import static org.apache.xtable.model.storage.TableFormat.HUDI; +import static org.apache.xtable.model.storage.TableFormat.ICEBERG; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import lombok.extern.log4j.Log4j2; import org.apache.hadoop.conf.Configuration; +import org.apache.hudi.common.table.timeline.HoodieInstant; + import org.apache.iceberg.SchemaParser; import com.google.common.annotations.VisibleForTesting; @@ -34,9 +41,12 @@ import org.apache.xtable.avro.AvroSchemaConverter; import org.apache.xtable.conversion.ConversionConfig; import org.apache.xtable.conversion.ConversionController; -import org.apache.xtable.conversion.ConversionUtils; +import org.apache.xtable.conversion.ConversionSourceProvider; import org.apache.xtable.conversion.SourceTable; import org.apache.xtable.conversion.TargetTable; +import org.apache.xtable.delta.DeltaConversionSourceProvider; +import org.apache.xtable.hudi.HudiConversionSourceProvider; +import org.apache.xtable.iceberg.IcebergConversionSourceProvider; import org.apache.xtable.iceberg.IcebergSchemaExtractor; import org.apache.xtable.model.InternalTable; import org.apache.xtable.model.storage.TableFormat; @@ -61,10 +71,15 @@ public class ConversionService { private final ConversionController conversionController; private final ConversionServiceConfig serviceConfig; private final Configuration hadoopConf; + private Map> sourceProviders; /** * Constructs a ConversionService instance with required dependencies. * + *

This constructor initializes the ConversionService using the provided service configuration. + * It retrieves the Hadoop configuration, creates a new ConversionController with the Hadoop + * configuration, and initializes conversion source providers based on the Hadoop configuration. + * * @param serviceConfig the conversion service configuration */ @Inject @@ -72,8 +87,19 @@ public ConversionService(ConversionServiceConfig serviceConfig) { this.serviceConfig = serviceConfig; this.hadoopConf = getHadoopConf(); this.conversionController = new ConversionController(hadoopConf); + this.sourceProviders = initSourceProviders(hadoopConf); } + /** + * Retrieves the Hadoop configuration. + * + *

This method creates a new {@code Configuration} instance, reads the Hadoop configuration + * file path from the service configuration, and attempts to load the configuration from the + * specified XML file. If no resources are loaded, it logs a warning. If an error occurs during + * configuration loading, it logs an error message. + * + * @return the initialized Hadoop {@code Configuration} + */ private Configuration getHadoopConf() { Configuration conf = new Configuration(); String hadoopConfigPath = serviceConfig.getHadoopConfigPath(); @@ -98,31 +124,66 @@ private Configuration getHadoopConf() { } /** - * Constructs a ConversionService instance using dependency injection for testing. + * Initializes conversion source providers for different table formats using the provided Hadoop + * configuration. + * + *

This method creates and initializes source providers for HUDI, DELTA, and ICEBERG formats. + * Each provider is initialized with the given Hadoop configuration and then mapped to its + * respective table format identifier. * + * @param hadoopConf the Hadoop configuration used to initialize the source providers + * @return a map mapping table format identifiers to their corresponding initialized conversion + * source providers + */ + private Map> initSourceProviders(Configuration hadoopConf) { + Map> sourceProviders = new HashMap<>(); + ConversionSourceProvider hudiConversionSourceProvider = + new HudiConversionSourceProvider(); + ConversionSourceProvider deltaConversionSourceProvider = + new DeltaConversionSourceProvider(); + ConversionSourceProvider icebergConversionSourceProvider = + new IcebergConversionSourceProvider(); + + hudiConversionSourceProvider.init(hadoopConf); + deltaConversionSourceProvider.init(hadoopConf); + icebergConversionSourceProvider.init(hadoopConf); + + sourceProviders.put(HUDI, hudiConversionSourceProvider); + sourceProviders.put(DELTA, deltaConversionSourceProvider); + sourceProviders.put(ICEBERG, icebergConversionSourceProvider); + + return sourceProviders; + } + + /** + * Constructs a new ConversionService instance for testing purposes. + * + *

This constructor is visible for testing using dependency injection. It allows the injection + * of a preconfigured ConversionController, Hadoop configuration, and source providers. + * + * @param serviceConfig the conversion service configuration * @param conversionController a preconfigured conversion controller + * @param hadoopConf the Hadoop configuration to be used for initializing resources + * @param sourceProviders a map of conversion source providers keyed by table format */ @VisibleForTesting public ConversionService( ConversionServiceConfig serviceConfig, ConversionController conversionController, - Configuration hadoopConf) { + Configuration hadoopConf, + Map> sourceProviders) { this.serviceConfig = serviceConfig; this.conversionController = conversionController; this.hadoopConf = hadoopConf; + this.sourceProviders = sourceProviders; } /** * Converts a source table to one or more target table formats. * - *

The method builds a SourceTable based on the request parameters and constructs corresponding - * TargetTable instances for each target format. It then performs a synchronous conversion through - * the conversion controller. After conversion, it retrieves schema and metadata paths for each - * target table. - * * @param convertTableRequest the conversion request containing source table details and target * formats - * @return a response containing details of converted target tables + * @return a ConvertTableResponse containing details of the converted target tables */ public ConvertTableResponse convertTable(ConvertTableRequest convertTableRequest) { SourceTable sourceTable = @@ -147,39 +208,16 @@ public ConvertTableResponse convertTable(ConvertTableRequest convertTableRequest ConversionConfig.builder().sourceTable(sourceTable).targetTables(targetTables).build(); conversionController.sync( - conversionConfig, - ConversionUtils.getConversionSourceProvider( - convertTableRequest.getSourceFormat(), hadoopConf)); + conversionConfig, sourceProviders.get(convertTableRequest.getSourceFormat())); List convertedTables = new ArrayList<>(); for (TargetTable targetTable : targetTables) { InternalTable internalTable = - ConversionUtils.getConversionSourceProvider(targetTable.getFormatName(), hadoopConf) + sourceProviders + .get(targetTable.getFormatName()) .getConversionSourceInstance(convertToSourceTable(targetTable)) .getCurrentTable(); - String schemaString; - switch (targetTable.getFormatName()) { - case TableFormat.HUDI: - schemaString = - AvroSchemaConverter.getInstance() - .fromInternalSchema(internalTable.getReadSchema()) - .toString(); - break; - case TableFormat.ICEBERG: - org.apache.iceberg.Schema iceSchema = - IcebergSchemaExtractor.getInstance().toIceberg(internalTable.getReadSchema()); - schemaString = SchemaParser.toJson(iceSchema); - break; - case TableFormat.DELTA: - schemaString = - SparkSchemaExtractor.getInstance() - .fromInternalSchema(internalTable.getReadSchema()) - .json(); - break; - default: - throw new UnsupportedOperationException( - "Unsupported table format: " + targetTable.getFormatName()); - } + String schemaString = extractSchemaString(targetTable, internalTable); convertedTables.add( ConvertedTable.builder() .targetFormat(internalTable.getName()) @@ -189,4 +227,43 @@ public ConvertTableResponse convertTable(ConvertTableRequest convertTableRequest } return new ConvertTableResponse(convertedTables); } + + /** + * Extracts the schema string from the given internal table based on the target table format. + * + *

This method supports the following table formats: + * + *

    + *
  • HUDI: Converts the internal schema to an Avro schema and returns its string + * representation. + *
  • ICEBERG: Converts the internal schema to an Iceberg schema and returns its JSON + * representation. + *
  • DELTA: Converts the internal schema to a Spark schema and returns its JSON + * representation. + *
+ * + * @param targetTable the target table containing the desired format information + * @param internalTable the internal table from which the schema is read + * @return the string representation of the converted schema + * @throws UnsupportedOperationException if the target table format is not supported + */ + private String extractSchemaString(TargetTable targetTable, InternalTable internalTable) { + switch (targetTable.getFormatName()) { + case TableFormat.HUDI: + return AvroSchemaConverter.getInstance() + .fromInternalSchema(internalTable.getReadSchema()) + .toString(); + case TableFormat.ICEBERG: + org.apache.iceberg.Schema iceSchema = + IcebergSchemaExtractor.getInstance().toIceberg(internalTable.getReadSchema()); + return SchemaParser.toJson(iceSchema); + case TableFormat.DELTA: + return SparkSchemaExtractor.getInstance() + .fromInternalSchema(internalTable.getReadSchema()) + .json(); + default: + throw new UnsupportedOperationException( + "Unsupported table format: " + targetTable.getFormatName()); + } + } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableRequest.java b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableRequest.java index d683fdded..465c3c0c0 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableRequest.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableRequest.java @@ -22,10 +22,12 @@ import java.util.Map; import lombok.Builder; +import lombok.Getter; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +@Getter @Builder public class ConvertTableRequest { @JsonProperty("source-format") @@ -59,24 +61,4 @@ public ConvertTableRequest( this.targetFormats = targetFormat; this.configurations = configurations; } - - public String getSourceTableName() { - return sourceTableName; - } - - public String getSourceFormat() { - return sourceFormat; - } - - public String getSourceTablePath() { - return sourceTablePath; - } - - public List getTargetFormats() { - return targetFormats; - } - - public Map getConfigurations() { - return configurations; - } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java index 3aab96cd1..1581ea19c 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertTableResponse.java @@ -21,10 +21,12 @@ import java.util.List; import lombok.Builder; +import lombok.Getter; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +@Getter @Builder public class ConvertTableResponse { @JsonProperty("convertedTables") @@ -34,8 +36,4 @@ public class ConvertTableResponse { public ConvertTableResponse(@JsonProperty List convertedTables) { this.convertedTables = convertedTables; } - - public List getConvertedTables() { - return convertedTables; - } } diff --git a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertedTable.java b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertedTable.java index 329691949..12bc915e2 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertedTable.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/models/ConvertedTable.java @@ -19,10 +19,12 @@ package org.apache.xtable.service.models; import lombok.Builder; +import lombok.Getter; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +@Getter @Builder public class ConvertedTable { @JsonProperty("target-format") @@ -43,16 +45,4 @@ public ConvertedTable( this.targetMetadataPath = targetMetadataPath; this.targetSchema = targetSchema; } - - public String getTargetFormat() { - return targetFormat; - } - - public String getTargetMetadataPath() { - return targetMetadataPath; - } - - public String getTargetSchema() { - return targetSchema; - } } diff --git a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java index a30c2205f..d22b561cf 100644 --- a/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java +++ b/xtable-service/src/test/java/org/apache/xtable/service/TestConversionService.java @@ -21,9 +21,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.apache.avro.Schema; import org.apache.hadoop.conf.Configuration; @@ -38,10 +43,8 @@ import org.apache.iceberg.SchemaParser; import org.apache.xtable.avro.AvroSchemaConverter; -import org.apache.xtable.conversion.ConversionConfig; import org.apache.xtable.conversion.ConversionController; import org.apache.xtable.conversion.ConversionSourceProvider; -import org.apache.xtable.conversion.ConversionUtils; import org.apache.xtable.iceberg.IcebergSchemaExtractor; import org.apache.xtable.model.InternalTable; import org.apache.xtable.model.schema.InternalSchema; @@ -94,12 +97,15 @@ class TestConversionService { @BeforeEach void setUp() { this.conf = new Configuration(); - this.service = new ConversionService(serviceConfig, controller, this.conf); + Map> providers = new HashMap<>(); + providers.put(TableFormat.DELTA, provider); + providers.put(TableFormat.HUDI, provider); + providers.put(TableFormat.ICEBERG, provider); + service = new ConversionService(serviceConfig, controller, this.conf, providers); } @Test void convertToTargetHudi() { - // build request ConvertTableRequest req = ConvertTableRequest.builder() .sourceFormat(TableFormat.DELTA) @@ -109,17 +115,8 @@ void convertToTargetHudi() { .build(); Schema avroSchema = new Schema.Parser().parse(HUDI_SCHEMA_JSON); - try (MockedStatic utils = mockStatic(ConversionUtils.class); - MockedStatic avroConv = mockStatic(AvroSchemaConverter.class)) { - - utils - .when(() -> ConversionUtils.getConversionSourceProvider(TableFormat.DELTA, conf)) - .thenReturn(provider); - utils - .when(() -> ConversionUtils.getConversionSourceProvider(TableFormat.HUDI, conf)) - .thenReturn(provider); - - when(controller.sync(any(ConversionConfig.class), eq(provider))).thenReturn(null); + try (MockedStatic avroConv = mockStatic(AvroSchemaConverter.class)) { + when(controller.sync(any(), eq(provider))).thenReturn(null); when(provider.getConversionSourceInstance(any())).thenReturn(conversionSrc); when(conversionSrc.getCurrentTable()).thenReturn(internalTbl); @@ -133,8 +130,7 @@ void convertToTargetHudi() { ConvertTableResponse resp = service.convertTable(req); - // verify & assert - verify(controller, times(1)).sync(any(ConversionConfig.class), eq(provider)); + verify(controller).sync(any(), eq(provider)); assertEquals(1, resp.getConvertedTables().size()); ConvertedTable ct = resp.getConvertedTables().get(0); assertEquals(TableFormat.HUDI, ct.getTargetFormat()); @@ -154,18 +150,10 @@ void convertToTargetIceberg() { .build(); org.apache.iceberg.Schema icebergSchema = mock(org.apache.iceberg.Schema.class); - try (MockedStatic utils = mockStatic(ConversionUtils.class); - MockedStatic iceExt = mockStatic(IcebergSchemaExtractor.class); + try (MockedStatic iceExt = mockStatic(IcebergSchemaExtractor.class); MockedStatic parserMock = mockStatic(SchemaParser.class)) { - utils - .when(() -> ConversionUtils.getConversionSourceProvider(TableFormat.DELTA, conf)) - .thenReturn(provider); - utils - .when(() -> ConversionUtils.getConversionSourceProvider(TableFormat.ICEBERG, conf)) - .thenReturn(provider); - - when(controller.sync(any(ConversionConfig.class), eq(provider))).thenReturn(null); + when(controller.sync(any(), eq(provider))).thenReturn(null); when(provider.getConversionSourceInstance(any())).thenReturn(conversionSrc); when(conversionSrc.getCurrentTable()).thenReturn(internalTbl); @@ -181,7 +169,7 @@ void convertToTargetIceberg() { ConvertTableResponse resp = service.convertTable(req); - verify(controller, times(1)).sync(any(ConversionConfig.class), eq(provider)); + verify(controller).sync(any(), eq(provider)); assertEquals(1, resp.getConvertedTables().size()); ConvertedTable ct = resp.getConvertedTables().get(0); assertEquals(TableFormat.ICEBERG, ct.getTargetFormat()); @@ -201,17 +189,8 @@ void convertToTargetDelta() { .build(); StructType structType = mock(StructType.class); - try (MockedStatic utils = mockStatic(ConversionUtils.class); - MockedStatic sparkExt = mockStatic(SparkSchemaExtractor.class)) { - - utils - .when(() -> ConversionUtils.getConversionSourceProvider(TableFormat.ICEBERG, conf)) - .thenReturn(provider); - utils - .when(() -> ConversionUtils.getConversionSourceProvider(TableFormat.DELTA, conf)) - .thenReturn(provider); - - when(controller.sync(any(ConversionConfig.class), eq(provider))).thenReturn(null); + try (MockedStatic sparkExt = mockStatic(SparkSchemaExtractor.class)) { + when(controller.sync(any(), eq(provider))).thenReturn(null); when(provider.getConversionSourceInstance(any())).thenReturn(conversionSrc); when(conversionSrc.getCurrentTable()).thenReturn(internalTbl); @@ -226,7 +205,7 @@ void convertToTargetDelta() { ConvertTableResponse resp = service.convertTable(req); - verify(controller, times(1)).sync(any(ConversionConfig.class), eq(provider)); + verify(controller).sync(any(), eq(provider)); assertEquals(1, resp.getConvertedTables().size()); ConvertedTable ct = resp.getConvertedTables().get(0); assertEquals(TableFormat.DELTA, ct.getTargetFormat()); From 0b6eccf5808c4e6a49f8adbd4cf9f55941a52e09 Mon Sep 17 00:00:00 2001 From: Vinish Reddy Date: Fri, 9 May 2025 21:47:08 -0700 Subject: [PATCH 15/15] Make sourceProviders private final --- .../main/java/org/apache/xtable/service/ConversionService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java index 6ef822162..1d4ad32e3 100644 --- a/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java +++ b/xtable-service/src/main/java/org/apache/xtable/service/ConversionService.java @@ -71,7 +71,7 @@ public class ConversionService { private final ConversionController conversionController; private final ConversionServiceConfig serviceConfig; private final Configuration hadoopConf; - private Map> sourceProviders; + private final Map> sourceProviders; /** * Constructs a ConversionService instance with required dependencies.