From ebb6877ba230518351a5f94c9e0c2118cd81eaef Mon Sep 17 00:00:00 2001 From: Johannes Bechberger Date: Tue, 8 Feb 2022 16:58:11 +0100 Subject: [PATCH 01/25] JMC by SAP: Update README and change splash screen. --- README.md | 2 ++ .../splash.bmp | Bin 943556 -> 943554 bytes 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 0cad2d0ca7..b019e329c3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Mission Control +*This is a friendly fork of [openjdk/jmc](https://github.com/openjdk/jmc). It aims to integrate changes and improvements for the specific needs of SAP customers.* + Mission Control is an open source production time profiling and diagnostics tool for Java. Builds of Mission Control can currently be found in the Oracle JDK on supported platforms and in the Eclipse marketplace. diff --git a/application/org.openjdk.jmc.rcp.application/splash.bmp b/application/org.openjdk.jmc.rcp.application/splash.bmp index ccd8ff85003fdba9fc0897715d594fba2f22959b..b93a93ce0e148855f2953d7457e53bcc330ebf7b 100644 GIT binary patch delta 14342 zcmcIq2V4}_*3ZnAp)5#MuppM$VV5c(f}$v>7;M-@#DWc3K$^f(1Yu!m3tW2d9T!+c zk*1(vqDG9pODx~hn7nk^o$t&p@Jv4Q^4`n$`2A-%duQg}^FR08bL)ix%kBZo8Fo(H z`&2)n{>lTRwKPd>pu(V>z*iEo^7gb>=OjThAsrWi`Rs-h_Tdb*mhZvHqC zrf5a5lJphEfG}HCUDWU?ri^0ut7sy}H!Kx&q90R1l1C~E!b-Ivls&{!6eXx{B}DIZ zR$;QA!UT0qk<-K#geYekBuy>A6h&W8-%cd_ukjDsl^W!R0^QJwT`9ax;n8-k0?`Rl=}U;;>Z`1?#l;tCHXDj=1jcnisM)F4|_R@F%C$ zBFnYz1lq5oG66Y1$C!xohNUR<{FN!ZzA1D!-(YE!?cw0{iQ7YOFNyuZ^3;2am|=@p z$wB~MVgZPg;dg~XiKB%sN*<<=LSeCR*jD(fgYes9KFyKK4#v$~Agp(>6%Dz#6T)@7 z@_Bl?adT|~wn{$gqPj}}qG=Ft)grzGYvl7)c(v|wxDuyrbh#c9K~X}>xqzdID% z5yQ5R(@~GtX3D^b*A^agoiAMC!4x6a-9*ZPG+zAFsa_t<>jJ;FI{B;FNhyUW3jYnY zK(oc^6ztM}-WhW{+IDlCk~T9=rd^yCaw9PEfvBV-*Vwovf1U5?< zmK%@KZ&XDaG;E`ShHbNcIS|szpEe^-TR1gBAHA2e+XlcX|0!^`1RTOr_9^*~c;H{3a z4*kiPCp7`c_5Ypn(NfcRsc|96K25TlNlI<84F3z6wopHN4{w|I9itE_MdEinBBaI{B&SkV10orT{|1j`;8AjS`WO$2%_Ry( zJ>0)k48H6RLY$^(QH~!WY%BKU38qeU@qGk*enTl#Y7#9q%8|0` zWMsgjfX{z}lEv>@$OY2y0=eKKY0yg=j#kYWCH7^K-A|hK4fEVXgpW!lA!VV8qUhI> z-302_R8YhfhtAsFEU&<%5YKFuQ6S>KJTu)-d+5q4A~hW zf`sD~5(E763+=kzeaH|h(&uCuI3{09xb(G_XjRJ|LQzIDajHV1(5+Vo32;?S;k#J6 z@J+iVFTy^^^n`@s2?&>R@rNYTyq`C#V9~sph zUElR}*9=}L8pDmAqMXdbJ_#HXCt(R7V7TA4uAqW70r6Kg)SL8|r18l#3x&=7rp z{s4h)R;%csZ?>`+DB-1w0?IRnk!?!v65eNiFE}T_c}Y$>$w?uNPDzc!{!iEe?lDs1 z1gUYF)HsJUhAJ$v4QVo`Bzw!X}FNZ0EHga+E z+qL@|9$JdOGk`(IACEgubicUMSA4gx=y&+4CqFaIFHPt>hR-inUAa(+QhnW(IJ;g3VE9bFr|mA^T!o_O0&1`kWFdZ2C3 zJIWFRq*1>#cJ>0Q8yZC%Gyx4+i_j2BZ|@|~{9+ZB(Ce{1PcVIwUvRc>Sb-0(z&kWQ z;Ul&@K3E_2BV=r?v9r>f0vyTk(U{iA@s@M z!39Y5Ny?0|IQuhYkPil<#+_tO-`TfB!E2*WIK}YR^Dj5%JnS!g*k6d=I|{2yBJz+o1)lsL^3KWdTP1!o z<`72bC4yYxPKQbUtNnPZlKI<&kqZNJ8MW>HeUSu~*#wHTMW#`U{l3VHo1sUG?8Qc-@ zMy12GeTJhAW!bqOax;$~-@o*b{g%)b>1We((mk?x_E}!by|&tEcvxQ*?=~;aa-azqtx7)D}F5l#9cjEZ6(4)&dcGzidTdEP|zqT-wOCgK9*J;{z zJ1uvo8F}fR^2GA|fDUn5QI7A{jz?gNUFFx&I9HVk3_1jhT4C1{9kD+hTSA~tWo#!e zZkJb7VtqhDHz!WIsFC!)EAhH1**hS0?vUCvOQA&=){usEGJp)>@?$-Rp@=+O`Gu$| zx-92-NfuWIub{GK@B&UNnOzjuTzzUZUH+6?k}bp0Y;Hzw#5|a?pC=7E$jtm0*#qwr zhnMbLuC;Ty=Fa6BGC^y{GPPXc!I95$xM4o4xw}mGA?u5?yh?JofZ}X!YeRfZNpM(o ziNOH5qw>aY10~RJQNdt}teOwweHb*2N6A{)BA#IFj+6ZQb$S1Dr2F00&iB;VKpq|c zEI=AUuPN&|4MftC!m#G*=(23?7;^JYE^PS~=;xQjG?a#prH=?X+%g$*w&jP)>06)s zzBn&Xo?4K0(0!GztG(tJ4sG~U{)oEga{c!%jPhFz!iT6Y4G~pE78HaS3`pIe1t7gj z)H3tSfy>ar_r(F01?Qcxj7m!}s9Xj`gqVN`kBMeJgUg zV<^eTGN)ftZIeO_cajMFS=5!3dONh#B${S8Ws~ zRHqhn2=hBq^3JDZwQetd{jbn>t$8Xc52?xL0$l2zuC9OCP#jQ`?=4S}-zy7_FK_-4 z==;@NsxR`bDd7Gdt_9rc0`HwI&*c4`bKBpl3P#^6wdk=y14rA)j zlz3N`23hs}$k*5V$Cyt8q8Sy>Wp`O%cN2S9V9=>O)KpbKk5;NOP!g^>4n4O8%LrYM z<(Bv5R9wob=*uqe%_{3n4N0Y@OQz<@MZJeAo;p?ku(0O60SpE|HXd}ZeR{gsr?JQj zu(AHRfrt#QI(NF5D^G#@>7rvXm5o%NFIzeEuK!}}5hb|8RqWMJ?CsigYiv9S(H>Q1 zLOO+#{{*K?y&Froo^Ab`>+Z&(bw^<7ZTAt3A=X$*HH{wyENaPviIN;JGhXtFwT0FF zg|$}-Y5)WI)dN|n^$9bl3UrACT_QCoIlH_sv#bx5U5d@WbSScOP5!IJ6+c>5|6)=r zk#~9K4L?^Fhl@&%6_v$;1t1<;h<+|E6+ns{kZ#`ce#{84@EcUu-caI8J>|(>YAp5j zukYaecCFg}-1k-GA)?Y_qO$)4r^~#O8q16aq&^WPRDUOjI)e`Y4;c}}ZH^esqx-hP zUY6lHY#A><<8;~S>!pp?N*b<})PIr9FHV^ADR_k39s+%xtkk-^s{XvH%ej@8(a9Wv z4wG+a9b@AXwd&CB#B0=oYa_X|;rsnHgEoynjm)H*z$Cx;*L0$C;fb1aw#`3L#u#-9 zY9aiL)VbwtL`{9hzDi+O&FQtR?>;(*c4+@Qs>u?S`81VzjpA5S*%-zW@JYoz|11Quzk#3QjhY$Fkk~22w$Hv`8wd(2!JvGObnVx!)9`RGimV0 zOGgI#+Q|85NrQj76)?Y(v^)RpjyfiqEJFmw_bd!Um@-Lkh< z{8d?LXQp>l!jy3ocOVY;DTL5~5-7g9M52XtVPQMvBMnyzD|-{>%@gRz?Lgg+grA}8 zFggqxGs2%Q#Dfw3!~Kwdx_~{l7;1c360$!GO{;}%%ljrOO5$#J4CX@6Qz{|$VQdR8 zeIaqii#Y46(72CCnmNK&FjYG{GOMJruUzzHx@VZYvgNfNuRnEL+U@^@>PMM6%le1k z>{N}eic-5jf4o+2&_^1|mwrc=3Rj+c1B)bR-5{n-s>NhZ!&P^SJru>+_$<2e|)6&3=@w)4xxb z(?@Q+M*7^7Zn;5nMwhvbE=xoA1S8THn~Zzt z_2^A7HirisHf28?i%x&EghBOMe|@L!x1Q;CgN&c>R2u(O%6}rY85miocd5J2hixML zpIGA=8jM(VhPXWhJ4B%THL!pI9TgL)Rj?G$iYUxpHPf1C^CmiY)6WLXN}eZN{T&=l zc!SYVOBANci<>cLZ~UddS}*@jwQw$y?t>JcglEzOt!ET1Q<)Dg>HPkbr9E^!=)n+6 z7Y9xUqp^box+lO~6;chDnTv_U>BuetGvyukE;2nm{NJty*bZ8JnGCoqO?);2PqJ`>7jDc*ovlPYS6ERp(k50$(c~L9eHswD2^9c4)KmRj(!iLV0 zOQh#bGU=K0Lmd7}=Hr)0FFd*$T}QC^eFkCb;x2^284tsJY?nfsDN(bFNSuOF^RcD8 ziRwWIQ&&`d^H=vMMz<&oyGfHC^0NWb_YRr-{5ObxOgdkqwmXgbq(|dV%LW+8We`(C ziEmlT=vV=CDGwK_Du|C4U^@tOw;bE0o@z|g?omse!h|j))sVIAm6|; z)HPyb!6TCv2~2SR-4J2kL#~CT{Hx@aFUU<_kZb$Nm6yrIeWVHOQ^Jn8Y^&0){kyR3 z$5CM;W+1-Uh{0;V`5A0KQ)tM{UapLa&S0zeMB8oMl>6x4EnL3y^qZ3eAH*lvx%LpA zk1=0L8AlTpkT7&U&<0aUSw#l6QKJS}MP;B@U6^QN!1fHY42emh)TB&mQYAHpZO z0|8UM$o<=;Zo^K}pp#qx=pyHLk@EoEM}|KwZ~9E^bzO{v36(ubGk zNgOIAE-jKHy;A}_Z;;wMvDwfRsu<4q*Yq#P6!1AXL>X-JR7 zp@;V#q#PCobjs*&_pmmP6Z-{5XQa@H8J#9g^Q4wZBZs@F^IabtwUVFJ0hMghhnJvX zyUgL`S;H{n9$Z7KgQ8F!x)JR}nzlPS;0v>`GfzX2r= zVLIw@+Vtw33@D~6(xTaGV%!AOHU!0dJ_N;3Te-;Q4c24LpEh%ku>Zp`qw#q%?(s-P z%d7jN_ZVRXTKpE%o0VzH$X><}=*#PxYW%TOb<<`{D;IbW+Y5 z^+vBrm3wsrQwYHXX1olEGZhLqYNEmbm5C_pM@-k;`$Wa^2H8ADwjJpE)yH)LUrc^R zCOr5>F!)WhUo5qGF%dByKp55h2}U!Y{zNtYbSbuWZNg*%EgmNue>0P2DGGF{Sx54G zrF1LR3_G>n#5n_L^Uj}~(Ru3AnuC*Goi+PfYzp^F!Z`!!a{=+=nbjVXAhBShcI}bL z!ep26$brNrv9;BMJQCbc|AyMfyPBV-Uw$JrhG7dlnD9QQAw2sqZ#2;0O10Gz}xSh)Asv2&hP`;IUK14s+5GkqSbI`d0 z7_S(s<1m{^(}5bWn8$j2#{PVcWmlfnt4@b!XIJcW)OmhxMc|(4w;Js(7FlzqD?Vmn;K*UKkv0T!o5mh1*dn* z-5T4ulexvVu@XHfZ?mIwXg#7qSFad zE|)FawR$r8b{eiTZsughDNjl>K38SuYJy4}j}}kIoy6hOad6}}b8(j=g5&I0JsSbZ zfkwBQoIn`r+%RK`;wL!GZ};q$4BJY9)gmLUaq8nR99L$sFd7{mbrmkZQtb$W-UJ1l zM)%zQX;s3apnY@YSv@(o?wmfn?^r)uPl?h%TitjzBi3si-%ACs zX*ux;hS<|_ZS;B`zD8^?pHeK-7#*y;L?XQ$#!y++BPJZUnMlguC!&>8spn+d9;<3%)zNeeR21*Xk5| z`PYL@F1K2@C@V2O!7&U68-YN>XaKtZK7*L!relSe8)%%#U8O&fHI@SJfC;DSDmpIK zU2QvY)>P$BFq}y!j8jtsVeGX}v~ZgHIt9=W)Qdf)vdvMArK*a;zr`mYwM)u$;9vFr#%OAPB~Cj zJQZ0x;TGl*2U+smAj7~tN@E$Wwq_i1QSf(FJh4~tgu9~m4u$OwObr%|PG=AVfv(?C z9FIDk@LA#qPE;uloAA}vYnRRRKVS*iz0q*2){;W(A9Nmh-0eBg;C}!7k=+{&?zA5o z>h)^Mak<}dXithF1y9x~PnPEv1$SqKFb}2Z zqsmc7l%ozS2?Nx!d75!tR^%bYpuGwf3+QNr3vMfpb)oe6ekX2kudGPVKK0qFD*>-R z50v9Ux3|B?qE$;~z|TA9y+k?NhA#Vo44OafJq{_#ipvgm0lXatyD247^`D(}1C6vb)x7uGY<4n)0+p2rO?AbxlpU|H zMO7hJxL2gPPS;bv*Ax6@TL7ieK*X!7QTMt-o?Z@zr;awWkef9=5B+)!pJ#D&ivsBL zJHyEIQA#?lez$GWoz{i7TTH)dGJ4j#{ZaRZ{7CIE4+Z1d$ViJZ2VMJ>PDe3bxT;v- z17~;Yk=HR?6X|==SvJsaWi5Ee2D7H3!vigWH`+s9T#bEoJ2=2CNT&{0Q4CFQ+at*^C*zaC6^btAd8l#5|B z3nP8w1(VU_aD2C={zO{DA?4`Nx|Ev_RDnv(4xjX>bH#)6cK6TO-fOeI(`xyoXT#Ip zo!|$7P@B`-Y1-&bF+PdF>2wxLg(ZF#j>B+R@=ie!ZH>ik6=zK!KXfhiO4~_P7>o0l zZClBN>^~@hDg>wr1GS&_ta;Ss@UX)k=-)qQ19kVe8@}nm+PwY5lnGRPhvvax5;&T6 zm@xqksnXPG7>g!O;^QzteSAbo1+h|a3vDH3qNASo`c~eZzLXwO2qidBk~l?;VP9%4Sd;QX}5>2dd}N1ZDlb}R?B|8xCFd7OUeeqzCNItu@h zW{^G|XW~$xwUDy;4}-T3)!{7R1QL z!_D=yXhH6Za;CEK6eA8Qh8&$@jAGoFX zO*8e~_ICXB3_6{*W--m*jTv@;;2j{611H{W+wkbZmirwWawDe)?`4|KMTLRNn&`xN ze6~3AJPxx2rC$7vo|-aaks;k{8#8z>0WCc8uxhx65|BK&kwK?psPR+Acr?EcpCPvI zqb%9@1^%-ZbX~LbXm+ObU27Qd-lk=A4OP^B6{6?2SHUFd-zqT0dv4*&F>&r~%0z5q zToE~UC^ONqS9B%uw8yv+CU$%RkHk$c@l}}khgX!m`&&vb{Em`Yzf!W(drEG_X(0bX zqd`_16P5H(k}VC~#|e7sYx{9JI;TwgP7%im80gKIsEgd#wAJEYSTt1vjT?sU7~a;9 zy(nI#MN`AX>$Itiii_a$f>s(KzB`$=02525Kq?KgK-|f+NvO^WXQFo}X)N^4oTh?o zt}7~{q+@giaAp@w(?{O56PF{}G(vnmk1AWefXXPieB>cV{HB6tOo-<+P^BDfq?EkbO1-Gv zM!gu;MWuIjQ}Tj-NajJ*6NtIUqr2gat1*qae=Li*uat+=EHK`1*BSZg>5=g)-4dN+gx8n)Z?=`1IH30fmQ1Vp zBbeI~jiqY}t~4U}ihK*d$0^&~DN|$VErTmq`j2IE4Gn+aY)elXK7*wnVR=9IB6Wr!QR$GPZ7F{6Q#4jj!iDO+r% z+}fz>_SIaTzUAte$F{`D(Xhy4OMICm(X~j~wAo?BGm*8n) z5e8Vl*-Amz1C}l?9lds}==+P{YPb%W7T4Uj8b_p0H_kKQ&3Em%J9pU%r=>tA1Q4moTAXVeJg)vi#7daTVUp1J2gB@2;XrTb17(&W*OE()hY~{RcD6^{g|O|vn%@s z$K9QcrSN326G~6}=|Tf~4qE}Z?mMQrudcZtu8Pi44^O=@99Uf9Ai7se!{XY0Y^LSLGC9_;dEaUuK!&T)1l&^6@rh$wgr<1 zW41l8p&qKI+L}A6OsgUyi`ZlMvn0zTiS&tNdN%%o4jIBh+a9YJuB)+QLk31fVmSvL zIVi5XOUq*znvmP%hSSfv^9@+Soq#((qPynCr7+*%0R?H{uCK|1IafPjo-$xX3#Rmn zvH)v_rAJr+)D}Aqf*||*hX@2N3(fg#)At zidiwODWE2g60g==WZwAPo zP|;%OiaYxG1hXHP%nm;gA`vtG4^^e?vDfpOSp1vb3?fJ&Z$XAFDLNZ}zL zOh$Y%*bs(LWtk!da`zvpXF-;yf}7H95+od*XUE}0r>$!Ojyw8|RC?AMB($i1q_ytL zJMM#P>oI>$UTjnFXU3fvyi(=p7a%g>Ac`ObZNMPkiK2kjVIZc+PTPP;ovp%c8|`q3 zA3oui0p1Y2SsR0IHe1E+S3Ax0cRR755k=wAm9_~Vzida`(i+_@{X%yi-8&7OKFqJ0 z7R#DQc|>@!BO}uY&j*=}YX&fhjHo=L6(-{hk`zC=}(243HkC z8$U%7Fmfox;&waWwlwI_sW{>E|9#Y8xLt+;`){^&x1qO&VCF;b3|oWA%WQorX{WC! zgf&Zq%#Gjz@l*oMdRxF1g}XTktw=if&ak5;ww>BOO; zn+1wVJ4AiSteasR!GNBQfG!lLn|P>-XES7?uRTDp1_SNWb{ETMa1KfmZaqi?o_>(6XUKVOP03_8Kt0*A79) zY&+m&*(FSX`FpH*-T?ZG3_v-?A_3#Jp@{ju)Zm_O%dGI*G|BsO#03#ctvLs=yVA{b zkH4V9FBOzP41P#cn{u@+?(U;0?;({{8}LLs((FXDm2f{^V!{Z8nQ%13DxsG|6Fsg& z)kp_5a<3h@*zYy^HBxx~9QfG;p_+n5RCOcQQ5hrf@)KaZ=_U zPQHfUp8VX_DkWF2SN$GtNu5kqODYqYPkncHpMiVHdjrEG%v$E_5Ld7TM%mjQM$TLgD*Vh(S?CTN2lFC))M7fMBuv=vvs zQ}F#a)h-c8ipXWceM0WEurT@~EXmcUZB@~l;&9ziryzj*%q4YM3tLCAJnxu&dtE zQvwV*Cd*54qrq>^*!k46$Oadj$>qfF4 zP&a8gzBJ3dO#!g|cHE>~Cqyv#tQFVEU(G3~P@Dp{WnwOEGA5DW4#@5drntTi2j#VN z8D7u57ck-Y)lLewDvklaUTDR=?W5Q&2An*M(wQ8~u6IkzbhvvHvl7xxQi(G4Lx+!# zu_UrBD~eRqGBp{)N~JhKEq8PT2@&~AmNVaX8TSeC82}Z20aghtLcaw>xuD2;_2bxW z1~l$tDpVar8Be`l2#2fKICmGSPRAxogMG`Hr4l%Jw#tc}F9IofM^~SBvKRErZxTLv z9;;2q23v1GZmCIMbo!CXJ{5M4#Bx#HVU?=L`8d>8J8@n3uL+iZXeGVeDQu1bZ#A<# zsC^Un<16DV2y3oJZJB>J)1!zbKZK4!FmjOXejdh)_eJFXx0>IJH0Kl9U2Egpb;~De>oO&~Xh*css8_YP$P&q~MWb z%z&*)QyUDcCZ~mxizmv ze8L9*`aS(ad@{WW`u7o2;gJs|RxCg8X17%ay$dbPyJHrcYe0M^i$X`OqeuMhtc@#Ez+_(zd*N7E`EChOx}GeU63lx)8?u zclWc}k$4b9fzI?uQY$H$`iIX@QgS$O%03^3GcrXeCiy~mM0kO;$uBqpQ-3lIq^1Zj zh7@KVx8gxRtXO(r!D%~%ep=&&A7l?0ZpG^X_^0LUdhCL-yhEIDY&pAt_Mfr#4l5TT zi)HJm(vgH1{ZM2~5Qrw29 zi(3)?BTc9aH?C$;@4nRx4@iXejlzQw_@8EWqlrC~AS+zjf`o33W05&C0o#`?D0$G< z$J9dKMxrDc?xz*qW3%6gB_8{X09?P?Du7ouVtTy40!!&i3!Aj6xt8gbw6X@&{-^Mr z742*jd^-V&PP2~_f=MFjH(uGveUq>@W`swu-j^92o?V5Wb;@x@5=r#6N$FUk};D=9z+c7++YsiA^ERi?^S)?Lx%g?^9`%SQiT*^mbx{bMh8Eul@9e zJc#@amwRL&d78Ngn7FJelDiUXb$oE+&G31O+^t=!d;K*{8;XvLnydegyc^A7| z$UC+~jU)(s8yf-h7h1VR6sLYWX&r(f7Fg%*o>%}|KEvJD=8d++*23VI@F=!-1$wgg zEOy$jZo_8r{cRM#@4{GE%HL#nNL|+9$v4?_+Use92iSpYWd^P*;)hRQ5+0z!HKrX( z^xGtNDyUg84W?{o72c1xvjw6ko4C`${vmP%VSKuqZF5gn8V}y z%00;DB?jiM?;N=kQI23d`JNv^*C1Q|31wA zBPNp}<5=N#SicaHjplIt>>!Zj(<4W4hkCk?rGiaSbxl-lifT>XppV%i>}`*+-^j^` z_Cyehm4=;Qon6eEa4${AN3=CB!nyiQMVsXimPcXRXK3?pKcj4*;_mhyQepI0>^=DO z0V{cNe}NrXY$cr~Mj~~_spMK1JQq94=8sT)79VG}_tWF-CWE&Y!J)sh$Ni2~w5#Rt zc0IN}ZXZitlGUXzGy}=hYWOZnmI3Bh6Qi(Sylwc>#Zbff)W!6*hmEG*^k^o-%HX^ zD75~7;C)2%4xD8R4YSy2DKcA%45&2t4eqqEAXM*R>QLlq76x%vw8pr!xR<-0EDSoy z9y2geFtXVY3kPAWeFw=K{|W^ruY|4yrX32mYGoo#SYd(5i@en)pJN!U#b#@f(Ta!v zybj9-4JZXG5h0MWFB2za%}~7!ckpyrFn<;1=dP)?PKUQbeMo>LmFbGS6Mtbz7&2Zu z?2RCnigzpnlYvF~1>VI`j_0_BmZxh;gTvYszv0n5T@^#g)0I38hbpdgUl1_pD^1Ne z&HR9lPm-FJr>Y4}`QE_S5-QFhzEYKfpqXzP_zq1aAL8%QRP-ZVvokp2POPfo6{gHW zJzAO1hnNIXQG-8?n6PSsIta#;@fxqGjJ!irsf=sz zhYR@+l^m|X)){I7I<5$5m#G}TV$2K%!qG6}JY-q;GQKl#;5#@kt~l@^-fOyntXMTi zInQBgDpjQEfgGmdfPKUHLhq7tTwP_jG_1Xt&qX8A7z38BQd2QRinFS^7PNw#tCk&B zVb|Y6ap)MTsBoR4grkh-#uJ7az=b3vxUQ1pY2s9_L*whJu4tML(bJer&6RwH_h}`r zrg6lm!ng@|PnO}Y;@>)y{9L?6s~F=1Ld*yUENcjy;F=K|XfWewYB&Os23{11&^2G) z%&$!3For+*gYiUO9`WYc4SYB(na6Kve>PajktW~FV)H2xu=!?xRbh44S`8BQ%hJooL>hR}}_r|Lq~FeA3NnYoR}b+Tc&tjv zr8o5UI(0<*LS-;?EaSuI2l6y(#zqxe>W6v2yX;|%pN_vszx(7$K8n;_!IV|ls$Rc= z{{(vCN~ys^AqznPYgAJi%Z7QEyEuoAc|@7NdpeST{sEKL|Zn zYq?N*jS`HD5aEO}9xj?V!`Yk{7)!>7(E7~pGGpGNNDiDPCmqYZYRe+^_zEjU;Cs`5llXS z7Pc)>v70QzMSGU$I@B-4NX}1ThK+p>opJ4Z$P$=;A=fDpUVNW_3y1b8VIi9E+J4N7 zGyBP`+J=zc{ut7F>=mJ0sA&iV@F$Dnk?XY{;tunE^%1?-Q>z$oYCKPR@m~G|=FK{a zPXp+S92|^$FMrObG4H!C=&4}_k=tmA_rp{4^j}ZYQ*;%k9Ez@|oS~<6f1{_RgUe8c zaUO3gSMVuUl{p5!2M6W{hQO|;IPSo)oIvkhZo<}((gzDhDbu}gEjls0_cSJDn9xV! zN+I+NwNl=sxDsbxeFCSUX)#Xl`=RqqUG-up$$DCX%U_y$5Xf|i}gOL`4M zX!%!%;!{i2G^8SGJz55*-Ux`PClS?jSUghs0;02&8@yLXDVkx6TqCtYPI8!XG*m!& zfqzj+;3lKD+8P7ZlQ38A`a>WDBgZNSz2G=pA}qO9R$3O1CD2n4-4eoM=coAj?G<=5 zQ#uX*e$-Q?eC)kZO)!bETrrJ+7rvTc-f|5-CHbKNODBfTgSN3+AtiAU#AYg|0pF;{ z6DkFd(r$d$wBgVbML)pXw8BSG6IVb!@;?C|BL=C!@RFHD;FF1T*KiN zbtyH>yKfu%0Sae_m9w1ZW_$QQw!4@c8s3> z__NGY1Zn8r!N1Vcp~w9h@O2#CqkqMxPkhj);77%eh94b227XNZ1n?8YPY6Gj_d%b1 K@?QM!asLks1Vo|$ From c47cbc24fbd9453fb93a29953225789f021c45f9 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Sat, 2 Jul 2022 12:15:38 +0200 Subject: [PATCH 02/25] Add a build workflow for SAP JMC build --- .github/workflows/build.yml | 276 ++++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..666697d3ec --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,276 @@ +name: Build + +on: + schedule: + - cron: '10 20 * * *' + + workflow_dispatch: + inputs: + publish: + description: 'Publish on GitHub' + required: true + type: boolean + default: true + release: + description: 'Release Build (removes -SNAPSHOT from version)' + required: true + type: boolean + default: false + forceBuild: + description: 'Force build (even if already published). EA releases will be updated/overwritten.' + required: true + type: boolean + default: false + skipTests: + description: 'Skip testing' + required: true + type: boolean + default: false + gitRef: + description: 'Git ref (branch/tag/commit). If not set, the head of the branch selected above is used.' + required: false + +jobs: + parameters: + name: Initialize Parameters and Versions + runs-on: ubuntu-latest + outputs: + publish: ${{ github.event.inputs.publish || true }} + release: ${{ github.event.inputs.release || false }} + skipTests: ${{ github.event.inputs.skipTests || false }} + githubRelease: ${{ steps.versions.outputs.githubRelease }} + jmcVersion: ${{ steps.versions.outputs.jmcVersion }} + agentVersion: ${{ steps.versions.outputs.agentVersion }} + doBuild: ${{ steps.buildcheck.outputs.doBuild }} + commit: ${{ steps.buildcheck.outputs.commit }} + steps: + - name: Checkout JMC + uses: actions/checkout@v3 + with: + ref: ${{ github.event.inputs.gitRef }} + + - name: Determine JMC version + id: versions + run: | + JMC_REV=$(grep -i \ pom.xml | sed 's/^[ \t]*//g;s/<\/revision>[ \t]*$//g') + if [[ '${{ github.event.inputs.release || false }}' == true ]]; then + JMC_VERSION=${JMC_REV} + else + JMC_VERSION=${JMC_REV}-SNAPSHOT + fi + echo JMC version: $JMC_VERSION + echo "::set-output name=jmcVersion::$(echo $JMC_VERSION)" + + RELEASE_TAG=${JMC_VERSION}-sap + echo GitHub Release Tag: $RELEASE_TAG + echo "::set-output name=githubRelease::$(echo $RELEASE_TAG)" + + AGENT_REV=$(cd agent && grep -i \ pom.xml | sed 's/^[ \t]*//g;s/<\/revision>[ \t]*$//g') + if [[ '${{ github.event.inputs.release || false }}' == true ]]; then + AGENT_VERSION=${AGENT_REV} + else + AGENT_VERSION=${AGENT_REV}-SNAPSHOT + fi + echo Agent version: $AGENT_VERSION + echo "::set-output name=agentVersion::$(echo $AGENT_VERSION)" + + - name: Download existing release file + uses: robinraju/release-downloader@v1.4 + continue-on-error: true + with: + tag: ${{ steps.versions.outputs.githubRelease }} + fileName: buildRef-${{ steps.versions.outputs.jmcVersion }}.txt + + - name: Determine whether build is needed + id: buildcheck + run: | + function check_run() { + FORCE_BUILD='${{ github.event.inputs.forceBuild || false }}' + + if [[ $FORCE_BUILD == true ]]; then + echo 'true' + exit 0 + fi + + if [[ $MY_REV != $REL_REV ]]; then + echo 'true' + else + echo 'false' + fi + } + + MY_REV=$(git rev-parse HEAD) + echo My Rev: $MY_REV + REL_REV=$(cat buildRef-${{ steps.versions.outputs.jmcVersion }}.txt) || true + echo Released Rev: $REL_REV + echo Should run: $(check_run) + echo "::set-output name=doBuild::$(check_run)" + echo "::set-output name=commit::$(echo $MY_REV)" + + build: + name: Build JMC + needs: parameters + if: needs.parameters.outputs.doBuild == 'true' + runs-on: ubuntu-latest + env: + MAVEN_OPTS: -Xmx2048m + MAVEN_CALL: mvn --no-transfer-progress + steps: + - name: Summarize parameters + run: | + echo publish: ${{ needs.parameters.outputs.publish }} + echo release: ${{ needs.parameters.outputs.release }} + echo skipTests: ${{ needs.parameters.outputs.skipTests }} + echo githubRelease: ${{ needs.parameters.outputs.githubRelease }} + echo jmcVersion: ${{ needs.parameters.outputs.jmcVersion }} + echo agentVersion: ${{ needs.parameters.outputs.agentVersion }} + echo commit: ${{ needs.parameters.outputs.commit }} + + - name: Checkout JMC + uses: actions/checkout@v3 + with: + ref: ${{ needs.parameters.outputs.commit }} + + - name: Set up build JDK + uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: '11.0.14' + java-package: jdk + + - name: Cache local Maven repository + uses: actions/cache@v3 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven + + - name: Set up GA build + if: needs.parameters.outputs.release == 'true' + run: | + find . ! -path "*/.git/**" -type f -name "pom.xml" -exec sed -i s/"${{ needs.versions.outputs.jmcVersion }}-SNAPSHOT"/"${{ needs.versions.outputs.jmcVersion }}"/ {} \; + find . ! -path "*/.git/**" -type f \( -name "feature.xml" -o -name "MANIFEST.MF" \) -exec sed -i s/"${{ needs.versions.outputs.jmcVersion }}.qualifier"/"${{ needs.versions.outputs.jmcVersion }}"/ {} \; + echo "MAVEN_OPTS=$MAVEN_OPTS -Dchangelist=" >> $GITHUB_ENV + + - name: Write build information + run: | + echo '${{ needs.parameters.outputs.commit }}' > buildRef.txt + + - name: Build & test core libraries + run: | + $MAVEN_CALL install + working-directory: core + + - name: Build & test agent + # we build the agent only in snapshots + if: needs.parameters.outputs.release != 'true' + run: | + $MAVEN_CALL install + working-directory: agent + + - name: Build JMC + run: | + $MAVEN_CALL p2:site + $MAVEN_CALL jetty:run & + cd ../../ + $MAVEN_CALL package + working-directory: releng/third-party + + - name: Run unit tests + if: needs.parameters.outputs.skipTests != 'true' + run: | + $MAVEN_CALL verify + + - name: Run UI tests + if: needs.parameters.outputs.skipTests != 'true' + # Ignore UI failures for now + continue-on-error: true + uses: GabrielBB/xvfb-action@v1 + with: + run: ${{ env.MAVEN_CALL }} verify -P uitests + + - name: Delete old GitHub release ${{ needs.parameters.outputs.githubRelease }} + if: ${{ needs.parameters.outputs.publish == 'true' && needs.parameters.outputs.release != 'true' }} + continue-on-error: true + uses: dev-drprasad/delete-tag-and-release@v0.2.0 + with: + delete_release: true + tag_name: ${{ needs.parameters.outputs.githubRelease }} + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Create/Update GitHub release ${{ needs.parameters.outputs.githubRelease }} + if: needs.parameters.outputs.publish == 'true' + uses: ncipollo/release-action@v1 + with: + tag: ${{ needs.parameters.outputs.githubRelease }} + commit: ${{ needs.parameters.outputs.commit }} + allowUpdates: ${{ needs.parameters.outputs.release != 'true' }} + prerelease: ${{ needs.parameters.outputs.release != 'true' }} + + - name: Upload buildRef-${{ needs.parameters.outputs.jmcVersion }}.txt + if: needs.parameters.outputs.publish == 'true' + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ needs.parameters.outputs.githubRelease }} + file: buildRef.txt + asset_name: buildRef-${{ needs.parameters.outputs.jmcVersion }}.txt + overwrite: ${{ needs.parameters.outputs.release != 'true' }} + + - name: Upload sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-linux.gtk.x86_64.tar.gz + if: needs.parameters.outputs.publish == 'true' + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ needs.parameters.outputs.githubRelease }} + file: target/products/org.openjdk.jmc-linux.gtk.x86_64.tar.gz + asset_name: sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-linux.gtk.x86_64.tar.gz + overwrite: ${{ needs.parameters.outputs.release != 'true' }} + + - name: Upload sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-macosx.cocoa.aarch64.tar.gz + if: needs.parameters.outputs.publish == 'true' + uses: svenstaro/upload-release-action@v2 + with: + tag: ${{ needs.parameters.outputs.githubRelease }} + file: target/products/org.openjdk.jmc-macosx.cocoa.aarch64.tar.gz + asset_name: sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-macosx.cocoa.aarch64.tar.gz + overwrite: ${{ needs.parameters.outputs.release != 'true' }} + + - name: Upload sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-macosx.cocoa.x86_64.tar.gz + if: needs.parameters.outputs.publish == 'true' + uses: svenstaro/upload-release-action@v2 + with: + tag: ${{ needs.parameters.outputs.githubRelease }} + file: target/products/org.openjdk.jmc-macosx.cocoa.x86_64.tar.gz + asset_name: sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-macosx.cocoa.x86_64.tar.gz + overwrite: ${{ needs.parameters.outputs.release != 'true' }} + + - name: Upload sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-win32.win32.x86_64.zip + if: needs.parameters.outputs.publish == 'true' + uses: svenstaro/upload-release-action@v2 + with: + tag: ${{ needs.parameters.outputs.githubRelease }} + file: target/products/org.openjdk.jmc-win32.win32.x86_64.zip + asset_name: sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-win32.win32.x86_64.zip + overwrite: ${{ needs.parameters.outputs.release != 'true' }} + + - name: Upload sap.jmc.updatesite.ide-${{ needs.parameters.outputs.jmcVersion }}.zip + if: needs.parameters.outputs.publish == 'true' + uses: svenstaro/upload-release-action@v2 + with: + tag: ${{ needs.parameters.outputs.githubRelease }} + file: application/org.openjdk.jmc.updatesite.ide/target/org.openjdk.jmc.updatesite.ide-${{ needs.parameters.outputs.jmcVersion }}.zip + asset_name: sap.jmc.updatesite.ide-${{ needs.parameters.outputs.jmcVersion }}.zip + overwrite: ${{ needs.parameters.outputs.release != 'true' }} + + - name: Upload agent-${{ needs.parameters.outputs.agentVersion }}.jar + # we only build the agent in snapshots + if: ${{ needs.parameters.outputs.publish == 'true' && needs.parameters.outputs.release != 'true' }} + uses: svenstaro/upload-release-action@v2 + with: + tag: ${{ needs.parameters.outputs.githubRelease }} + file: agent/target/agent-${{ needs.parameters.outputs.agentVersion }}.jar + asset_name: agent-${{ needs.parameters.outputs.agentVersion }}.jar + overwrite: ${{ needs.parameters.outputs.release != 'true' }} From cc3f1bce6ac40ea9794d343fe775c32b08311596 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Mon, 29 Aug 2022 09:10:29 +0200 Subject: [PATCH 03/25] Build workflow: Make it possible to use git ref as GitHub version in release builds --- .github/workflows/build.yml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 666697d3ec..91fe4d080b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,12 +7,17 @@ on: workflow_dispatch: inputs: publish: - description: 'Publish on GitHub' + description: 'Publish on GitHub.' required: true type: boolean default: true release: - description: 'Release Build (removes -SNAPSHOT from version)' + description: 'Release Build (removes -SNAPSHOT from source version).' + required: true + type: boolean + default: false + useGitRefAsGithubVersion: + description: 'Use the Git ref field as GitHub version, e.g. if you build a release tag. If false, the GitHub version is derived from the JMC source version.' required: true type: boolean default: false @@ -22,7 +27,7 @@ on: type: boolean default: false skipTests: - description: 'Skip testing' + description: 'Skip testing.' required: true type: boolean default: false @@ -61,7 +66,11 @@ jobs: echo JMC version: $JMC_VERSION echo "::set-output name=jmcVersion::$(echo $JMC_VERSION)" - RELEASE_TAG=${JMC_VERSION}-sap + if [[ '${{ github.event.inputs.useGitRefAsGithubVersion || false }}' == true ]]; then + RELEASE_TAG=${{ github.event.inputs.gitRef }} + else + RELEASE_TAG=${JMC_VERSION}-sap + fi echo GitHub Release Tag: $RELEASE_TAG echo "::set-output name=githubRelease::$(echo $RELEASE_TAG)" From 0679f1ed4c56b8ef04214c57ebb3c35be5542cb6 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Thu, 16 Feb 2023 23:19:50 +0100 Subject: [PATCH 04/25] Updates/Fixes for build workflow Remove occurences of deprecated ::set-output calls Update build JDK Disable UI tests since they timeout constantly --- .github/workflows/build.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 91fe4d080b..350c3d4cc6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,7 +64,7 @@ jobs: JMC_VERSION=${JMC_REV}-SNAPSHOT fi echo JMC version: $JMC_VERSION - echo "::set-output name=jmcVersion::$(echo $JMC_VERSION)" + echo "jmcVersion=$(echo $JMC_VERSION)" >> $GITHUB_OUTPUT if [[ '${{ github.event.inputs.useGitRefAsGithubVersion || false }}' == true ]]; then RELEASE_TAG=${{ github.event.inputs.gitRef }} @@ -72,7 +72,7 @@ jobs: RELEASE_TAG=${JMC_VERSION}-sap fi echo GitHub Release Tag: $RELEASE_TAG - echo "::set-output name=githubRelease::$(echo $RELEASE_TAG)" + echo "githubRelease=$(echo $RELEASE_TAG)" >> $GITHUB_OUTPUT AGENT_REV=$(cd agent && grep -i \ pom.xml | sed 's/^[ \t]*//g;s/<\/revision>[ \t]*$//g') if [[ '${{ github.event.inputs.release || false }}' == true ]]; then @@ -81,7 +81,7 @@ jobs: AGENT_VERSION=${AGENT_REV}-SNAPSHOT fi echo Agent version: $AGENT_VERSION - echo "::set-output name=agentVersion::$(echo $AGENT_VERSION)" + echo "agentVersion=$(echo $AGENT_VERSION)" >> $GITHUB_OUTPUT - name: Download existing release file uses: robinraju/release-downloader@v1.4 @@ -113,8 +113,8 @@ jobs: REL_REV=$(cat buildRef-${{ steps.versions.outputs.jmcVersion }}.txt) || true echo Released Rev: $REL_REV echo Should run: $(check_run) - echo "::set-output name=doBuild::$(check_run)" - echo "::set-output name=commit::$(echo $MY_REV)" + echo "doBuild=$(check_run)" >> $GITHUB_OUTPUT + echo "commit=$(echo $MY_REV)" >> $GITHUB_OUTPUT build: name: Build JMC @@ -144,7 +144,7 @@ jobs: uses: actions/setup-java@v3 with: distribution: temurin - java-version: '11.0.14' + java-version: '11.0.18' java-package: jdk - name: Cache local Maven repository @@ -191,13 +191,13 @@ jobs: run: | $MAVEN_CALL verify - - name: Run UI tests - if: needs.parameters.outputs.skipTests != 'true' - # Ignore UI failures for now - continue-on-error: true - uses: GabrielBB/xvfb-action@v1 - with: - run: ${{ env.MAVEN_CALL }} verify -P uitests + #- name: Run UI tests + # if: needs.parameters.outputs.skipTests != 'true' + # # Ignore UI failures for now + # continue-on-error: true + # uses: GabrielBB/xvfb-action@v1 + # with: + # run: ${{ env.MAVEN_CALL }} verify -P uitests - name: Delete old GitHub release ${{ needs.parameters.outputs.githubRelease }} if: ${{ needs.parameters.outputs.publish == 'true' && needs.parameters.outputs.release != 'true' }} From bbe27ebc5870a1401dd09a0c48eefdd2e5f56249 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Mon, 27 Mar 2023 22:23:47 +0200 Subject: [PATCH 05/25] Bump version of dev-drprasad/delete-tag-and-release --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 350c3d4cc6..3175258ff6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -202,7 +202,7 @@ jobs: - name: Delete old GitHub release ${{ needs.parameters.outputs.githubRelease }} if: ${{ needs.parameters.outputs.publish == 'true' && needs.parameters.outputs.release != 'true' }} continue-on-error: true - uses: dev-drprasad/delete-tag-and-release@v0.2.0 + uses: dev-drprasad/delete-tag-and-release@v0.2.1 with: delete_release: true tag_name: ${{ needs.parameters.outputs.githubRelease }} From de1a56f08eb98e41135aca780f596e815fef94cf Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Wed, 29 Mar 2023 20:55:34 +0200 Subject: [PATCH 06/25] Fix release creation --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3175258ff6..3d92199491 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -211,12 +211,13 @@ jobs: - name: Create/Update GitHub release ${{ needs.parameters.outputs.githubRelease }} if: needs.parameters.outputs.publish == 'true' - uses: ncipollo/release-action@v1 + uses: ncipollo/release-action@v1.12.0 with: tag: ${{ needs.parameters.outputs.githubRelease }} commit: ${{ needs.parameters.outputs.commit }} allowUpdates: ${{ needs.parameters.outputs.release != 'true' }} prerelease: ${{ needs.parameters.outputs.release != 'true' }} + draft: false - name: Upload buildRef-${{ needs.parameters.outputs.jmcVersion }}.txt if: needs.parameters.outputs.publish == 'true' From 0bfacb89fd60d7042c8d4e015c8031be3528bd74 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Wed, 7 Jun 2023 23:44:43 +0200 Subject: [PATCH 07/25] Fix build workflow after JMC switched to JDK 17 --- .github/workflows/build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3d92199491..a071aa94be 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -123,7 +123,7 @@ jobs: runs-on: ubuntu-latest env: MAVEN_OPTS: -Xmx2048m - MAVEN_CALL: mvn --no-transfer-progress + MAVEN_CALL: mvn --batch-mode --no-transfer-progress steps: - name: Summarize parameters run: | @@ -144,8 +144,9 @@ jobs: uses: actions/setup-java@v3 with: distribution: temurin - java-version: '11.0.18' + java-version: '17' java-package: jdk + mvn-toolchain-id: 'JavaSE-17' - name: Cache local Maven repository uses: actions/cache@v3 From c53f16b350028b7c25be6fa7ce8851e6231851de Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Fri, 19 Jan 2024 21:57:08 +0100 Subject: [PATCH 08/25] Update build action --- .github/workflows/build.yml | 53 ++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a071aa94be..e573a7863b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,7 +37,7 @@ on: jobs: parameters: - name: Initialize Parameters and Versions + name: Gather Parameters runs-on: ubuntu-latest outputs: publish: ${{ github.event.inputs.publish || true }} @@ -84,10 +84,11 @@ jobs: echo "agentVersion=$(echo $AGENT_VERSION)" >> $GITHUB_OUTPUT - name: Download existing release file - uses: robinraju/release-downloader@v1.4 + uses: robinraju/release-downloader@v1 continue-on-error: true with: tag: ${{ steps.versions.outputs.githubRelease }} + repository: ${{ github.repository }} fileName: buildRef-${{ steps.versions.outputs.jmcVersion }}.txt - name: Determine whether build is needed @@ -116,16 +117,12 @@ jobs: echo "doBuild=$(check_run)" >> $GITHUB_OUTPUT echo "commit=$(echo $MY_REV)" >> $GITHUB_OUTPUT - build: - name: Build JMC - needs: parameters - if: needs.parameters.outputs.doBuild == 'true' + printparameters: + name: Print Parameters + needs: [parameters] runs-on: ubuntu-latest - env: - MAVEN_OPTS: -Xmx2048m - MAVEN_CALL: mvn --batch-mode --no-transfer-progress steps: - - name: Summarize parameters + - name: Print parameters run: | echo publish: ${{ needs.parameters.outputs.publish }} echo release: ${{ needs.parameters.outputs.release }} @@ -133,8 +130,31 @@ jobs: echo githubRelease: ${{ needs.parameters.outputs.githubRelease }} echo jmcVersion: ${{ needs.parameters.outputs.jmcVersion }} echo agentVersion: ${{ needs.parameters.outputs.agentVersion }} + echo doBuild: ${{ needs.parameters.outputs.doBuild }} echo commit: ${{ needs.parameters.outputs.commit }} + deleteold: + name: Delete old Release + needs: parameters + if: ${{ needs.parameters.outputs.doBuild == 'true' && needs.parameters.outputs.publish == 'true' && needs.parameters.outputs.release != 'true' }} + runs-on: ubuntu-latest + steps: + - name: Delete old GitHub release ${{ needs.parameters.outputs.githubRelease }} + continue-on-error: true + uses: dev-drprasad/delete-tag-and-release@v1.0 + with: + tag_name: ${{ needs.parameters.outputs.githubRelease }} + github_token: ${{ secrets.GITHUB_TOKEN }} + + build: + name: Build JMC + needs: [parameters, deleteold] + if: needs.parameters.outputs.doBuild == 'true' + runs-on: ubuntu-latest + env: + MAVEN_OPTS: -Xmx2048m + MAVEN_CALL: mvn --batch-mode --no-transfer-progress + steps: - name: Checkout JMC uses: actions/checkout@v3 with: @@ -200,25 +220,14 @@ jobs: # with: # run: ${{ env.MAVEN_CALL }} verify -P uitests - - name: Delete old GitHub release ${{ needs.parameters.outputs.githubRelease }} - if: ${{ needs.parameters.outputs.publish == 'true' && needs.parameters.outputs.release != 'true' }} - continue-on-error: true - uses: dev-drprasad/delete-tag-and-release@v0.2.1 - with: - delete_release: true - tag_name: ${{ needs.parameters.outputs.githubRelease }} - env: - GITHUB_TOKEN: ${{ github.token }} - - name: Create/Update GitHub release ${{ needs.parameters.outputs.githubRelease }} if: needs.parameters.outputs.publish == 'true' - uses: ncipollo/release-action@v1.12.0 + uses: ncipollo/release-action@v1 with: tag: ${{ needs.parameters.outputs.githubRelease }} commit: ${{ needs.parameters.outputs.commit }} allowUpdates: ${{ needs.parameters.outputs.release != 'true' }} prerelease: ${{ needs.parameters.outputs.release != 'true' }} - draft: false - name: Upload buildRef-${{ needs.parameters.outputs.jmcVersion }}.txt if: needs.parameters.outputs.publish == 'true' From 1c2b75bbd6229f1fc591b090aff9ca20188a4c81 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Thu, 28 Mar 2024 17:50:42 +0100 Subject: [PATCH 09/25] Update build workflow --- .github/workflows/build.yml | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e573a7863b..d60ed82ebb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,7 +50,7 @@ jobs: commit: ${{ steps.buildcheck.outputs.commit }} steps: - name: Checkout JMC - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.inputs.gitRef }} @@ -84,7 +84,7 @@ jobs: echo "agentVersion=$(echo $AGENT_VERSION)" >> $GITHUB_OUTPUT - name: Download existing release file - uses: robinraju/release-downloader@v1 + uses: robinraju/release-downloader@v1.9 continue-on-error: true with: tag: ${{ steps.versions.outputs.githubRelease }} @@ -133,35 +133,30 @@ jobs: echo doBuild: ${{ needs.parameters.outputs.doBuild }} echo commit: ${{ needs.parameters.outputs.commit }} - deleteold: - name: Delete old Release - needs: parameters - if: ${{ needs.parameters.outputs.doBuild == 'true' && needs.parameters.outputs.publish == 'true' && needs.parameters.outputs.release != 'true' }} + build: + name: Build JMC + needs: [parameters] + if: needs.parameters.outputs.doBuild == 'true' runs-on: ubuntu-latest + env: + MAVEN_OPTS: -Xmx2048m + MAVEN_CALL: mvn --batch-mode --no-transfer-progress steps: - name: Delete old GitHub release ${{ needs.parameters.outputs.githubRelease }} + if: ${{ needs.parameters.outputs.publish == 'true' && needs.parameters.outputs.release != 'true' }} continue-on-error: true uses: dev-drprasad/delete-tag-and-release@v1.0 with: tag_name: ${{ needs.parameters.outputs.githubRelease }} github_token: ${{ secrets.GITHUB_TOKEN }} - build: - name: Build JMC - needs: [parameters, deleteold] - if: needs.parameters.outputs.doBuild == 'true' - runs-on: ubuntu-latest - env: - MAVEN_OPTS: -Xmx2048m - MAVEN_CALL: mvn --batch-mode --no-transfer-progress - steps: - name: Checkout JMC - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ needs.parameters.outputs.commit }} - name: Set up build JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin java-version: '17' @@ -169,7 +164,7 @@ jobs: mvn-toolchain-id: 'JavaSE-17' - name: Cache local Maven repository - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} From 0d37a23b0836f5b61b51c6f9f253c3aec96a2502 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Fri, 5 Jul 2024 07:33:56 +0200 Subject: [PATCH 10/25] Update build workflow to new naming of archive files --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d60ed82ebb..44567a6b1d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -240,7 +240,7 @@ jobs: with: repo_token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ needs.parameters.outputs.githubRelease }} - file: target/products/org.openjdk.jmc-linux.gtk.x86_64.tar.gz + file: target/products/org.openjdk.jmc-${{ needs.parameters.outputs.jmcVersion }}-linux.gtk.x86_64.tar.gz asset_name: sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-linux.gtk.x86_64.tar.gz overwrite: ${{ needs.parameters.outputs.release != 'true' }} @@ -249,7 +249,7 @@ jobs: uses: svenstaro/upload-release-action@v2 with: tag: ${{ needs.parameters.outputs.githubRelease }} - file: target/products/org.openjdk.jmc-macosx.cocoa.aarch64.tar.gz + file: target/products/org.openjdk.jmc-${{ needs.parameters.outputs.jmcVersion }}-macosx.cocoa.aarch64.tar.gz asset_name: sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-macosx.cocoa.aarch64.tar.gz overwrite: ${{ needs.parameters.outputs.release != 'true' }} @@ -258,7 +258,7 @@ jobs: uses: svenstaro/upload-release-action@v2 with: tag: ${{ needs.parameters.outputs.githubRelease }} - file: target/products/org.openjdk.jmc-macosx.cocoa.x86_64.tar.gz + file: target/products/org.openjdk.jmc-${{ needs.parameters.outputs.jmcVersion }}-macosx.cocoa.x86_64.tar.gz asset_name: sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-macosx.cocoa.x86_64.tar.gz overwrite: ${{ needs.parameters.outputs.release != 'true' }} @@ -267,7 +267,7 @@ jobs: uses: svenstaro/upload-release-action@v2 with: tag: ${{ needs.parameters.outputs.githubRelease }} - file: target/products/org.openjdk.jmc-win32.win32.x86_64.zip + file: target/products/org.openjdk.jmc-${{ needs.parameters.outputs.jmcVersion }}-win32.win32.x86_64.zip asset_name: sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-win32.win32.x86_64.zip overwrite: ${{ needs.parameters.outputs.release != 'true' }} From 4a5de40017efe45aee106f8f766be8a3ee8a88c9 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Tue, 17 Sep 2024 08:38:53 +0200 Subject: [PATCH 11/25] Bump build JDK to 21 and use SapMachine --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 44567a6b1d..c4a54e604d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -158,10 +158,10 @@ jobs: - name: Set up build JDK uses: actions/setup-java@v4 with: - distribution: temurin - java-version: '17' + distribution: sapmachine + java-version: '21' java-package: jdk - mvn-toolchain-id: 'JavaSE-17' + mvn-toolchain-id: 'JavaSE-21' - name: Cache local Maven repository uses: actions/cache@v4 From 97f2a3469a89ebd33fadd9dc3baecf484a50e608 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Mon, 23 Sep 2024 15:02:22 +0200 Subject: [PATCH 12/25] Use JDK17, JDK21 and Maven 3.9.6 --- .github/workflows/build.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c4a54e604d..f6229fa987 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -155,7 +155,15 @@ jobs: with: ref: ${{ needs.parameters.outputs.commit }} - - name: Set up build JDK + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: sapmachine + java-version: '17' + java-package: jdk + mvn-toolchain-id: 'JavaSE-17' + + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: sapmachine @@ -163,6 +171,11 @@ jobs: java-package: jdk mvn-toolchain-id: 'JavaSE-21' + - name: Set up Maven + uses: stCarolas/setup-maven@v4.5 + with: + maven-version: 3.9.6 + - name: Cache local Maven repository uses: actions/cache@v4 with: From 49656449f64b2dc9881702179dd39a2999dd2f3b Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Thu, 3 Apr 2025 11:12:05 +0200 Subject: [PATCH 13/25] Upload linux aarch64 binary in build workflow --- .github/workflows/build.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3b00314571..1a4ea65564 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -247,6 +247,16 @@ jobs: asset_name: buildRef-${{ needs.parameters.outputs.jmcVersion }}.txt overwrite: ${{ needs.parameters.outputs.release != 'true' }} + - name: Upload sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-linux.gtk.aarch64.tar.gz + if: needs.parameters.outputs.publish == 'true' + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ needs.parameters.outputs.githubRelease }} + file: target/products/org.openjdk.jmc-${{ needs.parameters.outputs.jmcVersion }}-linux.gtk.aarch64.tar.gz + asset_name: sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-linux.gtk.aarch64.tar.gz + overwrite: ${{ needs.parameters.outputs.release != 'true' }} + - name: Upload sap.jmc-${{ needs.parameters.outputs.jmcVersion }}-linux.gtk.x86_64.tar.gz if: needs.parameters.outputs.publish == 'true' uses: svenstaro/upload-release-action@v2 From 8ca3540fb741db8acc866869475d033a94dacd30 Mon Sep 17 00:00:00 2001 From: Ralf Schmelter Date: Tue, 29 Jul 2025 08:52:58 +0200 Subject: [PATCH 14/25] Add SAP extensions for JMC agent (#104) --- agent/pom.xml | 89 +- .../java/org/openjdk/jmc/agent/SapAgent.java | 341 ++++ .../jmc/agent/SapTransformRegistry.java | 135 ++ .../org/openjdk/jmc/agent/SapTransformer.java | 116 ++ .../jmc/agent/jfr/impl/JFRClassVisitor.java | 12 +- .../sap/boot/converters/AllocationSite.java | 94 + .../boot/converters/AllocationStatistic.java | 110 ++ .../AllocationStatisticDumpFilter.java | 53 + .../boot/converters/FileOpenCloseLogger.java | 296 ++++ .../sap/boot/converters/GenericLogger.java | 1537 +++++++++++++++++ .../boot/converters/LocaleChangeLogger.java | 79 + .../converters/SystemPropChangeLogger.java | 104 ++ .../boot/converters/TimeZoneChangeLogger.java | 72 + .../UnsafeMemoryAllocationLogger.java | 148 ++ .../jmc/agent/sap/boot/util/Arguments.java | 269 +++ .../agent/sap/boot/util/ArgumentsHolder.java | 42 + .../jmc/agent/sap/boot/util/Command.java | 172 ++ .../jmc/agent/sap/boot/util/Commands.java | 95 + .../jmc/agent/sap/boot/util/Dumps.java | 147 ++ .../jmc/agent/sap/boot/util/LoggingUtils.java | 178 ++ .../agent/sap/boot/util/OutputCommand.java | 33 + .../jmc/agent/sap/traceLocaleChange.xml | 43 + .../openjdk/jmc/agent/sap/traceOpenFiles.xml | 166 ++ .../jmc/agent/sap/traceSysPropsChange.xml | 80 + .../jmc/agent/sap/traceTimeZoneChange.xml | 48 + .../jmc/agent/sap/traceUnsafeAllocations.xml | 81 + .../jmc/agent/sap/test/CloneClassLoader.java | 217 +++ .../sap/test/DuplicateTracedClasses.java | 46 + .../agent/sap/test/GenericLoggingTest.java | 390 +++++ .../jmc/agent/sap/test/JavaAgentRunner.java | 403 +++++ .../jmc/agent/sap/test/LocaleChangeTest.java | 72 + .../agent/sap/test/OpenFileStatisticTest.java | 136 ++ .../jmc/agent/sap/test/OutputReader.java | 76 + .../agent/sap/test/SapIntegrationTest.java | 56 + .../agent/sap/test/SysPropsChangeTest.java | 77 + .../openjdk/jmc/agent/sap/test/TestBase.java | 271 +++ .../jmc/agent/sap/test/TestRunner.java | 102 ++ .../agent/sap/test/TimeZoneChangeTest.java | 79 + .../agent/sap/test/UnsafeAllocationTest.java | 329 ++++ .../jmc/agent/sap/test/VmAgnostic.java | 31 + .../jmc/agent/test/sap/duplicateClasses.xml | 47 + .../openjdk/jmc/agent/test/sap/generic.xml | 357 ++++ .../jmc/agent/test/sap/jconsoleMain.xml | 46 + scripts/runagenttests.bat | 1 + scripts/runagenttests.sh | 1 + 45 files changed, 7267 insertions(+), 10 deletions(-) create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/SapAgent.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/SapTransformRegistry.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/SapTransformer.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationSite.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatistic.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatisticDumpFilter.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/FileOpenCloseLogger.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/GenericLogger.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/LocaleChangeLogger.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/SystemPropChangeLogger.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/TimeZoneChangeLogger.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/UnsafeMemoryAllocationLogger.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Arguments.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/ArgumentsHolder.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Command.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Commands.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Dumps.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/LoggingUtils.java create mode 100644 agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/OutputCommand.java create mode 100644 agent/src/main/resources/org/openjdk/jmc/agent/sap/traceLocaleChange.xml create mode 100644 agent/src/main/resources/org/openjdk/jmc/agent/sap/traceOpenFiles.xml create mode 100644 agent/src/main/resources/org/openjdk/jmc/agent/sap/traceSysPropsChange.xml create mode 100644 agent/src/main/resources/org/openjdk/jmc/agent/sap/traceTimeZoneChange.xml create mode 100644 agent/src/main/resources/org/openjdk/jmc/agent/sap/traceUnsafeAllocations.xml create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/CloneClassLoader.java create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/DuplicateTracedClasses.java create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/GenericLoggingTest.java create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/JavaAgentRunner.java create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/LocaleChangeTest.java create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/OpenFileStatisticTest.java create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/OutputReader.java create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/SapIntegrationTest.java create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/SysPropsChangeTest.java create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestBase.java create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestRunner.java create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/TimeZoneChangeTest.java create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java create mode 100644 agent/src/test/java/org/openjdk/jmc/agent/sap/test/VmAgnostic.java create mode 100644 agent/src/test/resources/org/openjdk/jmc/agent/test/sap/duplicateClasses.xml create mode 100644 agent/src/test/resources/org/openjdk/jmc/agent/test/sap/generic.xml create mode 100644 agent/src/test/resources/org/openjdk/jmc/agent/test/sap/jconsoleMain.xml diff --git a/agent/pom.xml b/agent/pom.xml index 77ebd9f7ab..f9639e09ee 100644 --- a/agent/pom.xml +++ b/agent/pom.xml @@ -93,7 +93,84 @@ 9.8 4.13.2 + Agent + + + + release + + + + + + SapAgent + + SapAgent + 0.9.0 + + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven.jar.version} + + + boot-jar + + jar + + + boot + + org/openjdk/jmc/agent/sap/boot/** + + + + + + test-jar + + + + org/openjdk/jmc/agent/sap/** + org/openjdk/jmc/agent/test/sap/** + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + ${maven.failsafe.version} + + + test-sap-extensions + + integration-test + verify + + + + ${fullTest} + ${dumpOutputToFile} + ${debugPort} + ${singleTest} + + + -cp target/test-classes/ + + SapIntegrationTest.java + + + + + + + + ${scmConnection} @@ -174,6 +251,7 @@ --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -XX:+FlightRecorder + SapIntegrationTest.java TestDefineEventProbes.java TestCustomClassloader.java TestPermissionChecks.java @@ -183,11 +261,6 @@ - - org.apache.maven.plugins - maven-jar-plugin - ${maven.jar.version} - org.apache.maven.plugins maven-shade-plugin @@ -210,6 +283,7 @@ module-info.class META-INF/MANIFEST.MF + org/openjdk/jmc/agent/sap/boot/** @@ -217,8 +291,8 @@ org.openjdk.jmc.agent - org.openjdk.jmc.agent.Agent - org.openjdk.jmc.agent.Agent + org.openjdk.jmc.agent.${agent.name} + org.openjdk.jmc.agent.${agent.name} true JavaSE-17 @@ -383,6 +457,7 @@ ${spotless.version} + ${jmc.config.path}/ide/eclipse/formatting/formatting.xml 4.8.0 diff --git a/agent/src/main/java/org/openjdk/jmc/agent/SapAgent.java b/agent/src/main/java/org/openjdk/jmc/agent/SapAgent.java new file mode 100644 index 0000000000..d487b3abcd --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/SapAgent.java @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.lang.instrument.Instrumentation; +import java.lang.instrument.UnmodifiableClassException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.jar.JarFile; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.openjdk.jmc.agent.impl.DefaultTransformRegistry; +import org.openjdk.jmc.agent.jfr.JFRTransformDescriptor; +import org.openjdk.jmc.agent.jmx.AgentManagementFactory; +import org.openjdk.jmc.agent.sap.boot.converters.GenericLogger; +import org.openjdk.jmc.agent.sap.boot.util.Command; +import org.openjdk.jmc.agent.sap.boot.util.Commands; +import org.openjdk.jmc.agent.sap.boot.util.Dumps; +import org.openjdk.jmc.agent.util.ModuleUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class SapAgent { + + private static final String CONFIGS_PATH = "org/openjdk/jmc/agent/sap/"; + private static final String CONVERTERS_PREFIX = "org.openjdk.jmc.agent.sap.boot.converters."; + private static Logger logger = Logger.getLogger(SapAgent.class.getName()); + private static Instrumentation instr; + private static boolean addedBootJar = false; + private static HashMap seenCommands = new HashMap<>(); + + public static void premain(String agentArguments, Instrumentation instrumentation) throws Exception { + agentmain(agentArguments, instrumentation); + } + + public static void agentmain(String agentArguments, Instrumentation instrumentation) throws Exception { + ModuleUtils.openUnsafePackage(instrumentation); + instr = instrumentation; + + if (agentArguments == null || agentArguments.trim().length() == 0) { + initializeAgent(null, instrumentation); + } else { + if (agentArguments.equals("help")) { + ensureBootJarAdded(); + Commands.printAllCommands(); + System.exit(0); + } + + if (agentArguments.startsWith("dump=")) { + ensureBootJarAdded(); + Dumps.performDump(agentArguments.substring(5)); + return; + } + + try (InputStream stream = new ByteArrayInputStream(getXmlConfig(agentArguments))) { + initializeAgent(stream, instrumentation); + } catch (XMLStreamException | IOException | XMLValidationException e) { + logger.log(Level.SEVERE, "Failed to read jfr probe definitions from " + agentArguments, e); + } + } + } + + private static void addBootJarIfNeeded(TransformRegistry registry) throws IOException { + // Check if we need converters from the boot jar. + boolean needsBootJar = false; + + outer: for (String className : registry.getClassNames()) { + for (TransformDescriptor descriptor : registry.getTransformData(className)) { + JFRTransformDescriptor impl = (JFRTransformDescriptor) descriptor; + + for (Field field : impl.getFields()) { + if (field.hasConverter() && field.getConverterDefinition().startsWith(CONVERTERS_PREFIX)) { + needsBootJar = true; + break outer; + } + } + + for (Parameter param : impl.getParameters()) { + if (param.hasConverter() && param.getConverterDefinition().startsWith(CONVERTERS_PREFIX)) { + needsBootJar = true; + break outer; + } + } + } + } + + if (needsBootJar) { + ensureBootJarAdded(); + } + } + + private static void ensureBootJarAdded() throws IOException { + if (addedBootJar) { + return; + } + + ClassLoader cl = SapAgent.class.getClassLoader(); + + // Find out where the agent jar is, since the boot jar should live + // there too. + URL url = cl.getResource(SapAgent.class.getName().replace('.', '/') + ".class"); + String file = url.getFile(); + + if (!file.startsWith("file:/")) { + throw new IOException("Could not determine agent jar from " + file); + } + + System.err.println("Agent base file: " + file); + + String os = AccessController.doPrivileged((PrivilegedAction) () -> System.getProperty("os.name")); + int skip = os.toLowerCase().startsWith("win") ? 6 : 5; + String jar = file.substring(skip, file.indexOf(".jar!")) + "-boot.jar"; + + if (!new File(jar).canRead()) { + throw new IOException("Could not find boot jar at " + jar); + } + + instr.appendToBootstrapClassLoaderSearch(new JarFile(jar)); + addedBootJar = true; + } + + private static InputStream getStreamForConfig(String config) throws Exception { + try { + return new FileInputStream(config); + } catch (FileNotFoundException e) { + ClassLoader cl = SapAgent.class.getClassLoader(); + InputStream is = cl.getResourceAsStream(CONFIGS_PATH + config + ".xml"); + + if (is != null) { + return is; + } + + throw e; + } + } + + private static void preInitCommands() throws IOException { + if (seenCommands.size() > 0) { + ensureBootJarAdded(); + } + + for (String commandName : seenCommands.keySet()) { + Command command = Commands.getCommand(commandName); + + if (command != null) { + command.addCommandArgs(seenCommands.get(commandName)); + } + } + } + + private static StringBuilder addCommandOptions(String commandName, StringBuilder options) { + if (commandName != null) { + seenCommands.put(commandName, options.toString()); + } + + return new StringBuilder(); + } + + private static byte[] getXmlConfig(String agentArguments) throws Exception { + String[] parts = agentArguments.split("(?\n" + + " \n" + + " __JFREvent\n" + + " false\n" + + " false\n" + + " \n" + + " \n" + + " \n" + + "\n"; + // spotless:on + + Document base = factory.newDocumentBuilder() + .parse(new ByteArrayInputStream(DUMMY.getBytes(StandardCharsets.UTF_8))); + Node events = base.getElementsByTagName("events").item(0); + String requestedPrefix = null; + String configName = null; + + for (String part : parts) { + if (part.equals("help")) { + configProp.append("help=true,"); + } else if (part.startsWith(GenericLogger.GENERIC_COMMAND_PREFIX)) { + // Do nothing, just pick up the options and make sure the converter is accessible. + configProp = addCommandOptions(configName, configProp); + configName = part; + } else if (part.indexOf('=') > 0) { + configProp.append(part).append(','); + } else { + InputStream is = getStreamForConfig(part); + Document doc = factory.newDocumentBuilder().parse(is); + configProp = addCommandOptions(configName, configProp); + + if (is instanceof FileInputStream) { + // No configuration for direct XML file. + configName = null; + } else { + configName = part; + } + + if (getBool(doc, "allowtostring", false)) { + setText(base, "allowtostring", "true"); + } + + if (getBool(doc, "allowconverter", false)) { + setText(base, "allowconverter", "true"); + } + + String prefix = getString(doc, "classprefix"); + + if (requestedPrefix == null) { + requestedPrefix = prefix; + setText(base, "classprefix", prefix); + } else if ((prefix != null) && !requestedPrefix.equals(prefix)) { + System.out.println("Conflicting class prefixes " + prefix + " vs. " + requestedPrefix); + } + + NodeList list = doc.getElementsByTagName("event"); + + for (int j = 0; j < list.getLength(); ++j) { + Node toAdd = list.item(j).cloneNode(true); + events.getOwnerDocument().adoptNode(toAdd); + events.appendChild(toAdd); + } + } + } + + addCommandOptions(configName, configProp); + preInitCommands(); + + // If we added our boot jar, check the options now. + if (addedBootJar && !Commands.checkCommands()) { + System.exit(1); + } + + TransformerFactory tf = TransformerFactory.newInstance(); + javax.xml.transform.Transformer trans = tf.newTransformer(); + StringWriter sw = new StringWriter(); + trans.transform(new DOMSource(base), new StreamResult(sw)); + + return sw.toString().getBytes(); + } + + private static void setText(Document doc, String tag, String text) { + NodeList list = doc.getElementsByTagName(tag); + + if (list.getLength() == 1) { + list.item(0).setTextContent(text); + } + } + + private static String getString(Document doc, String tag) { + NodeList list = doc.getElementsByTagName(tag); + + if (list.getLength() != 1) { + return null; + } + + return list.item(0).getTextContent(); + } + + private static boolean getBool(Document doc, String tag, boolean fallback) { + String text = getString(doc, tag); + + return text == null ? fallback : Boolean.parseBoolean(text); + } + + public static void initializeAgent(InputStream configuration, Instrumentation instrumentation) + throws XMLStreamException, XMLValidationException, IOException { + TransformRegistry registry = configuration != null ? DefaultTransformRegistry.from(configuration) + : DefaultTransformRegistry.empty(); + addBootJarIfNeeded(registry); + instrumentation.addTransformer(new SapTransformer(registry), true); + AgentManagementFactory.createAndRegisterAgentControllerMBean(instrumentation, + new SapTransformRegistry(registry)); + + List> classesToRetransform = new ArrayList<>(); + Set clazzes = registry.getClassNames().stream().map((name) -> name.replace('/', '.')) + .collect(Collectors.toSet()); + + for (Class clazz : instrumentation.getAllLoadedClasses()) { + if (clazzes.contains(clazz.getName())) { + classesToRetransform.add(clazz); + System.out.println("Class to retransform: " + clazz); + } + } + + try { + instrumentation.retransformClasses(classesToRetransform.toArray(new Class[0])); + } catch (UnmodifiableClassException e) { + logger.log(Level.SEVERE, "Unable to retransform classes", e); + } + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/SapTransformRegistry.java b/agent/src/main/java/org/openjdk/jmc/agent/SapTransformRegistry.java new file mode 100644 index 0000000000..63882f0845 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/SapTransformRegistry.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +import org.openjdk.jmc.agent.jfr.JFRTransformDescriptor; + +public class SapTransformRegistry implements TransformRegistry { + + private TransformRegistry registry; + private final HashMap> modifiedTransforms = new HashMap<>(); + + private void modifyTransformations() { + modifiedTransforms.clear(); + + for (String className : getClassNames()) { + String simpleName = className.substring(className.lastIndexOf('/') + 1); + List descs = getTransformData(className); + List modifiedDescs = null; + + for (int i = 0; i < descs.size(); ++i) { + JFRTransformDescriptor desc = (JFRTransformDescriptor) descs.get(i); + JFRTransformDescriptor modified = null; + + if (simpleName.equals(desc.getMethod().getName())) { + Method modifiedMethod = new Method("", desc.getMethod().getSignature()); + modified = new JFRTransformDescriptor(desc.getId(), desc.getClassName(), modifiedMethod, + desc.getTransformationAttributes(), desc.getParameters(), desc.getReturnValue(), + desc.getFields()); + } + + if (modified != null) { + if (modifiedDescs == null) { + modifiedDescs = new ArrayList(descs); + } + + modifiedDescs.set(i, modified); + } + } + + if (modifiedDescs != null) { + modifiedTransforms.put(className, modifiedDescs); + } + } + } + + public SapTransformRegistry(TransformRegistry registry) { + this.registry = registry; + modifyTransformations(); + } + + @Override + public boolean hasPendingTransforms(String className) { + return registry.hasPendingTransforms(className); + } + + @Override + public List getTransformData(String className) { + List modified = modifiedTransforms.get(className); + + if (modified != null) { + return modified; + } + + return registry.getTransformData(className); + } + + @Override + public Set getClassNames() { + return registry.getClassNames(); + } + + @Override + public String getCurrentConfiguration() { + return registry.getCurrentConfiguration(); + } + + @Override + public void setCurrentConfiguration(String xmlDescription) { + registry.setCurrentConfiguration(xmlDescription); + modifyTransformations(); + } + + @Override + public Set modify(String xmlDescription) throws XMLValidationException { + Set result = registry.modify(xmlDescription); + modifyTransformations(); + + return result; + } + + @Override + public Set clearAllTransformData() { + Set result = registry.clearAllTransformData(); + modifyTransformations(); + + return result; + } + + @Override + public void setRevertInstrumentation(boolean shouldRevert) { + registry.setRevertInstrumentation(shouldRevert); + } + + @Override + public boolean isRevertIntrumentation() { + return registry.isRevertIntrumentation(); + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/SapTransformer.java b/agent/src/main/java/org/openjdk/jmc/agent/SapTransformer.java new file mode 100644 index 0000000000..9f41d61697 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/SapTransformer.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.security.ProtectionDomain; + +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.openjdk.jmc.agent.util.TypeUtils; + +public class SapTransformer implements ClassFileTransformer { + + private final Transformer impl; + private final Module jfrModule; + private TransformRegistry registry; + + public SapTransformer(TransformRegistry registry) { + this.registry = registry; + jfrModule = ModuleLayer.boot().findModule("jdk.jfr").get(); + impl = new Transformer(new SapTransformRegistry(registry)); + } + + private void grantJfrAccessToModule( + Module module, ClassLoader loader, String className, ProtectionDomain protectionDomain) + throws IllegalClassFormatException { + // We need to access the jfr module. + if (!module.canRead(jfrModule)) { + // Create a class in the module which grants the access. + ClassWriter cw = new ClassWriter(0); + String name = className + "_$MakeJFRModuleReadable"; + cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, name, null, "java/lang/Object", null); + + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "", "()V", null, null); + mv.visitCode(); + mv.visitLdcInsn(Type.getObjectType(name)); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getModule", "()Ljava/lang/Module;", false); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/ModuleLayer", "boot", "()Ljava/lang/ModuleLayer;", + false); + mv.visitLdcInsn("jdk.jfr"); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/ModuleLayer", "findModule", + "(Ljava/lang/String;)Ljava/util/Optional;", false); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/Optional", "get", "()Ljava/lang/Object;", false); + mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Module"); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Module", "addReads", + "(Ljava/lang/Module;)Ljava/lang/Module;", false); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(2, 0); + mv.visitEnd(); + + cw.visitEnd(); + byte[] bytes = cw.toByteArray(); + + try { + TypeUtils.defineClass(name.replace('/', '.'), bytes, 0, bytes.length, loader, protectionDomain); + // Trigger clinit to invoke the code. Needs no special permissions. + Class.forName(name.replace('/', '.'), true, loader); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + } + + @Override + public byte[] transform( + ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, + byte[] classfileBuffer) throws IllegalClassFormatException { + if (registry.getTransformData(className).isEmpty()) { + return null; + } + + if (classBeingRedefined != null) { + grantJfrAccessToModule(classBeingRedefined.getModule(), loader, className, protectionDomain); + } + + return impl.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer); + } + + @Override + public byte[] transform( + Module module, ClassLoader loader, String className, Class classBeingRedefined, + ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + if (registry.getTransformData(className).isEmpty()) { + return null; + } + + grantJfrAccessToModule(module, loader, className, protectionDomain); + + return impl.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer); + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/jfr/impl/JFRClassVisitor.java b/agent/src/main/java/org/openjdk/jmc/agent/jfr/impl/JFRClassVisitor.java index 67ff2d9be8..9b4827933d 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/jfr/impl/JFRClassVisitor.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/jfr/impl/JFRClassVisitor.java @@ -106,8 +106,14 @@ private void reflectiveRegister(Class generateEventClass) throws Exception { } private Class generateEventClass() throws Exception { - byte[] eventClass = JFREventClassGenerator.generateEventClass(transformDescriptor, inspectionClass); - return TypeUtils.defineClass(transformDescriptor.getEventClassName(), eventClass, 0, eventClass.length, - definingClassLoader, protectionDomain); + try { + // Might have already been defined earlier. + return Class.forName(TypeUtils.getCanonicalName(transformDescriptor.getEventClassName()), false, + definingClassLoader); + } catch (ClassNotFoundException e) { + byte[] eventClass = JFREventClassGenerator.generateEventClass(transformDescriptor, inspectionClass); + return TypeUtils.defineClass(transformDescriptor.getEventClassName(), eventClass, 0, eventClass.length, + definingClassLoader, protectionDomain); + } } } diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationSite.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationSite.java new file mode 100644 index 0000000000..7d1bce9a08 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationSite.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.converters; + +import java.io.PrintStream; +import java.util.Date; + +public class AllocationSite { + public final Exception stack; + public final long timestamp; + public final long size; + + public AllocationSite(long size) { + this.stack = new Exception(); + this.timestamp = System.currentTimeMillis(); + this.size = size; + } + + public boolean printOn(long address, PrintStream ps, AllocationStatisticDumpFilter filter) { + if (size < filter.minStackSize) { + return false; + } + + long age = System.currentTimeMillis() - timestamp; + + if (age > filter.maxAge) { + return false; + } + + if (age < filter.minAge) { + return false; + } + + StackTraceElement[] frames = stack.getStackTrace(); + int framesToSkip = 3; + int maxFrames = Math.min(filter.maxFrames + framesToSkip, frames.length); + + if (filter.mustContain != null) { + boolean matchFound = false; + + for (int i = framesToSkip; i < maxFrames; ++i) { + if (filter.mustContain.matcher(frames[i].toString()).find()) { + matchFound = true; + + break; + } + } + + if (!matchFound) { + return false; + } + } + + if (filter.mustNotContain != null) { + for (int i = framesToSkip; i < maxFrames; ++i) { + if (filter.mustNotContain.matcher(frames[i].toString()).find()) { + return false; + } + } + } + + ps.println("Allocated " + size + " bytes at 0x" + Long.toUnsignedString(address, 16)); + ps.println("Timestamp: " + new Date(timestamp).toString()); + ps.println("Allocated at:"); + + for (int i = framesToSkip; i < maxFrames; ++i) { + ps.println("\t" + frames[i]); + } + + return true; + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatistic.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatistic.java new file mode 100644 index 0000000000..5c117d710d --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatistic.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.converters; + +import java.io.PrintStream; +import java.util.HashMap; +import java.util.Map; + +import org.openjdk.jmc.agent.sap.boot.util.Arguments; +import org.openjdk.jmc.agent.sap.boot.util.LoggingUtils; + +public class AllocationStatistic { + private HashMap activeAllocations = new HashMap<>(); + private long totalSize = 0; + private static long lastDumpSize = 0; + + public AllocationStatistic copy() { + AllocationStatistic result = new AllocationStatistic(); + + synchronized (activeAllocations) { + result.activeAllocations = new HashMap<>(activeAllocations); + result.totalSize = totalSize; + } + + return result; + } + + public void addAllocation(long addr, long size) { + AllocationSite site = new AllocationSite(size); + + synchronized (activeAllocations) { + assert !activeAllocations.containsKey(addr); + totalSize += size; + activeAllocations.put(addr, site); + } + } + + public void removeAllocation(long addr) { + synchronized (activeAllocations) { + assert activeAllocations.containsKey(addr); + AllocationSite site = activeAllocations.remove(addr); + + if (site != null) { + assert totalSize > site.size; + totalSize -= site.size; + } + } + } + + public boolean printActiveAllocations(Arguments args) { + PrintStream ps = LoggingUtils.getStream(args); + AllocationStatisticDumpFilter filter = new AllocationStatisticDumpFilter(args); + + synchronized (AllocationStatistic.class) { + if (totalSize < filter.minSize) { + return false; + } + + if (totalSize < lastDumpSize * filter.minPercentageIncrease) { + return false; + } + + if ((filter.minIncrease >= 0) && (totalSize < lastDumpSize + filter.minIncrease)) { + return false; + } + + long printedSize = 0; + long printedCount = 0; + boolean dumped = false; + + for (Map.Entry entry : activeAllocations.entrySet()) { + if (entry.getValue().printOn(entry.getKey(), ps, filter)) { + printedSize += entry.getValue().size; + printedCount += 1; + } + } + + if (printedCount > 0) { + ps.println("Printed " + printedCount + " of " + activeAllocations.size() + " allocations with " + + printedSize + " bytes (of " + totalSize + " bytes allocated in total)."); + lastDumpSize = totalSize; + dumped = true; + } + + return dumped; + } + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatisticDumpFilter.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatisticDumpFilter.java new file mode 100644 index 0000000000..96dc20bd61 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatisticDumpFilter.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.converters; + +import java.util.regex.Pattern; + +import org.openjdk.jmc.agent.sap.boot.util.Arguments; + +public class AllocationStatisticDumpFilter { + public final int maxFrames; + public final long minSize; + public final long minStackSize; + public final long minIncrease; + public final double minPercentageIncrease; + public final long minAge; + public final long maxAge; + public final Pattern mustContain; + public final Pattern mustNotContain; + + public AllocationStatisticDumpFilter(Arguments args) { + this.maxFrames = args.getInt(UnsafeMemoryAllocationLogger.MAX_FRAMES, 16); + this.minSize = args.getSize(UnsafeMemoryAllocationLogger.MIN_SIZE, 0); + this.minStackSize = args.getSize(UnsafeMemoryAllocationLogger.MIN_STACK_SIZE, 0); + this.minIncrease = args.getSize(UnsafeMemoryAllocationLogger.MIN_INCREASE, -1); + this.minPercentageIncrease = 0.01 * args.getLong(UnsafeMemoryAllocationLogger.MIN_PERCENTAGE, 0); + this.minAge = 1000 * args.getDurationInSeconds(UnsafeMemoryAllocationLogger.MIN_AGE, 0); + this.maxAge = 1000 * args.getDurationInSeconds(UnsafeMemoryAllocationLogger.MAX_AGE, 365 * 24 * 3600); + this.mustContain = args.getPattern(UnsafeMemoryAllocationLogger.MUST_CONTAIN, null); + this.mustNotContain = args.getPattern(UnsafeMemoryAllocationLogger.MUST_NOT_CONTAIN, null); + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/FileOpenCloseLogger.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/FileOpenCloseLogger.java new file mode 100644 index 0000000000..6077dcf8e4 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/FileOpenCloseLogger.java @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.converters; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.regex.Pattern; + +import org.openjdk.jmc.agent.sap.boot.util.Command; +import org.openjdk.jmc.agent.sap.boot.util.Arguments; +import org.openjdk.jmc.agent.sap.boot.util.Dumps; +import org.openjdk.jmc.agent.sap.boot.util.LoggingUtils; + +public class FileOpenCloseLogger { + public static final String MUST_CONTAIN = "mustContain"; + public static final String MUST_NOT_CONTAIN = "mustNotContain"; + public static final Command dumpCommand; + public static final Command command; + + private static HashMap mapping = new HashMap<>(); + private static final ThreadLocal pathKey = new ThreadLocal(); + private static final ThreadLocal modeKey = new ThreadLocal(); + private static final String UNKNOWN_FILE = ""; + + static { + // spotless:off + dumpCommand = new Command( + "openFiles", "Dump the currently files opened by Java code.", + MUST_CONTAIN, "A regexp which must match the file name to be printed.", + MUST_NOT_CONTAIN, "A regexp which must not match the file name to be printed."); + command = new Command(dumpCommand, + "traceOpenFiles", "Traces files opened by Java code.") { + public void preTraceInit() { + Dumps.registerPeriodicDump(command, "Open files", (Arguments args) -> printOpenFiles(args)); + } + }; + // spotless:on + + LoggingUtils.addOptions(command); + Dumps.addOptions(command); + Dumps.registerOnDemandDump(dumpCommand, (Arguments args) -> printOpenFiles(args)); + } + + public static synchronized boolean openFileInputStream(FileInputStream stream) { + if (pathKey.get() != null) { + mapping.put(new Key(stream), new Entry(pathKey.get(), "r", new Exception())); + pathKey.remove(); + } + + return true; + } + + public static synchronized String openFileInputStream(File file) { + String result = file.getAbsolutePath(); + pathKey.set(result); + + return result; + } + + public static synchronized String closeFileInputStream(FileInputStream stream) { + Key key = new Key(stream); + Entry entry = mapping.get(key); + + if (entry != null) { + mapping.remove(key); + + return entry.path; + } + + return UNKNOWN_FILE; + } + + public static synchronized boolean openFileOutputStream(FileOutputStream stream) { + if ((pathKey.get() != null) && (modeKey.get() != null)) { + mapping.put(new Key(stream), new Entry(pathKey.get(), modeKey.get(), new Exception())); + } + + pathKey.remove(); + modeKey.remove(); + + return true; + } + + public static synchronized boolean openFileOutputStream(boolean append) { + modeKey.set(append ? "wa" : "w"); + + return append; + } + + public static synchronized String openFileOutputStream(File file) { + String result = file.getAbsolutePath(); + pathKey.set(result); + + return result; + } + + public static synchronized String closeFileOutputStream(FileOutputStream stream) { + Key key = new Key(stream); + Entry entry = mapping.get(key); + + if (entry != null) { + mapping.remove(key); + + return entry.path; + } + + return UNKNOWN_FILE; + } + + public static synchronized String openRandomAccessFile(File file) { + String result = file.getAbsolutePath(); + pathKey.set(result); + + return result; + } + + public static synchronized String openRandomAccessFile(String file) { + return openRandomAccessFile(new File(file)); + } + + public static synchronized String openRandomAccessFileMode(String mode) { + modeKey.set(mode); + + return mode; + } + + public static synchronized boolean openRandomAccessFile(RandomAccessFile file) { + if ((pathKey.get() != null) && (modeKey.get() != null)) { + mapping.put(new Key(file), new Entry(pathKey.get(), modeKey.get(), new Exception())); + } + + return true; + } + + public static synchronized String closeRandomAccessFile(RandomAccessFile file) { + Key key = new Key(file); + Entry entry = mapping.get(key); + + if (entry != null) { + mapping.remove(key); + + return entry.path; + } + + return UNKNOWN_FILE; + } + + public static boolean printOpenFiles(Arguments args) { + HashMap copy; + + // Make a copy first, since logging might open new files. + synchronized (FileOpenCloseLogger.class) { + copy = new HashMap(mapping); + } + + for (Key key : new ArrayList(copy.keySet())) { + Object obj = key.getObject(); + + // If the ref is dead, remove it from the original map. + if (obj == null) { + synchronized (FileOpenCloseLogger.class) { + mapping.remove(key); + } + // Fall through to remove from copy as well. + } + + boolean remove = true; + + try { + FileDescriptor fd = null; + + if (obj instanceof FileInputStream) { + fd = ((FileInputStream) obj).getFD(); + } else if (obj instanceof FileOutputStream) { + fd = ((FileOutputStream) obj).getFD(); + } else if (obj instanceof RandomAccessFile) { + fd = ((RandomAccessFile) obj).getFD(); + } + + remove = (fd == null) || !fd.valid(); + } catch (IOException e) { + // Remove too. + } + + if (remove) { + copy.remove(key); + } + } + + Pattern mustContain = args.getPattern(MUST_CONTAIN, null); + Pattern mustNotContain = args.getPattern(MUST_NOT_CONTAIN, null); + int printed = 0; + + for (Entry entry : copy.values()) { + if (mustContain != null) { + if (!mustContain.matcher(entry.path).find()) { + continue; + } + } + + if (mustNotContain != null) { + if (mustNotContain.matcher(entry.path).find()) { + continue; + } + } + + LoggingUtils.logWithStack(args, "File '" + entry.path + "', mode '" + entry.mode + "'", entry.stack, 1); + printed += 1; + } + + if (printed > 0) { + LoggingUtils.log(args, "Printed " + printed + " of " + copy.size() + " file(s) currently opened."); + } + + return printed > 0; + } + + private static class Key { + private final WeakReference ref; + private final int hashCode; + + public Key(Object obj) { + ref = new WeakReference(obj); + hashCode = System.identityHashCode(obj); + } + + public Object getObject() { + return ref.get(); + } + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public boolean equals(Object other) { + if (other instanceof Key) { + if (this == other) { + // Needed so we can remove a dead key from the hash map. + return true; + } + + Object thisKey = ref.get(); + Object otherKey = ((Key) other).ref.get(); + + if ((thisKey != null) && (otherKey != null)) { + return thisKey == otherKey; + } + } + + return false; + } + } + + private static class Entry { + public final String path; + public final String mode; + public final Exception stack; + + public Entry(String path, String mode, Exception stack) { + this.path = path; + this.mode = mode; + this.stack = stack; + } + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/GenericLogger.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/GenericLogger.java new file mode 100644 index 0000000000..66f5a9a1a7 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/GenericLogger.java @@ -0,0 +1,1537 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.converters; + +import java.lang.reflect.Array; +import java.nio.CharBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +import org.openjdk.jmc.agent.sap.boot.util.Arguments; +import org.openjdk.jmc.agent.sap.boot.util.ArgumentsHolder; +import org.openjdk.jmc.agent.sap.boot.util.Command; +import org.openjdk.jmc.agent.sap.boot.util.LoggingUtils; + +public class GenericLogger { + + public static final String GENERIC_COMMAND_PREFIX = "logGeneric"; + public static final int MAX_FORMATS = 6; + public static final Command[] commands = new Command[MAX_FORMATS]; + + private static final int DEFAULT_MAX_PRINT_LENGTH = 256; + private static final int DEFAULT_MAX_ARRAY_PRINT_LENGTH = 5; + private static final String ONCE_PER_STACK = "oncePerStack"; + private static final String FORMAT = "format"; + private static final String PRINT_COLLECTION_CONTENT = "printCollectionContent"; + private static final String MAX_PRINT_LENGTH = "maxPrintLength"; + private static final String MAX_ARRAY_PRINT_LENGTH = "maxArrayPrintLength"; + private static final String MAX_LONG = "maxLongValue"; + private static final String MIN_LONG = "minLongValue"; + private static final String MAX_DOUBLE = "maxDoubleValue"; + private static final String MIN_DOUBLE = "minDoubleValue"; + private static final String MIN_LENGTH = "valueMinLength"; + private static final String MAX_LENGTH = "valueMaxLength"; + private static final String EQUALS = "valueEquals"; + private static final String STARTS_WITH = "valueStartsWith"; + private static final String ENDS_WITH = "valueEndsWith"; + private static final String CONTAINS = "valueContains"; + private static final String MATCHES_REGEXP = "valueMatchesRegexp"; + private static final String INSTANCEOF = "valueInstanceof"; + private static final String IS_TYPE = "valueIsType"; + private static final String NOT_EQUALS = "valueNotEquals"; + private static final String NOT_STARTS_WITH = "valueNotStartsWith"; + private static final String NOT_ENDS_WITH = "valueNotEndsWith"; + private static final String NOT_CONTAINS = "valueNotContains"; + private static final String NOT_MATCHES_REGEXP = "valueNotMatchesRegexp"; + private static final String NOT_INSTANCEOF = "valueNotInstanceof"; + private static final String IS_NOT_TYPE = "valueIsNotType"; + private static final ArrayList>> locals = new ArrayList<>(); + private static final int[] parameterIndices = new int[MAX_FORMATS]; + private static final HashSet seenStacks = new HashSet<>(); + private static final ArgumentsHolder[] argsHolder = new ArgumentsHolder[MAX_FORMATS]; + + static { + for (int i = 0; i < MAX_FORMATS; ++i) { + commands[i] = new Command(GENERIC_COMMAND_PREFIX + (i + 1), + "Used to specify the logging options for generic logger " + (i + 1), FORMAT, + "Used to specify the output of the generic logging format " + (i + 1) + ".", ONCE_PER_STACK, + "If true we only log once per unique call stack.", MAX_PRINT_LENGTH, + "The maximum number of characters to print.", MAX_ARRAY_PRINT_LENGTH, + "The maximum number of elements in an array to print.", PRINT_COLLECTION_CONTENT, + "If true we dump part of the contents of a supported Java collection type. " + + "This is disabled by default because of potential multi-threading issues."); + LoggingUtils.addOptionsWithStack(commands[i]); + addFilterOptions(commands[i]); + argsHolder[i] = commands[i].getArguments(); + } + } + + private static StringBuilder sanitize(CharSequence cs) { + StringBuilder sb = new StringBuilder(cs.length()); + + for (int i = 0; i < cs.length(); ++i) { + char c = cs.charAt(i); + + switch (c) { + case '\n': + sb.append("\\n"); + break; + + case '\t': + sb.append("\\t"); + break; + + case '"': + sb.append("\\\""); + break; + + case '\'': + sb.append("\\'"); + break; + + case '\\': + sb.append("\\\\"); + break; + + default: + if (c < 32 || c >= 127) { + sb.append('.'); + } else { + sb.append(c); + } + } + } + + return sb; + } + + private static StringBuilder convertToString(int format, boolean allowInspection, Object o) { + if (o == null) { + return new StringBuilder("null"); + } + + int maxPrintLen = argsHolder[format].get().getInt(MAX_PRINT_LENGTH, DEFAULT_MAX_PRINT_LENGTH); + boolean isCollection = o instanceof Collection || o instanceof Map; + + if (o.getClass().isArray() || (isCollection && allowInspection)) { + int maxArrayLen = argsHolder[format].get().getInt(MAX_ARRAY_PRINT_LENGTH, DEFAULT_MAX_ARRAY_PRINT_LENGTH); + int len; + Iterator it = null; + + StringBuilder sb = new StringBuilder("{"); + boolean success = true; + + if (o.getClass().isArray()) { + len = Array.getLength(o); + } else if (o instanceof Map) { + len = ((Map) o).size(); + it = ((Map) o).entrySet().iterator(); + } else { + len = ((Collection) o).size(); + it = ((Collection) o).iterator(); + } + + for (int i = 0; i < len && i < maxArrayLen; ++i) { + if (i > 0) { + sb.append(", "); + } + + if (o instanceof Collection) { + if (it.hasNext()) { + try { + Object v = it.next(); + sb.append(convertToString(format, allowInspection, v)); + } catch (ConcurrentModificationException | NoSuchElementException e) { + success = false; + break; + } + } + } else if (o instanceof Map) { + if (it.hasNext()) { + try { + Map.Entry v = (Map.Entry) it.next(); + sb.append(convertToString(format, allowInspection, v.getKey()) + ": " + + convertToString(format, allowInspection, v.getValue())); + } catch (ConcurrentModificationException | NoSuchElementException e) { + success = false; + break; + } + } + } else if (o instanceof boolean[]) { + sb.append(Boolean.toString(((boolean[]) o)[i])); + } else if (o instanceof byte[]) { + sb.append(Byte.toString(((byte[]) o)[i])); + } else if (o instanceof short[]) { + sb.append(Short.toString(((short[]) o)[i])); + } else if (o instanceof char[]) { + sb.append("'" + sanitize(Character.toString(((char[]) o)[i])) + "'"); + } else if (o instanceof int[]) { + sb.append(Integer.toString(((int[]) o)[i])); + } else if (o instanceof long[]) { + sb.append(Long.toString(((long[]) o)[i])); + } else if (o instanceof float[]) { + sb.append(Float.toString(((float[]) o)[i])); + } else if (o instanceof double[]) { + sb.append(Double.toString(((double[]) o)[i])); + } else { + Class compType = o.getClass().getComponentType(); + Object oi = ((Object[]) o)[i]; + + if (oi == null) { + sb.append("null"); + } else if (oi.getClass().isArray()) { + int depth = 0; + compType = oi.getClass().getComponentType(); + + while (compType.isArray()) { + depth += 1; + compType = compType.getComponentType(); + } + + sb.append(compType.getName() + "[" + Array.getLength(oi) + "]"); + + for (int j = 0; j < depth; ++j) { + sb.append("[]"); + } + } else { + sb.append(convertToString(format, allowInspection, ((Object[]) o)[i])); + } + } + } + + if (len > maxArrayLen) { + sb.append(", " + (len - maxArrayLen) + " skipped ..."); + } + + sb.append("}"); + + if (success) { + return sb; + } + } + + StringBuilder sb = new StringBuilder(); + + if (isCollection) { + if (o instanceof Collection) { + sb.append(o.getClass().getName() + "(size " + ((Collection) o).size() + ")"); + + return sb; + } + + if (o instanceof Map) { + sb.append(o.getClass().getName() + "(size " + ((Map) o).size() + ")"); + + return sb; + } + } + + if (o instanceof CharSequence) { + StringBuilder cs = sanitize(new StringBuilder((CharSequence) o)); + sb = new StringBuilder(cs.length() + 2); + sb.append('"'); + sb.append(cs); + sb.append('"'); + } else { + sb = new StringBuilder(sanitize(o.toString())); + + if (sb.length() > maxPrintLen) { + return new StringBuilder(sb.substring(0, maxPrintLen)); + } + } + + return sb; + } + + @SuppressWarnings("deprecation") + private static void logValue(Object value, int index, boolean isLast) { + int paramenterIndex; + ArrayList> params; + + synchronized (GenericLogger.class) { + while (index >= locals.size()) { + locals.add(new ArrayList<>()); + } + + params = locals.get(index); + paramenterIndex = parameterIndices[index]++; + + if (isLast) { + parameterIndices[index] = 0; + } + + while (paramenterIndex >= params.size()) { + params.add(new ThreadLocal()); + } + } + + params.get(paramenterIndex).set(value); + + if (isLast) { + Arguments args = argsHolder[index].get(); + + if (args.getBoolean(ONCE_PER_STACK, false)) { + SeenStack stack = new SeenStack(); + + synchronized (GenericLogger.class) { + if (seenStacks.contains(stack)) { + return; + } + + seenStacks.add(stack); + } + } + + Object[] values = new Object[paramenterIndex + 1]; + + for (int i = 0; i <= paramenterIndex; ++i) { + values[i] = params.get(i).get(); + + // Make sure we have a standard format for dates. + if (values[i] instanceof Date) { + values[i] = ((Date) values[i]).toGMTString(); + } + + params.get(i).remove(); + } + + @SuppressWarnings("unchecked") + ArrayList> filters = (ArrayList>) args.getCustomData(); + + if (filters == null) { + filters = new ArrayList<>(values.length); + + for (int i = 0; i < values.length; ++i) { + filters.add(getFilter(args, i + 1)); + } + + args.setCustomData(filters); + } + + for (int i = 0; i < values.length; ++i) { + Predicate filter = filters.get(i); + + if ((filter != null) && !filter.test(values[i])) { + return; + } + } + + StringBuilder sb = new StringBuilder("Values for generic logger " + (index + 1) + ":"); + + for (Object o : values) { + sb.append(' '); + sb.append(convertToString(index, args.getBoolean(PRINT_COLLECTION_CONTENT, false), o)); + } + + LoggingUtils.log(args, sb.toString()); + } + } + + private static void log(boolean v, int index, boolean isLast) { + logValue(Boolean.valueOf(v), index, isLast); + } + + private static void log(byte v, int index, boolean isLast) { + logValue(Byte.valueOf(v), index, isLast); + } + + private static void log(short v, int index, boolean isLast) { + logValue(Short.valueOf(v), index, isLast); + } + + private static void log(char v, int index, boolean isLast) { + logValue(Character.valueOf(v), index, isLast); + } + + private static void log(int v, int index, boolean isLast) { + logValue(Integer.valueOf(v), index, isLast); + } + + private static void log(long v, int index, boolean isLast) { + logValue(Long.valueOf(v), index, isLast); + } + + private static void log(float v, int index, boolean isLast) { + logValue(Float.valueOf(v), index, isLast); + } + + private static void log(double v, int index, boolean isLast) { + logValue(Double.valueOf(v), index, isLast); + } + + private static void log(Object v, int index, boolean isLast) { + logValue(v, index, isLast); + } + + private static String stringify(Object v) { + return v == null ? "null" : v.toString(); + } + + public static boolean logFormat1(boolean v) { + log(v, 0, false); + return v; + } + + public static byte logFormat1(byte v) { + log(v, 0, false); + return v; + } + + public static short logFormat1(short v) { + log(v, 0, false); + return v; + } + + public static char logFormat1(char v) { + log(v, 0, false); + return v; + } + + public static int logFormat1(int v) { + log(v, 0, false); + return v; + } + + public static long logFormat1(long v) { + log(v, 0, false); + return v; + } + + public static float logFormat1(float v) { + log(v, 0, false); + return v; + } + + public static double logFormat1(double v) { + log(v, 0, false); + return v; + } + + public static String logFormat1(Object v) { + log(v, 0, false); + return stringify(v); + } + + public static boolean logLastFormat1(boolean v) { + log(v, 0, true); + return v; + } + + public static byte logLastFormat1(byte v) { + log(v, 0, true); + return v; + } + + public static short logLastFormat1(short v) { + log(v, 0, true); + return v; + } + + public static char logLastFormat1(char v) { + log(v, 0, true); + return v; + } + + public static int logLastFormat1(int v) { + log(v, 0, true); + return v; + } + + public static long logLastFormat1(long v) { + log(v, 0, true); + return v; + } + + public static float logLastFormat1(float v) { + log(v, 0, true); + return v; + } + + public static double logLastFormat1(double v) { + log(v, 0, true); + return v; + } + + public static String logLastFormat1(Object v) { + log(v, 0, true); + return stringify(v); + } + + public static boolean logFormat2(boolean v) { + log(v, 1, false); + return v; + } + + public static byte logFormat2(byte v) { + log(v, 1, false); + return v; + } + + public static short logFormat2(short v) { + log(v, 1, false); + return v; + } + + public static char logFormat2(char v) { + log(v, 1, false); + return v; + } + + public static int logFormat2(int v) { + log(v, 1, false); + return v; + } + + public static long logFormat2(long v) { + log(v, 1, false); + return v; + } + + public static float logFormat2(float v) { + log(v, 1, false); + return v; + } + + public static double logFormat2(double v) { + log(v, 1, false); + return v; + } + + public static String logFormat2(Object v) { + log(v, 1, false); + return stringify(v); + } + + public static boolean logLastFormat2(boolean v) { + log(v, 1, true); + return v; + } + + public static byte logLastFormat2(byte v) { + log(v, 1, true); + return v; + } + + public static short logLastFormat2(short v) { + log(v, 1, true); + return v; + } + + public static char logLastFormat2(char v) { + log(v, 1, true); + return v; + } + + public static int logLastFormat2(int v) { + log(v, 1, true); + return v; + } + + public static long logLastFormat2(long v) { + log(v, 1, true); + return v; + } + + public static float logLastFormat2(float v) { + log(v, 1, true); + return v; + } + + public static double logLastFormat2(double v) { + log(v, 1, true); + return v; + } + + public static String logLastFormat2(Object v) { + log(v, 1, true); + return stringify(v); + } + + public static boolean logFormat3(boolean v) { + log(v, 2, false); + return v; + } + + public static byte logFormat3(byte v) { + log(v, 2, false); + return v; + } + + public static short logFormat3(short v) { + log(v, 2, false); + return v; + } + + public static char logFormat3(char v) { + log(v, 2, false); + return v; + } + + public static int logFormat3(int v) { + log(v, 2, false); + return v; + } + + public static long logFormat3(long v) { + log(v, 2, false); + return v; + } + + public static float logFormat3(float v) { + log(v, 2, false); + return v; + } + + public static double logFormat3(double v) { + log(v, 2, false); + return v; + } + + public static String logFormat3(Object v) { + log(v, 2, false); + return stringify(v); + } + + public static boolean logLastFormat3(boolean v) { + log(v, 2, true); + return v; + } + + public static byte logLastFormat3(byte v) { + log(v, 2, true); + return v; + } + + public static short logLastFormat3(short v) { + log(v, 2, true); + return v; + } + + public static char logLastFormat3(char v) { + log(v, 2, true); + return v; + } + + public static int logLastFormat3(int v) { + log(v, 2, true); + return v; + } + + public static long logLastFormat3(long v) { + log(v, 2, true); + return v; + } + + public static float logLastFormat3(float v) { + log(v, 2, true); + return v; + } + + public static double logLastFormat3(double v) { + log(v, 2, true); + return v; + } + + public static String logLastFormat3(Object v) { + log(v, 2, true); + return stringify(v); + } + + public static boolean logFormat4(boolean v) { + log(v, 3, false); + return v; + } + + public static byte logFormat4(byte v) { + log(v, 3, false); + return v; + } + + public static short logFormat4(short v) { + log(v, 3, false); + return v; + } + + public static char logFormat4(char v) { + log(v, 3, false); + return v; + } + + public static int logFormat4(int v) { + log(v, 3, false); + return v; + } + + public static long logFormat4(long v) { + log(v, 3, false); + return v; + } + + public static float logFormat4(float v) { + log(v, 3, false); + return v; + } + + public static double logFormat4(double v) { + log(v, 3, false); + return v; + } + + public static String logFormat4(Object v) { + log(v, 3, false); + return stringify(v); + } + + public static boolean logLastFormat4(boolean v) { + log(v, 3, true); + return v; + } + + public static byte logLastFormat4(byte v) { + log(v, 3, true); + return v; + } + + public static short logLastFormat4(short v) { + log(v, 3, true); + return v; + } + + public static char logLastFormat4(char v) { + log(v, 3, true); + return v; + } + + public static int logLastFormat4(int v) { + log(v, 3, true); + return v; + } + + public static long logLastFormat4(long v) { + log(v, 3, true); + return v; + } + + public static float logLastFormat4(float v) { + log(v, 3, true); + return v; + } + + public static double logLastFormat4(double v) { + log(v, 3, true); + return v; + } + + public static String logLastFormat4(Object v) { + log(v, 3, true); + return stringify(v); + } + + public static boolean logFormat5(boolean v) { + log(v, 4, false); + return v; + } + + public static byte logFormat5(byte v) { + log(v, 4, false); + return v; + } + + public static short logFormat5(short v) { + log(v, 4, false); + return v; + } + + public static char logFormat5(char v) { + log(v, 4, false); + return v; + } + + public static int logFormat5(int v) { + log(v, 4, false); + return v; + } + + public static long logFormat5(long v) { + log(v, 4, false); + return v; + } + + public static float logFormat5(float v) { + log(v, 4, false); + return v; + } + + public static double logFormat5(double v) { + log(v, 4, false); + return v; + } + + public static String logFormat5(Object v) { + log(v, 4, false); + return stringify(v); + } + + public static boolean logLastFormat5(boolean v) { + log(v, 4, true); + return v; + } + + public static byte logLastFormat5(byte v) { + log(v, 4, true); + return v; + } + + public static short logLastFormat5(short v) { + log(v, 4, true); + return v; + } + + public static char logLastFormat5(char v) { + log(v, 4, true); + return v; + } + + public static int logLastFormat5(int v) { + log(v, 4, true); + return v; + } + + public static long logLastFormat5(long v) { + log(v, 4, true); + return v; + } + + public static float logLastFormat5(float v) { + log(v, 4, true); + return v; + } + + public static double logLastFormat5(double v) { + log(v, 4, true); + return v; + } + + public static String logLastFormat5(Object v) { + log(v, 4, true); + return stringify(v); + } + + public static boolean logFormat6(boolean v) { + log(v, 5, false); + return v; + } + + public static byte logFormat6(byte v) { + log(v, 5, false); + return v; + } + + public static short logFormat6(short v) { + log(v, 5, false); + return v; + } + + public static char logFormat6(char v) { + log(v, 5, false); + return v; + } + + public static int logFormat6(int v) { + log(v, 5, false); + return v; + } + + public static long logFormat6(long v) { + log(v, 5, false); + return v; + } + + public static float logFormat6(float v) { + log(v, 5, false); + return v; + } + + public static double logFormat6(double v) { + log(v, 5, false); + return v; + } + + public static String logFormat6(Object v) { + log(v, 5, false); + return stringify(v); + } + + public static boolean logLastFormat6(boolean v) { + log(v, 5, true); + return v; + } + + public static byte logLastFormat6(byte v) { + log(v, 5, true); + return v; + } + + public static short logLastFormat6(short v) { + log(v, 5, true); + return v; + } + + public static char logLastFormat6(char v) { + log(v, 5, true); + return v; + } + + public static int logLastFormat6(int v) { + log(v, 5, true); + return v; + } + + public static long logLastFormat6(long v) { + log(v, 5, true); + return v; + } + + public static float logLastFormat6(float v) { + log(v, 5, true); + return v; + } + + public static double logLastFormat6(double v) { + log(v, 5, true); + return v; + } + + public static String logLastFormat6(Object v) { + log(v, 5, true); + return stringify(v); + } + + private static void addFilterOptions(Command cmd) { + cmd.addOption(suffixValue(MAX_LONG, ""), "Traces only if value has the given maximum long value."); + cmd.addOption(suffixValue(MIN_LONG, ""), "Traces only if value has the given minimum long value."); + cmd.addOption(suffixValue(MAX_DOUBLE, ""), + "Traces only if value has the given maximum double value."); + cmd.addOption(suffixValue(MIN_DOUBLE, ""), + "Traces only if value has the given minimum double value."); + cmd.addOption(suffixValue(MIN_LENGTH, ""), + "Traces only if array or similar type has the given minimum length."); + cmd.addOption(suffixValue(MAX_LENGTH, ""), + "Traces only if array or similar type has the given minimum length."); + cmd.addOption(suffixValue(EQUALS, ""), "Traces only if value equals the given value."); + cmd.addOption(suffixValue(CONTAINS, ""), + "Traces only if the string representation of value contains the given string."); + cmd.addOption(suffixValue(STARTS_WITH, ""), + "Traces only if the string representation of value starts with the given string."); + cmd.addOption(suffixValue(ENDS_WITH, ""), + "Traces only if the string representation of value ends with the given string."); + cmd.addOption(suffixValue(MATCHES_REGEXP, ""), + "Traces only if the string representation of value matches the given regexp."); + cmd.addOption(suffixValue(INSTANCEOF, ""), + "Traces only if value is a class and is an instance of the given type."); + cmd.addOption(suffixValue(IS_TYPE, ""), + "Traces only if the value is of the given type (null, array, primitive_array or object_array)."); + cmd.addOption(suffixValue(NOT_EQUALS, ""), "Traces only if value does NOT equals the given value."); + cmd.addOption(suffixValue(NOT_CONTAINS, ""), + "Traces only if the string representation of value does NOT contains the given string."); + cmd.addOption(suffixValue(NOT_STARTS_WITH, ""), + "Traces only if the string representation of value does NOT starts with the given string."); + cmd.addOption(suffixValue(NOT_ENDS_WITH, ""), + "Traces only if the string representation of value does NOT ends with the given string."); + cmd.addOption(suffixValue(NOT_MATCHES_REGEXP, ""), + "Traces only if the string representation of value does NOT matches the given regexp."); + cmd.addOption(suffixValue(NOT_INSTANCEOF, ""), + "Traces only if value is a class and is NOT an instance of the given type."); + cmd.addOption(suffixValue(IS_NOT_TYPE, ""), + "Traces only if the value is not of the given type (null, array, primitive_array or object_array)."); + } + + private static String suffixValue(String option, String suffix) { + if (option.startsWith("value")) { + return "value" + suffix + option.substring(5); + } + + int pos = option.indexOf("Value"); + + return option.substring(0, pos) + "Value" + suffix + option.substring(pos + 5); + } + + private static String getValueOption(String option, int idx) { + return suffixValue(option, Integer.toString(idx)); + } + + private static Predicate addPredicate(Predicate predicate, Predicate toAdd) { + if (predicate == null) { + return toAdd; + } else if (toAdd == null) { + return predicate; + } else { + return predicate.and(toAdd); + } + } + + private static Predicate getFilter(Arguments args, int idx) { + Predicate result = null; + String maxLong = getValueOption(MAX_LONG, idx); + String maxDouble = getValueOption(MAX_DOUBLE, idx); + String minLong = getValueOption(MIN_LONG, idx); + String minDouble = getValueOption(MIN_DOUBLE, idx); + String minLength = getValueOption(MIN_LENGTH, idx); + String maxLength = getValueOption(MAX_LENGTH, idx); + String equals = getValueOption(EQUALS, idx); + String startsWith = getValueOption(STARTS_WITH, idx); + String endsWith = getValueOption(ENDS_WITH, idx); + String contains = getValueOption(CONTAINS, idx); + String matchesRegexp = getValueOption(MATCHES_REGEXP, idx); + String instanceOf = getValueOption(INSTANCEOF, idx); + String isType = getValueOption(IS_TYPE, idx); + String notEquals = getValueOption(NOT_EQUALS, idx); + String notStartsWith = getValueOption(NOT_STARTS_WITH, idx); + String notEndsWith = getValueOption(NOT_ENDS_WITH, idx); + String notContains = getValueOption(NOT_CONTAINS, idx); + String notMatchesRegexp = getValueOption(NOT_MATCHES_REGEXP, idx); + String notInstanceOf = getValueOption(NOT_INSTANCEOF, idx); + String isNotType = getValueOption(IS_NOT_TYPE, idx); + + if (args.hasOption(maxLong)) { + result = addPredicate(result, new MaxLongValueFilter(args.getLong(maxLong, 0))); + } + + if (args.hasOption(maxDouble)) { + result = addPredicate(result, new MaxDoubleValueFilter(args.getDouble(maxDouble, 0))); + } + + if (args.hasOption(minLong)) { + result = addPredicate(result, new MinLongValueFilter(args.getLong(minLong, 0))); + } + + if (args.hasOption(minDouble)) { + result = addPredicate(result, new MinDoubleValueFilter(args.getDouble(minDouble, 0))); + } + + if (args.hasOption(minLength)) { + result = addPredicate(result, new MinLengthFilter(args.getInt(minLength, 0))); + } + + if (args.hasOption(maxLength)) { + result = addPredicate(result, new MaxLengthFilter(args.getInt(maxLength, 0))); + } + + if (args.hasOption(equals)) { + result = addPredicate(result, new EqualsValueFilter(args.getString(equals, ""))); + } + + if (args.hasOption(startsWith)) { + result = addPredicate(result, new StartsWithValueFilter(args.getString(startsWith, ""))); + } + + if (args.hasOption(endsWith)) { + result = addPredicate(result, new EndsWithValueFilter(args.getString(endsWith, ""))); + } + + if (args.hasOption(contains)) { + for (String str : args.getStrings(contains)) { + result = addPredicate(result, new ContainsValueFilter(str)); + } + } + + if (args.hasOption(matchesRegexp)) { + for (String str : args.getStrings(matchesRegexp)) { + result = addPredicate(result, new MatchesRegexpValueFilter(str)); + } + } + + if (args.hasOption(instanceOf)) { + for (String str : args.getStrings(instanceOf)) { + result = addPredicate(result, new InstanceofValueFilter(str)); + } + } + + if (args.hasOption(isType)) { + for (String str : args.getStrings(isType)) { + result = addPredicate(result, new IsTypeFilter(str)); + } + } + + if (args.hasOption(notEquals)) { + for (String str : args.getStrings(notEquals)) { + result = addPredicate(result, new EqualsValueFilter(str).negate()); + } + } + + if (args.hasOption(notStartsWith)) { + for (String str : args.getStrings(notStartsWith)) { + result = addPredicate(result, new StartsWithValueFilter(str).negate()); + } + } + + if (args.hasOption(notEndsWith)) { + for (String str : args.getStrings(notEndsWith)) { + result = addPredicate(result, new EndsWithValueFilter(str).negate()); + } + } + + if (args.hasOption(notContains)) { + for (String str : args.getStrings(notContains)) { + result = addPredicate(result, new ContainsValueFilter(str).negate()); + } + } + + if (args.hasOption(notMatchesRegexp)) { + for (String str : args.getStrings(notMatchesRegexp)) { + result = addPredicate(result, new MatchesRegexpValueFilter(str).negate()); + } + } + + if (args.hasOption(notInstanceOf)) { + for (String str : args.getStrings(notInstanceOf)) { + result = addPredicate(result, new InstanceofValueFilter(str).negate()); + } + } + + if (args.hasOption(isNotType)) { + for (String str : args.getStrings(isNotType)) { + result = addPredicate(result, new IsTypeFilter(str).negate()); + } + } + + return result; + } + + private static final class IsTypeFilter implements Predicate { + private final String type; + + public IsTypeFilter(String type) { + this.type = type; + } + + @Override + public boolean test(Object t) { + if (t == null) { + return "null".equals(type); + } + + if (t.getClass().isArray()) { + if ("array".equals(type)) { + return true; + } + + if (t.getClass().getComponentType().isPrimitive()) { + return "primitive_array".equals(type); + } + + return "object_array".equals(type); + } + + return false; + } + } + + private static final class MaxLongValueFilter implements Predicate { + + private final long max; + + MaxLongValueFilter(long max) { + this.max = max; + } + + @Override + public boolean test(Object t) { + // Handle double and float separately, since we want to avoid treating 0.3 <= 0. + if (t instanceof Double) { + return ((Double) t).doubleValue() <= max; + } + + if (t instanceof Float) { + return ((Float) t).floatValue() <= max; + } + + if (t instanceof Number) { + return ((Number) t).longValue() <= max; + } + + if (t instanceof Character) { + return ((Character) t).charValue() <= max; + } + + return false; + } + } + + private static final class MaxDoubleValueFilter implements Predicate { + + private final double max; + + MaxDoubleValueFilter(double max) { + this.max = max; + } + + @Override + public boolean test(Object t) { + if (t instanceof Number) { + return ((Number) t).doubleValue() <= max; + } + + if (t instanceof Character) { + return ((Character) t).charValue() <= max; + } + + return false; + } + } + + private static final class MinLongValueFilter implements Predicate { + + private final long min; + + MinLongValueFilter(long min) { + this.min = min; + } + + @Override + public boolean test(Object t) { + // Handle double and float separately, since we want to avoid treating -0.3 >= 0. + if (t instanceof Double) { + return ((Double) t).doubleValue() >= min; + } + + if (t instanceof Float) { + return ((Float) t).floatValue() >= min; + } + + if (t instanceof Number) { + return ((Number) t).longValue() >= min; + } + + if (t instanceof Character) { + return ((Character) t).charValue() >= min; + } + + return false; + } + } + + private static final class MinDoubleValueFilter implements Predicate { + + private final double min; + + MinDoubleValueFilter(double min) { + this.min = min; + } + + @Override + public boolean test(Object t) { + if (t instanceof Number) { + return ((Number) t).doubleValue() >= min; + } + + if (t instanceof Character) { + return ((Character) t).charValue() >= min; + } + + return false; + } + } + + private static int getLength(Object o) { + if (o == null) { + return -1; + } + + if (o.getClass().isArray()) { + return Array.getLength(o); + } + + // Support some of the common types with lengths. + if (o instanceof CharSequence) { + return ((CharSequence) o).length(); + } + + if (o instanceof Collection) { + return ((Collection) o).size(); + } + + if (o instanceof Map) { + return ((Map) o).size(); + } + + return -1; + } + + private static final class MinLengthFilter implements Predicate { + + private final int min; + + MinLengthFilter(int min) { + this.min = min; + } + + @Override + public boolean test(Object t) { + int len = getLength(t); + + if (len < 0) { + return false; + } + + return len >= min; + } + } + + private static final class MaxLengthFilter implements Predicate { + + private final int max; + + MaxLengthFilter(int max) { + this.max = max; + } + + @Override + public boolean test(Object t) { + int len = getLength(t); + + if (len < 0) { + return false; + } + + return len <= max; + } + } + + private static final class EqualsValueFilter implements Predicate { + + private final String val; + + EqualsValueFilter(String val) { + this.val = val; + } + + @Override + public boolean test(Object t) { + if (t == null) { + return false; + } + + try { + if (t instanceof Number) { + if ((t instanceof Double) || (t instanceof Float)) { + return Double.parseDouble(val) == ((Number) t).doubleValue(); + } else { + return Long.parseLong(val) == ((Number) t).longValue(); + } + } else if (t instanceof CharSequence) { + return val.equals((CharSequence) t); + } else if (t instanceof Class) { + return val.equals(((Class) t).getName()); + } else { + return val.equals(t.toString()); + } + } catch (NumberFormatException e) { + // Ignore and return false. + } + + return false; + } + } + + private static final class StartsWithValueFilter implements Predicate { + + private final String prefix; + + StartsWithValueFilter(String prefix) { + this.prefix = prefix; + } + + @Override + public boolean test(Object t) { + if (t != null) { + if (t instanceof Class) { + return ((Class) t).getName().startsWith(prefix); + } + + if (t instanceof CharBuffer) { + return t.toString().startsWith(prefix); + } + + return t.toString().startsWith(prefix); + } + + return false; + } + } + + private static final class EndsWithValueFilter implements Predicate { + + private final String suffix; + + EndsWithValueFilter(String suffix) { + this.suffix = suffix; + } + + @Override + public boolean test(Object t) { + if (t != null) { + if (t instanceof Class) { + return ((Class) t).getName().endsWith(suffix); + } + + return t.toString().endsWith(suffix); + } + + return false; + } + } + + private static final class ContainsValueFilter implements Predicate { + + private final String part; + + ContainsValueFilter(String part) { + this.part = part; + } + + @Override + public boolean test(Object t) { + if (t != null) { + if (t instanceof Class) { + return ((Class) t).getName().contains(part); + } + + return t.toString().contains(part); + } + + return false; + } + } + + private static final class MatchesRegexpValueFilter implements Predicate { + + private final Pattern pattern; + + MatchesRegexpValueFilter(String pattern) { + this.pattern = Pattern.compile(pattern); + } + + @Override + public boolean test(Object t) { + if (t != null) { + if (t instanceof Class) { + return pattern.matcher(((Class) t).getName()).find(); + } else if (t instanceof CharSequence) { + return pattern.matcher((CharSequence) t).find(); + } + + return pattern.matcher(t.toString()).find(); + } + + return false; + } + } + + private static final class InstanceofValueFilter implements Predicate { + + private final String clazz; + + InstanceofValueFilter(String clazz) { + this.clazz = clazz; + } + + private boolean instanceofImpl(Class base) { + if (base == null) { + return false; + } + + if (base.getName().equals(clazz)) { + return true; + } + + if (instanceofImpl(base.getSuperclass())) { + return true; + } + + for (Class interf : base.getInterfaces()) { + if (instanceofImpl(interf)) { + return true; + } + } + + return false; + } + + @Override + public boolean test(Object t) { + if (t instanceof Class) { + if ("java.lang.Class".equals(clazz)) { + return true; + } + + return instanceofImpl((Class) t); + } else if (t != null) { + return instanceofImpl(t.getClass()); + } + + return false; + } + } + + private static class SeenStack { + private final int hashCode; + private final StackTraceElement[] stack; + + public SeenStack() { + stack = new Throwable().fillInStackTrace().getStackTrace(); + hashCode = Arrays.hashCode(stack); + } + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public boolean equals(Object other) { + if (other instanceof SeenStack) { + SeenStack otherStack = (SeenStack) other; + + if (otherStack.hashCode != hashCode) { + return false; + } + + return Arrays.equals(stack, otherStack.stack); + } + + return false; + } + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/LocaleChangeLogger.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/LocaleChangeLogger.java new file mode 100644 index 0000000000..f278103014 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/LocaleChangeLogger.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.converters; + +import java.util.Locale; + +import org.openjdk.jmc.agent.sap.boot.util.ArgumentsHolder; +import org.openjdk.jmc.agent.sap.boot.util.Command; +import org.openjdk.jmc.agent.sap.boot.util.LoggingUtils; +import org.openjdk.jmc.agent.sap.boot.util.OutputCommand; + +public class LocaleChangeLogger { + + private static final ThreadLocal categoryKey = new ThreadLocal(); + + public static Command command = new OutputCommand("traceLocaleChange", + "Traces when the default locale is changed."); + + private static final ArgumentsHolder holder = command.getArguments(); + + public static String logDefaultLocaleCategoryChange(Locale.Category newCategory) { + assert categoryKey.get() == null; + categoryKey.set(newCategory); + + return newCategory.name(); + } + + public static String logDefaultLocale(Locale.Category newCategory) { + assert categoryKey.get() != null; + + return Locale.getDefault(newCategory).getDisplayName(Locale.ENGLISH); + } + + public static String logDefaultLocalChange(Locale newLocale) { + assert categoryKey.get() != null; + + return newLocale.getDisplayName(Locale.ENGLISH); + } + + public static boolean changesDefaultLocale(Locale newLocale) { + assert categoryKey.get() != null; + Locale oldLocale = Locale.getDefault(categoryKey.get()); + boolean result = !oldLocale.equals(newLocale); + + if (result) { + LoggingUtils.logWithStack(holder.get(), + "Changed default locale for category '" + categoryKey.get().name() + "' from '" + + oldLocale.getDisplayName(Locale.ENGLISH) + "' to '" + + newLocale.getDisplayName(Locale.ENGLISH) + "'.", + 2); + } + + categoryKey.remove(); + + return result; + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/SystemPropChangeLogger.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/SystemPropChangeLogger.java new file mode 100644 index 0000000000..2dbeb0c006 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/SystemPropChangeLogger.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.converters; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Properties; + +import org.openjdk.jmc.agent.sap.boot.util.ArgumentsHolder; +import org.openjdk.jmc.agent.sap.boot.util.Arguments; +import org.openjdk.jmc.agent.sap.boot.util.LoggingUtils; +import org.openjdk.jmc.agent.sap.boot.util.OutputCommand; + +public class SystemPropChangeLogger { + private static final Properties systemProps = AccessController + .doPrivileged((PrivilegedAction) () -> System.getProperties()); + + public static final OutputCommand command = new OutputCommand("traceSysPropsChange", + "Traces changes to the system properties."); + + private static final ArgumentsHolder holder = command.getArguments(); + + private static final ThreadLocal usedKey = new ThreadLocal(); + private static final ThreadLocal usedValue = new ThreadLocal(); + + // This is just used to get the old value in the JFR event too. + public static String logOldValue(Properties props) { + String key = usedKey.get(); + + return props.getProperty(key); + } + + public static boolean logProperties(Properties props) { + Arguments args = holder.get(); + String key = usedKey.get(); + assert key == null; + String val = usedValue.get(); + + usedKey.remove(); + usedValue.remove(); + + if (props == systemProps) { + String oldVal = props.getProperty(key); + + if (val == null) { + LoggingUtils.logWithStack(args, "System properties '" + key + "' with value '" + oldVal + "' removed", + 2); + } else { + LoggingUtils.logWithStack(args, + "System property '" + key + "' changed from '" + oldVal + "' to '" + val + "'", 2); + } + + return true; + } + + return false; + } + + public static String logKey(Object key) { + assert usedKey.get() == null; + + if (key instanceof String) { + usedKey.set((String) key); + + return (String) key; + } + + return ""; + } + + public static String logValue(Object value) { + assert usedValue.get() == null; + + if ((value instanceof String) || (value == null)) { + usedValue.set((String) value); + + return (String) value; + } + + return ""; + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/TimeZoneChangeLogger.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/TimeZoneChangeLogger.java new file mode 100644 index 0000000000..35ed931267 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/TimeZoneChangeLogger.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.converters; + +import java.util.TimeZone; + +import org.openjdk.jmc.agent.sap.boot.util.ArgumentsHolder; +import org.openjdk.jmc.agent.sap.boot.util.Command; +import org.openjdk.jmc.agent.sap.boot.util.LoggingUtils; +import org.openjdk.jmc.agent.sap.boot.util.OutputCommand; + +public class TimeZoneChangeLogger { + + public static Command command = new OutputCommand("traceTimeZoneChange", + "Traces when the default time zone is changed.") { + public void preTraceInit() { + TimeZone.getDefault(); // Trigger loading before we trace to avoid circularity errors. + } + }; + + private static final ArgumentsHolder holder = command.getArguments(); + + public static String logDefaultTimeZoneChange(TimeZone newZone) { + String result = newZone.getDisplayName(); + + // If this doesn't changes the default time zone, don't log it. + if (changesDefaultTimeZone(newZone)) { + LoggingUtils.logWithStack(holder.get(), + "Changed default time zone to " + result + " (" + newZone.toZoneId().toString() + ").", 2); + } + + return result; + } + + public static String logDefaultTimeZoneIdChange(TimeZone newZone) { + return newZone.toZoneId().getId(); + } + + public static String logDefaultTimeZone(TimeZone newZone) { + return TimeZone.getDefault().getDisplayName(); + } + + public static String logDefaultTimeZoneId(TimeZone newZone) { + return TimeZone.getDefault().toZoneId().getId(); + } + + public static boolean changesDefaultTimeZone(TimeZone newZone) { + return !newZone.toZoneId().equals(TimeZone.getDefault().toZoneId()); + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/UnsafeMemoryAllocationLogger.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/UnsafeMemoryAllocationLogger.java new file mode 100644 index 0000000000..e6795f96a2 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/UnsafeMemoryAllocationLogger.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.converters; + +import org.openjdk.jmc.agent.sap.boot.util.ArgumentsHolder; +import org.openjdk.jmc.agent.sap.boot.util.Command; +import org.openjdk.jmc.agent.sap.boot.util.Arguments; +import org.openjdk.jmc.agent.sap.boot.util.Dumps; +import org.openjdk.jmc.agent.sap.boot.util.LoggingUtils; + +public class UnsafeMemoryAllocationLogger { + public static final String MAX_FRAMES = "maxFrames"; + public static final String MIN_STACK_SIZE = "minStackSize"; + public static final String MIN_SIZE = "minSize"; + public static final String MIN_INCREASE = "minIncrease"; + public static final String MIN_PERCENTAGE = "minPercentage"; + public static final String MIN_AGE = "minAge"; + public static final String MAX_AGE = "maxAge"; + public static final String MUST_CONTAIN = "mustContain"; + public static final String MUST_NOT_CONTAIN = "mustNotContain"; + public static final Command dumpCommand; + public static final Command command; + + private static final ThreadLocal sizeKey = new ThreadLocal(); + private static final ThreadLocal ptrKey = new ThreadLocal(); + private static final AllocationStatistic allocations = new AllocationStatistic(); + private static final ArgumentsHolder holder; + + static { + // spotless:off + dumpCommand = new Command( + "unsafeAllocations", "Dump the currently active jdk.internal.misc.Unsafe allocatios.", + MAX_FRAMES, "The maximum number of frame to use for stack traces.", + MIN_SIZE, "The minimum size of the live allocations to dump the result.", + MIN_STACK_SIZE, "The minimum size of a stack to be included in a dump.", + MIN_PERCENTAGE, "The minimum percentage compared to the last dump to print a dump.", + MIN_AGE, "The minimum age in minutes to include an allocation in the output.", + MAX_AGE, "The maximum age in minutes to include an allocation in the output.", + MUST_CONTAIN, "A regexp which must match at least one frame to be printed.", + MUST_NOT_CONTAIN, "A regexp which must not match any frame to be printed."); + command = new Command(dumpCommand, + "traceUnsafeAllocations", "Traces native memory allocation by jdk.internal.misc.Unsafe") { + public void preTraceInit() { + Dumps.registerPeriodicDump(command, "Unsafe native memory allocation", + (Arguments args) -> printActiveAllocations(args)); + } + }; + // spotless:on + + LoggingUtils.addOptions(command); + Dumps.addOptions(command); + Dumps.registerOnDemandDump(dumpCommand, (Arguments args) -> printActiveAllocations(args)); + holder = command.getArguments(); + } + + public static long logSize(long size) { + assert sizeKey.get() == null; + sizeKey.set(size); + + return size; + } + + public static long logPtr(long ptr) { + assert ptrKey.get() == null; + assert sizeKey.get() != null; + ptrKey.set(ptr); + + return ptr; + } + + public static long logResult(long result) { + Long toAdd = Long.valueOf(result); + Long oldPtr = ptrKey.get(); + + if ((oldPtr != null) && (oldPtr.longValue() != 0)) { + // This is realloc. + Long newSize = sizeKey.get(); + + if (newSize != null) { + allocations.removeAllocation(oldPtr); + + // Realloc with size 0 is a free. + if (newSize > 0) { + allocations.addAllocation(toAdd, newSize); + } + } + } else { + // This is malloc. + Long size = sizeKey.get(); + + if (size != null) { + allocations.addAllocation(toAdd, size); + } + } + + sizeKey.remove(); + ptrKey.remove(); + + return result; + } + + public static long logFree(long ptr) { + assert sizeKey.get() == null; + assert ptrKey.get() == null; + + Long toRemove = Long.valueOf(ptr); + + if (toRemove != null) { + allocations.removeAllocation(toRemove); + } + + return ptr; + } + + public static boolean printActiveAllocations() { + return printActiveAllocations(holder.get()); + } + + public static boolean printActiveAllocations(Arguments args) { + if (LoggingUtils.doesOutput(args)) { + return allocations.copy().printActiveAllocations(args); + } + + return false; + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Arguments.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Arguments.java new file mode 100644 index 0000000000..e26c104d14 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Arguments.java @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.util; + +import java.util.HashMap; +import java.util.regex.Pattern; + +public class Arguments { + + private final HashMap args; + private final Command command; + private volatile Object customData; + + Arguments(String optionsLine) { + this.command = null; + this.args = getOptions(optionsLine); + } + + Arguments(String line, Command command) { + this.command = command; + this.args = getOptions(line); + } + + public Command getCommand() { + return command; + } + + public Object getCustomData() { + return customData; + } + + public void setCustomData(Object customData) { + this.customData = customData; + } + + public boolean hasOption(String option) { + return args.containsKey(option); + } + + public boolean hasHelpOption() { + return args.containsKey("help"); + } + + public String getString(String option, String defaultResult) { + if (args.containsKey(option)) { + String[] opts = args.get(option); + + if (opts.length == 0) { + return null; + } + + if (opts.length == 1) { + return opts[0]; + } + + reportOptionError(option, "Found " + opts.length + " values for option. Expected only one."); + } + + return defaultResult; + } + + public String[] getStrings(String option) { + if (args.containsKey(option)) { + return args.get(option); + } + + return new String[0]; + } + + public boolean getBoolean(String option, boolean defaultResult) { + if (args.containsKey(option)) { + return Boolean.parseBoolean(getString(option, "")); + } + + return defaultResult; + } + + public Pattern getPattern(String option, Pattern defaultResult) { + if (args.containsKey(option)) { + return Pattern.compile(getString(option, "")); + } + + return defaultResult; + } + + public int getInt(String option, int defaultRersult) { + if (args.containsKey(option)) { + try { + return Integer.parseInt(getString(option, "")); + } catch (NumberFormatException e) { + reportOptionError(option, "Could not parse integer value"); + } + } + + return defaultRersult; + } + + public String getUnknownArgument() { + for (String key : args.keySet()) { + if (!command.hasOption(key)) { + return key; + } + } + + return null; + } + + public long getLong(String option, long defaultRersult) { + if (args.containsKey(option)) { + try { + return Long.parseLong(getString(option, "")); + } catch (NumberFormatException e) { + reportOptionError(option, "Could not parse integer value"); + } + } + + return defaultRersult; + } + + public double getDouble(String option, double defaultRersult) { + if (args.containsKey(option)) { + try { + return Double.parseDouble(getString(option, "")); + } catch (NumberFormatException e) { + reportOptionError(option, "Could not parse floating point value"); + } + } + + return defaultRersult; + } + + private long parseUnits(String option, long defaultRersult, char[] suffixes, long[] scale) { + if (!args.containsKey(option)) { + return defaultRersult; + } + + String rest = getString(option, ""); + long result = 0; + + while (!rest.isEmpty()) { + long part = 0; + boolean isNeg = false; + + if (rest.startsWith("-")) { + isNeg = true; + rest = rest.substring(1); + } + + while (!rest.isEmpty()) { + int c = rest.charAt(0); + + if ((c < '0') || (c > '9')) { + break; + } + + part = part * 10 + (c - '0'); + rest = rest.substring(1); + } + + if (rest.isEmpty()) { + result += part * (isNeg ? -1 : 1); + break; + } + + boolean found = false; + + for (int i = 0; i < suffixes.length; ++i) { + if (rest.charAt(0) == suffixes[i]) { + result += part * scale[i] * (isNeg ? -1 : 1); + found = true; + break; + } + } + + if (!found) { + reportOptionError(option, "Unknown unit '" + rest.charAt(0) + "'."); + } + + rest = rest.substring(1); + } + + return result; + } + + public long getSize(String option, long defaultRersult) { + return parseUnits(option, defaultRersult, new char[] {'k', 'M', 'G'}, + new long[] {1024, 1024 * 1024, 1024 * 1024 * 1024}); + } + + public long getDurationInSeconds(String option, long defaultRersult) { + return parseUnits(option, defaultRersult, new char[] {'s', 'm', 'h', 'd'}, new long[] {1, 60, 3600, 3600 * 24}); + } + + private static String dequote(String str) { + StringBuilder result = new StringBuilder(); + + for (int i = 0; i < str.length(); ++i) { + char c = str.charAt(i); + + if (c == '\\') { + if (i + 1 < str.length()) { + result.append(str.charAt(i + 1)); + i += 1; + } else { + // Trailing backslash is treated just as a backslash. + result.append(c); + } + } else { + result.append(c); + } + } + + return result.toString(); + } + + private static HashMap getOptions(String line) { + HashMap result = new HashMap<>(); + String[] keysAndValues = line.split("(? 0) { + String[] parts = keyAndValue.split("(? 0) { + String key = dequote(parts[0]); + + if (parts.length > 1) { + String[] oldOpts = result.containsKey(key) ? result.get(key) : new String[0]; + String[] newOpts = new String[oldOpts.length + 1]; + System.arraycopy(oldOpts, 0, newOpts, 0, oldOpts.length); + newOpts[oldOpts.length] = dequote(parts[1]); + result.put(key, newOpts); + } + } + } + } + + return result; + } + + private void reportOptionError(String option, String msg) { + System.err.println("Error in option " + option + "=" + getString(option, "") + " for command '" + + command.getName() + "'"); + System.err.println(msg); + System.exit(1); + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/ArgumentsHolder.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/ArgumentsHolder.java new file mode 100644 index 0000000000..50243b4b74 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/ArgumentsHolder.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.util; + +public class ArgumentsHolder { + + private volatile Arguments args; + + public ArgumentsHolder(Arguments args) { + this.args = args; + } + + public void set(Arguments args) { + this.args = args; + } + + public Arguments get() { + return args; + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Command.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Command.java new file mode 100644 index 0000000000..cbc682d196 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Command.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.util; + +import java.io.PrintStream; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Objects; + +public class Command { + private final String name; + private final String description; + private final HashMap optionsWithHelp; + public static final HashMap holders = new HashMap<>(); + + public Command(String name, String description, String ... optionsWithHelp) { + this.name = name; + this.description = description; + this.optionsWithHelp = new HashMap<>(); + + for (int i = 0; i < optionsWithHelp.length; i += 2) { + this.optionsWithHelp.put(optionsWithHelp[i], optionsWithHelp[i + 1]); + } + } + + public Command(Command parentCommand, String name, String description, String ... optionsWithHelp) { + this.name = name; + this.description = description; + this.optionsWithHelp = new HashMap<>(parentCommand.optionsWithHelp); + + for (int i = 0; i < optionsWithHelp.length; i += 2) { + this.optionsWithHelp.put(optionsWithHelp[i], optionsWithHelp[i + 1]); + } + } + + public void addOption(String option, String description) { + optionsWithHelp.put(option, description); + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public String[] getOptions() { + return optionsWithHelp.keySet().toArray(new String[optionsWithHelp.size()]); + } + + public boolean hasOption(String name) { + if (optionsWithHelp.containsKey(name)) { + return true; + } + + for (String option : optionsWithHelp.keySet()) { + if (option.contains("")) { + if (name.matches(option.replace("", "[0-9]+"))) { + return true; + } + } + } + + return false; + } + + public String getOptionHelp(String name) { + return optionsWithHelp.get(name); + } + + public void preTraceInit() { + // Nothing to do by default + } + + public void addCommandArgs(String options) { + Arguments args = new Arguments(options, this); + boolean seenFirst = false; + + synchronized (Command.class) { + ArgumentsHolder holder = holders.get(name); + + if (holder == null) { + holder = new ArgumentsHolder(args); + holders.put(name, holder); + seenFirst = true; + } else { + if (holder.get() == null) { + seenFirst = true; + } + + holder.set(args); + } + } + + if (seenFirst) { + preTraceInit(); + } + } + + public ArgumentsHolder getArguments() { + synchronized (Command.class) { + ArgumentsHolder holder = holders.get(name); + + if (holder == null) { + holder = new ArgumentsHolder(null); + holders.put(name, holder); + } + + return holder; + } + } + + public void printHelp(PrintStream str) { + str.println("Help for command '" + getName() + "':"); + str.println("Description: " + getDescription()); + String[] options = getOptions(); + Arrays.sort(options, String.CASE_INSENSITIVE_ORDER); + + if (options.length > 0) { + str.println(); + str.println("The following options are supported:"); + + for (String option : options) { + str.println(option + ": " + getOptionHelp(option)); + } + + str.println(); + str.println("In order to specify options, add them separated by commas after the command:"); + str.println(getName() + "[,[,,help to get further help for a specific command."); + } + + public static Command getCommand(String name) { + for (Command command : commands) { + if (command.getName().equals(name)) { + return command; + } + } + + return null; + } + + public static boolean checkCommands() { + for (Command command : commands) { + ArgumentsHolder holder = command.getArguments(); + + if (holder.get() == null) { + continue; // No arguments. + } + + Arguments args = holder.get(); + + if (args.hasHelpOption()) { + printHelp(command); + + return false; + } + + String unknownArgument = args.getUnknownArgument(); + + if (unknownArgument != null) { + // spotless:off + System.err.println("Unknown argument '" + unknownArgument + "' for command '" + command.getName() + "'."); + // spotless:on + printHelp(command); + + return false; + } + } + + return true; + } + + private static void printHelp(Command command) { + command.printHelp(System.err); + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Dumps.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Dumps.java new file mode 100644 index 0000000000..0922e74603 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Dumps.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.util; + +import java.io.IOException; +import java.util.HashMap; +import java.util.function.Predicate; + +public class Dumps { + public static final String DUMP_COUNT = "dumpCount"; + public static final String DUMP_INTERVAL = "dumpInterval"; + public static final String DUMP_DELAY = "dumpDelay"; + public static final String EXIT_AFTER_LAST_DUMP = "exitAfterLastDump"; + + private static final HashMap> registeredDumps = new HashMap<>(); + + public static void performDump(String arguments) throws IOException { + if (arguments.equals("help")) { + System.out.println("The following dumps are supported:"); + + for (Command cmd : registeredDumps.keySet()) { + if (registeredDumps.get(cmd) != null) { + System.out.println(cmd.getName() + ": " + cmd.getDescription()); + } + } + + System.out.println("Use dump=help: for all options for a specific dump."); + return; + } else if (arguments.startsWith("help:")) { + String name = arguments.substring(5); + + for (Command cmd : registeredDumps.keySet()) { + if (cmd.getName().equals(name)) { + cmd.printHelp(System.out); + return; + } + } + + System.err.println("Could not find dump type '" + name + "'. Use dump=help for a list of supported types."); + return; + } + + String[] parts = arguments.split(","); + String type = parts[0]; + + if (parts.length > 1) { + arguments = arguments.substring(type.length() + 1); + } else { + arguments = ""; + } + + Arguments args = new Arguments(arguments); + Predicate callback = null; + + synchronized (Dumps.class) { + callback = registeredDumps.get(new Command(type, "")); + } + + if (callback == null) { + System.err.println("No dump registered for dump type '" + type + "'"); + return; + } + + callback.test(args); + } + + public static void registerPeriodicDump(Command command, String name, Predicate callback) { + Arguments args = command.getArguments().get(); + long dumpCount = args.getLong(DUMP_COUNT, 0); + + if (dumpCount != 0) { + long interval = args.getDurationInSeconds(DUMP_INTERVAL, 3600); + long delay = args.getDurationInSeconds(DUMP_DELAY, interval); + boolean exitAfterLastDump = args.getBoolean(EXIT_AFTER_LAST_DUMP, false); + + Thread t = new Thread(new Runnable() { + + @Override + public void run() { + try { + Thread.sleep(delay * 1000); + + long dumpsLeft = dumpCount; + + while (dumpsLeft > 0) { + if (callback.test(args)) { + dumpsLeft -= 1; + LoggingUtils.log(args, + name + " dump " + (dumpCount - dumpsLeft) + " of " + dumpCount + "."); + } + + if (dumpsLeft > 0) { + Thread.sleep(interval * 1000); + } + } + + if (exitAfterLastDump) { + LoggingUtils.log(args, name + " dumps finished. Exiting VM."); + System.exit(0); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }, "Dumper Thread"); + + t.setDaemon(true); + t.start(); + } + } + + public static void registerOnDemandDump(Command command, Predicate callback) { + synchronized (Dumps.class) { + registeredDumps.put(command, callback); + } + } + + public static void addOptions(Command command) { + command.addOption(DUMP_COUNT, "The maximum number of dumps to perform."); + command.addOption(DUMP_INTERVAL, + "The interval between successive dumps. Supports s, m, h and d (e.g. 10s or 6m)."); + command.addOption(DUMP_DELAY, "The delay until the first dump is triggered. Supports s, m, h and d."); + command.addOption(EXIT_AFTER_LAST_DUMP, "If true, the VM will be exited after the last dump is triggered."); + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/LoggingUtils.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/LoggingUtils.java new file mode 100644 index 0000000000..011a5963b4 --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/LoggingUtils.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.util; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.Formatter; +import java.util.HashMap; +import java.util.IdentityHashMap; + +public class LoggingUtils { + public static final String LOG_DEST = "logDest"; + public static final String LOG_WITH_STACK = "logWithStack"; + private static HashMap outputs = new HashMap<>(); + private static IdentityHashMap formatters = new IdentityHashMap<>(); + + public static void addOptions(Command command) { + command.addOption(LOG_DEST, + "Specifies the output destination. Can be 'stdout', 'stderr', 'none' or a file name. " + + "Prepend the filename with a '+' to append to the file instead of overwriting it."); + command.addOption(LOG_WITH_STACK, "If not false, print a stack trace for every log output."); + } + + public static void addOptionsWithStack(Command command) { + addOptions(command); + command.addOption(LOG_WITH_STACK, "Print a stack trace for every log output."); + } + + public static boolean doesOutput(Arguments args) { + return !"none".equals(args.getString(LOG_DEST, "stderr")); + } + + public static Formatter getFormatter(Arguments args) { + PrintStream stream = getStream(args); + Formatter formatter; + + synchronized (formatters) { + formatter = formatters.get(stream); + + if (formatter == null) { + formatter = new Formatter(stream); + formatters.put(stream, formatter); + } + } + + return formatter; + } + + public static PrintStream getStream(Arguments args) { + String dest = args.getString(LOG_DEST, "stderr"); + + if ("none".equals(dest)) { + return new PrintStream(new OutputStream() { + + @Override + public void write(byte[] b) throws IOException { + // Just throw everything away. + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + // Just throw everything away. + } + + @Override + public void write(int b) throws IOException { + // Just throw everything away. + } + }); + } + + if ("stdout".equals(dest)) { + return System.out; + } + + if ("stderr".equals(dest)) { + return System.err; + } + + synchronized (outputs) { + PrintStream result = outputs.get(dest); + + if (result != null) { + return result; + } + + try { + if (dest.startsWith("+")) { + // Append if the file name starts with a +. + result = new PrintStream(new FileOutputStream(dest.substring(1), true), true); + } else { + result = new PrintStream(new FileOutputStream(dest, false), true); + } + } catch (FileNotFoundException e) { + System.err.println("Could not open file '" + dest + "' for output. Using stderr instead."); + // Don't try this again. + result = System.err; + } + + outputs.put(dest, result); + return result; + } + } + + public static void log(Arguments args, String msg) { + getStream(args).println(msg); + + if (args.getBoolean(LOG_WITH_STACK, false)) { + logCurrentStack(args, 1); + } + } + + public static void log(Arguments args, Object[] parts) { + PrintStream stream = getStream(args); + + for (Object part : parts) { + stream.print(part); + } + } + + public static void logWithFormat(Arguments args, String format, Object[] values) { + Formatter formatter = getFormatter(args); + formatter.format(format + "\n", values); + + if (args.getBoolean(LOG_WITH_STACK, false)) { + logCurrentStack(args, 1); + } + } + + private static void logCurrentStack(Arguments args, int toSkip) { + logWithStack(args, "", new Exception(), toSkip); + } + + public static void logWithStack(Arguments args, String msg, int toSkip) { + logWithStack(args, msg, new Exception(), toSkip); + } + + public static void logWithStack(Arguments args, String msg, Exception stack, int toSkip) { + PrintStream stream = getStream(args); + + if (msg.length() > 0) { + stream.println(msg); + } + + if (args.getBoolean(LOG_WITH_STACK, true)) { + StackTraceElement[] frames = stack.getStackTrace(); + + for (int i = toSkip; i < frames.length; ++i) { + stream.println("\t" + frames[i]); + } + } + } +} diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/OutputCommand.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/OutputCommand.java new file mode 100644 index 0000000000..38a2fca9ca --- /dev/null +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/OutputCommand.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.boot.util; + +public class OutputCommand extends Command { + + public OutputCommand(String name, String description) { + super(name, description); + LoggingUtils.addOptions(this); + } +} diff --git a/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceLocaleChange.xml b/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceLocaleChange.xml new file mode 100644 index 0000000000..feb8433b9e --- /dev/null +++ b/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceLocaleChange.xml @@ -0,0 +1,43 @@ + + + __JFREvent + false + true + + + + + Change of the default locale + java.util.Locale + true + false + jdk/log/locale/changed + + setDefault + (Ljava/util/Locale$Category;Ljava/util/Locale;)V + + + newCategory + The category of the new locale + org.openjdk.jmc.agent.sap.boot.converters.LocaleChangeLogger.logDefaultLocaleCategoryChange()V + + + oldLocale + The current locale for the category + org.openjdk.jmc.agent.sap.boot.converters.LocaleChangeLogger.logDefaultLocale()V + + + newLocale + The new default locale + org.openjdk.jmc.agent.sap.boot.converters.LocaleChangeLogger.logDefaultLocalChange()V + + + hasLocaleChanged + Has the locale for the category really changed + org.openjdk.jmc.agent.sap.boot.converters.LocaleChangeLogger.changesDefaultLocale()V + + + + + + diff --git a/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceOpenFiles.xml b/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceOpenFiles.xml new file mode 100644 index 0000000000..cbdce0044c --- /dev/null +++ b/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceOpenFiles.xml @@ -0,0 +1,166 @@ + + + __JFREvent + false + true + + + + + Traces the FileInputStream constructor taking a File + java.io.FileInputStream + true + false + EXIT + jdk/log/file/statistic + + FileInputStream + (Ljava/io/File;)V + + + fileName + The file name + org.openjdk.jmc.agent.sap.boot.converters.FileOpenCloseLogger.openFileInputStream()V + + + + + + hasOpened + this + has the file been opened + org.openjdk.jmc.agent.sap.boot.converters.FileOpenCloseLogger.openFileInputStream()V + + + + + + Traces the FileInputStream close calls + java.io.FileInputStream + true + false + ENTRY + jdk/log/file/statistic + + close + ()V + + + + closedFile + this + The closed file + org.openjdk.jmc.agent.sap.boot.converters.FileOpenCloseLogger.closeFileInputStream()V + + + + + + Traces the FileOutputStream constructor taking a File + java.io.FileOutputStream + true + false + EXIT + jdk/log/file/statistic + + FileOutputStream + (Ljava/io/File;Z)V + + + fileName + The file name + org.openjdk.jmc.agent.sap.boot.converters.FileOpenCloseLogger.openFileOutputStream()V + + + append + The append flag + org.openjdk.jmc.agent.sap.boot.converters.FileOpenCloseLogger.openFileOutputStream()V + + + + + + hasOpened + this + has the file been opened + org.openjdk.jmc.agent.sap.boot.converters.FileOpenCloseLogger.openFileOutputStream()V + + + + + + Traces the FileOutputStream close calls + java.io.FileOutputStream + true + false + ENTRY + jdk/log/file/statistic + + close + ()V + + + + closedFile + this + The closed file + org.openjdk.jmc.agent.sap.boot.converters.FileOpenCloseLogger.closeFileOutputStream()V + + + + + + Traces the RandomAccessFile constructor taking a File + java.io.RandomAccessFile + true + false + EXIT + jdk/log/file/statistic + + RandomAccessFile + (Ljava/io/File;Ljava/lang/String;)V + + + fileName + The file name + org.openjdk.jmc.agent.sap.boot.converters.FileOpenCloseLogger.openRandomAccessFile()V + + + mode + The file mode + org.openjdk.jmc.agent.sap.boot.converters.FileOpenCloseLogger.openRandomAccessFileMode()V + + + + + + hasOpened + this + has the file been opened + org.openjdk.jmc.agent.sap.boot.converters.FileOpenCloseLogger.openRandomAccessFile()V + + + + + + Traces the RandomAccessFile close call + java.io.RandomAccessFile + true + false + EXIT + jdk/log/file/statistic + + close + ()V + + + + closedFile + this + The closed file + org.openjdk.jmc.agent.sap.boot.converters.FileOpenCloseLogger.closeRandomAccessFile()V + + + + + diff --git a/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceSysPropsChange.xml b/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceSysPropsChange.xml new file mode 100644 index 0000000000..64fd0297be --- /dev/null +++ b/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceSysPropsChange.xml @@ -0,0 +1,80 @@ + + + __JFREvent + false + true + + + + + Change of system property + java.util.Properties + true + false + jdk/log/sysProps/changed + + put + (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + + + key + The key + org.openjdk.jmc.agent.sap.boot.converters.SystemPropChangeLogger.logKey()V + + + value + The changed value + org.openjdk.jmc.agent.sap.boot.converters.SystemPropChangeLogger.logValue()V + + + + + + oldValue + this + The old value + org.openjdk.jmc.agent.sap.boot.converters.SystemPropChangeLogger.logOldValue()V + + + isSystemProperty + this + Is this change for a System property + org.openjdk.jmc.agent.sap.boot.converters.SystemPropChangeLogger.logProperties()V + + + + + + Removing of system property + java.util.Properties + true + false + jdk/log/sysProps/changed + + remove + (Ljava/lang/Object;)Ljava/lang/Object; + + + key + The key + org.openjdk.jmc.agent.sap.boot.converters.SystemPropChangeLogger.logKey()V + + + + + + removedValue + this + The value of the removed property + org.openjdk.jmc.agent.sap.boot.converters.SystemPropChangeLogger.logOldValue()V + + + isSystemProperty + this + Is this change for a System property + org.openjdk.jmc.agent.sap.boot.converters.SystemPropChangeLogger.logProperties()V + + + + + diff --git a/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceTimeZoneChange.xml b/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceTimeZoneChange.xml new file mode 100644 index 0000000000..d9b64d17fc --- /dev/null +++ b/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceTimeZoneChange.xml @@ -0,0 +1,48 @@ + + + __JFREvent + false + true + + + + + Change of the default time zone + java.util.TimeZone + true + false + jdk/log/timeZone/changed + + setDefault + (Ljava/util/TimeZone;)V + + + newTimeZone + The new default time zone + org.openjdk.jmc.agent.sap.boot.converters.TimeZoneChangeLogger.logDefaultTimeZoneChange()V + + + newTimeZoneId + The new default time zone id + org.openjdk.jmc.agent.sap.boot.converters.TimeZoneChangeLogger.logDefaultTimeZoneIdChange()V + + + oldTimeZone + The old default time zone + org.openjdk.jmc.agent.sap.boot.converters.TimeZoneChangeLogger.logDefaultTimeZone()V + + + oldTimeZoneId + The old default time zone id + org.openjdk.jmc.agent.sap.boot.converters.TimeZoneChangeLogger.logDefaultTimeZoneId()V + + + changesDefault + Does this changes the default time zone, because it's not already the default + org.openjdk.jmc.agent.sap.boot.converters.TimeZoneChangeLogger.changesDefaultTimeZone()V + + + + + + diff --git a/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceUnsafeAllocations.xml b/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceUnsafeAllocations.xml new file mode 100644 index 0000000000..bacccb255d --- /dev/null +++ b/agent/src/main/resources/org/openjdk/jmc/agent/sap/traceUnsafeAllocations.xml @@ -0,0 +1,81 @@ + + + __JFREvent + false + true + + + + + Memory trace of Unsafe allocations + jdk.internal.misc.Unsafe + true + false + jdk/log/Unsafe/memoryTrace + + allocateMemory + (J)J + + + size + The allocated size + org.openjdk.jmc.agent.sap.boot.converters.UnsafeMemoryAllocationLogger.logSize(J)J + + + + address + the allocated address + org.openjdk.jmc.agent.sap.boot.converters.UnsafeMemoryAllocationLogger.logResult(J)J + + + + + + Memory trace of Unsafe reallocations + jdk.internal.misc.Unsafe + true + false + jdk/log/Unsafe/memoryTrace + + reallocateMemory + (JJ)J + + + oldAddress + The old memory address + org.openjdk.jmc.agent.sap.boot.converters.UnsafeMemoryAllocationLogger.logPtr()V + + + size + The new allocated size + org.openjdk.jmc.agent.sap.boot.converters.UnsafeMemoryAllocationLogger.logSize()V + + + + address + the allocated address + org.openjdk.jmc.agent.sap.boot.converters.UnsafeMemoryAllocationLogger.logResult()V + + + + + + Memory trace of Unsafe frees + jdk.internal.misc.Unsafe + true + false + jdk/log/Unsafe/memoryTrace + + freeMemory + (J)V + + + address + The freed memory address + org.openjdk.jmc.agent.sap.boot.converters.UnsafeMemoryAllocationLogger.logFree()V + + + + + + diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/CloneClassLoader.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/CloneClassLoader.java new file mode 100644 index 0000000000..7631385c57 --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/CloneClassLoader.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.security.SecureClassLoader; +import java.util.Arrays; +import java.util.HashSet; + +/** + * This is a class loader which can load the same classes as another class loader. + *

+ * This is mainly useful for tests when you want to load a class, but do it with a class loader you + * can dispose. The clone loader just asks the loader to be cloned to get the bytecodes, but defines + * the class itself. + *

+ * Additionally you can specify a set of classes the loader should not be able to load. + * + * @author Ralf Schmelter + */ +public class CloneClassLoader extends SecureClassLoader { + + /** + * The class loaded to clone. + */ + private final ClassLoader toClone; + + /** + * The strings we cannot load. + */ + private final HashSet notLoadable; + + /** + * The strings we just delegate. + */ + private final HashSet simpleDelegate; + + /** + * Creates a class loader which can load the same classes as the loader which loaded the + * CloneClassLoader class itself. + *

+ * Only the bootstrap classes are delegated to the bootstrap class loader. + * + * @param toClone + * the class loader to mimic. The clone class loader will be able to load the same + * classes as the 'toClone' loader. + */ + public CloneClassLoader(ClassLoader toClone) { + this(null, toClone, new String[0], new String[0]); + } + + /** + * Creates a class loader which can load the same classes as the loader which loaded the + * CloneClassLoader class itself. + *

+ * Only the bootstrap classes are delegated to the bootstrap class loader. + * + * @param toClone + * the class loader to mimic. The clone class loader will be able to load the same + * classes as the 'toClone' loader. + * @param notLoadable + * The classes we should not be able to load via this loader. + */ + public CloneClassLoader(ClassLoader toClone, String[] notLoadable) { + this(null, toClone, notLoadable, new String[0]); + } + + /** + * Creates a class loader which can load the same classes as the loader which loaded the + * CloneClassLoader class itself. + *

+ * Only the classes which are loadable by the 'parent' loader are delegated to that loader (to + * make it possible mix classes). + * + * @param parent + * the parent loader which is first asked to load a class. + * @param toClone + * the class loader to mimic. The clone class loader will be able to load the same + * classes as the 'toClone' loader. + */ + public CloneClassLoader(ClassLoader parent, ClassLoader toClone) { + this(parent, toClone, new String[0], new String[0]); + } + + /** + * Creates a class loader which can load the same classes as the loader which loaded the + * CloneClassLoader class itself. + *

+ * Only the classes which are loadable by the 'parent' loader are delegated to that loader (to + * make it possible mix classes). + * + * @param parent + * the parent loader which is first asked to load a class. + * @param toClone + * the class loader to mimic. The clone class loader will be able to load the same + * classes as the 'toClone' loader. + * @param notLoadable + * The classes we should not be able to load via this loader. + * @param simpleDelegate + * The names of the classes for which we simply delegate. + */ + public CloneClassLoader(ClassLoader parent, ClassLoader toClone, String[] notLoadable, String[] simpleDelegate) { + super(parent); + + this.toClone = toClone; + this.notLoadable = new HashSet<>(Arrays.asList(notLoadable)); + this.simpleDelegate = new HashSet<>(Arrays.asList(simpleDelegate)); + } + + /** + * @see java.lang.ClassLoader#findClass(java.lang.String) + */ + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (notLoadable.contains(name)) { + throw new ClassNotFoundException("The clone class loader explicitly didn't find the class '" + name + "'"); + } + + if (simpleDelegate.contains(name)) { + return toClone.loadClass(name); + } + + // We just ask the wrapper class loader to find the resource for us + URL res = toClone.getResource(name.replace('.', '/') + ".class"); + + if (res == null) { + throw new ClassNotFoundException(name); + } + + try { + InputStream is = res.openStream(); + byte[] code = readStreamIntoBuffer(is, 8192); + is.close(); + return defineClass(name, code, 0, code.length); + } catch (IOException e) { + throw new ClassNotFoundException(name, e); + } + } + + /** + * Reads all data of a stream into a byte array. The method allocates as much memory as + * necessary to put the whole data into that byte array. The data is read in chunks of + * chunkSize chunks.
+ *
+ * Implementation Note: The data is read in chunks of chunkSize bytes. The + * data is copied to the result array. The memory consumption at the end of the reading is + * 2 x [size of resulting array] + chunkSize. + * + * @param is + * the stream to read the data from + * @param chunkSize + * the size of the chunks the data should be read in + * @return the whole data of the stream read into an byte array + * @throws IllegalArgumentException + * if chunkSize <= 0 + * @throws NullPointerException + * if is == null + * @throws IOException + * thrown if the provided stream encounters IO problems + */ + public static byte[] readStreamIntoBuffer(InputStream is, int chunkSize) throws IOException { + + // check preconditions + if (chunkSize <= 0) { + throw new IllegalArgumentException("chunkSize <= 0"); + } else if (is == null) { + throw new NullPointerException("is is null"); + } + + // temporary buffer for read operations and result buffer + byte[] tempBuffer = new byte[chunkSize]; + byte[] buffer = new byte[0]; + + int bytesRead = 0; // bytes actual read + int oldSize = 0; // size of the resulting buffer + + while ((bytesRead = is.read(tempBuffer)) > 0) { + + // temporary reference to the buffer for the copy operation + byte[] oldBuffer = buffer; + + // create a new buffer with the size needed and copy data + buffer = new byte[oldSize + bytesRead]; + System.arraycopy(oldBuffer, 0, buffer, 0, oldBuffer.length); + + // copy the new data + System.arraycopy(tempBuffer, 0, buffer, oldSize, bytesRead); + oldSize += bytesRead; + } + + return buffer; + } +} diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/DuplicateTracedClasses.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/DuplicateTracedClasses.java new file mode 100644 index 0000000000..0dcb2870df --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/DuplicateTracedClasses.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +import java.lang.reflect.Method; + +public class DuplicateTracedClasses { + + public static void main(String[] args) throws Exception { + CloneClassLoader cl1 = new CloneClassLoader(DuplicateTracedClasses.class.getClassLoader()); + CloneClassLoader cl2 = new CloneClassLoader(DuplicateTracedClasses.class.getClassLoader()); + Class clz1 = cl1.loadClass(DuplicateTracedClasses.class.getName()); + Class clz2 = cl2.loadClass(DuplicateTracedClasses.class.getName()); + Method m1 = clz1.getDeclaredMethod("test", String.class); + Method m2 = clz2.getDeclaredMethod("test", String.class); + m1.invoke(null, "Loader 1"); + m2.invoke(null, "Loader 2"); + test("Default loader"); + } + + public static void test(String msg) { + // Nothing to do. + } +} diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/GenericLoggingTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/GenericLoggingTest.java new file mode 100644 index 0000000000..ab044c880a --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/GenericLoggingTest.java @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +import java.io.File; +import java.io.InputStream; +import java.io.Serializable; +import java.nio.CharBuffer; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; + +public class GenericLoggingTest extends TestBase implements VmAgnostic { + + public static void main(String[] args) { + new GenericLoggingTest().dispatch(args); + } + + public static void genericLogging4() { + Object[][] oa1 = new Object[][] {new Object[1], new Serializable[2][], new String[3]}; + String[] sa = new String[] {"just", "a", "test", null, "with", "many", "strings", "!"}; + boolean[] za = new boolean[] {true, false, true, false, true}; + boolean[] za1 = new boolean[] {true}; + HashMap map1 = new HashMap<>(); + map1.put("test", new C1()); + LinkedHashMap map2 = new LinkedHashMap<>(); // Must be linked to stable order. + map2.put("test1", new C1()); + map2.put("test2", new C2()); + map2.put("test3", new C3()); + map2.put(null, new C1()); + map2.put("test5", new C2()); + map2.put("test6", new C3()); + DummyList dl1 = new DummyList(map2.values(), true); + DummyList dl2 = new DummyList(map2.values(), false); + LinkedHashMap map3 = new LinkedHashMap<>(); + map3.put("map1", map1); + map3.put("map2", map2); + Object[] oa2 = new Object[] {oa1, sa, map1, map3, za, za1}; + + // The calls we expect to be logged + traceObjects1(null, new byte[3], new byte[4][], new Integer[10], new C1(), new C1(), new C3(), "Hehe!"); + tracePrimitives1(false, (byte) -1, (short) -7, 'C', 128, -7, 0.2f, -2.2); + tracePrimitives2('C', (byte) 1, (short) 7, 'C', -2, 7, -0.2f, 2.2); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', -222, 77132, -0.22387f, 2.1332); + traceObjects1(null, new byte[3], new byte[4][], new Integer[10], C1.class, new C1(), new C3(), "Hehe!"); + traceObjects1(null, new byte[3], new byte[4][], new Integer[10], C1.class, new C1(), new C3(), + new StringBuilder("Hehe!")); + traceObjects1(null, new byte[3], new byte[4][], new Integer[10], C1.class, new C1(), new C3(), + new StringBuffer("Hehe!")); + traceObjects1(null, new byte[3], new byte[4][], new Integer[10], C1.class, new C1(), new C3(), + CharBuffer.allocate(5).append("Hele!").position(0)); + traceObjects2(map1, map2, za, null, dl1, dl2, map3, oa2); + traceObjects3(dl2, sa, za, map1, map2, oa1, Class.class, new StringBuilder("Jeje")); + + // The calls we expect to be filtered out. + tracePrimitives1(true, (byte) -1, (short) -7, 'C', 128, -7, 0.2f, -2.2); + tracePrimitives1(false, (byte) -2, (short) -7, 'C', 128, -7, 0.2f, -2.2); + tracePrimitives1(false, (byte) 3, (short) -7, 'C', 128, -7, 0.2f, -2.2); + tracePrimitives1(false, (byte) -1, (short) -8, 'C', 128, -7, 0.2f, -2.2); + tracePrimitives1(false, (byte) -1, (short) 2, 'C', 128, -7, 0.2f, -2.2); + tracePrimitives1(false, (byte) -1, (short) -7, 'B', 128, -7, 0.2f, -2.2); + tracePrimitives1(false, (byte) -1, (short) -7, 'D', 128, -7, 0.2f, -2.2); + tracePrimitives1(false, (byte) -1, (short) -7, 'C', 127, -7, 0.2f, -2.2); + tracePrimitives1(false, (byte) -1, (short) -7, 'C', 129, -7, 0.2f, -2.2); + tracePrimitives1(false, (byte) -1, (short) -7, 'C', 128, -8, 0.2f, -2.2); + tracePrimitives1(false, (byte) -1, (short) -7, 'C', 128, -6, 0.2f, -2.2); + tracePrimitives1(false, (byte) -1, (short) -7, 'C', 128, -7, 0.1f, -2.2); + tracePrimitives1(false, (byte) -1, (short) -7, 'C', 128, -7, 0.3f, -2.2); + tracePrimitives2('D', (byte) 1, (short) 7, 'C', -2, 7, -0.2f, 2.2); + tracePrimitives2('C', (byte) 0, (short) 7, 'C', -2, 7, -0.2f, 2.2); + tracePrimitives2('C', (byte) 2, (short) 7, 'C', -2, 7, -0.2f, 2.2); + tracePrimitives2('C', (byte) 1, (short) 6, 'C', -2, 7, -0.2f, 2.2); + tracePrimitives2('C', (byte) 1, (short) 8, 'C', -2, 7, -0.2f, 2.2); + tracePrimitives2('C', (byte) 1, (short) 7, 'B', -2, 7, -0.2f, 2.2); + tracePrimitives2('C', (byte) 1, (short) 7, 'D', -2, 7, -0.2f, 2.2); + tracePrimitives2('C', (byte) 1, (short) 7, 'C', -4, 7, -0.2f, 2.2); + tracePrimitives2('C', (byte) 1, (short) 7, 'C', 0, 7, -0.2f, 2.2); + tracePrimitives2('C', (byte) 1, (short) 7, 'C', -2, 6, -0.2f, 2.2); + tracePrimitives2('C', (byte) 1, (short) 7, 'C', -2, 8, -0.2f, 2.2); + tracePrimitives2('C', (byte) 1, (short) 7, 'C', -2, 7, -1.2f, 2.2); + tracePrimitives2('C', (byte) 1, (short) 7, 'C', -2, 7, 0.2f, 2.2); + tracePrimitives2('C', (byte) 1, (short) 7, 'C', -2, 7, -0.2f, 2.1); + tracePrimitives2('C', (byte) 1, (short) 7, 'C', -2, 7, -0.2f, 2.3); + tracePrimitives3('E', (byte) 127, (short) 15, 'E', -222, 77132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 126, (short) 15, 'E', -222, 77132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 107, (short) 15, 'E', -222, 77132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 27, (short) 15, 'E', -222, 77132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 215, 'E', -222, 77132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 151, 'E', -222, 77132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15315, 'E', -222, 77132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15715, 'E', -222, 77132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15, 'e', -222, 77132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15, 'f', -222, 77132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', 222, 77132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', -223, 77132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', -232, 77132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', -222, 67132, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', -222, 77133, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', -222, 77232, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', -222, 76232, -0.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', -222, 77132, -1.22387f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', -222, 77132, -0.22367f, 2.1332); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', -222, 77132, -0.22387f, 2.1432); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', -222, 77132, -0.22387f, 2.1335); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', -222, 77132, -0.22387f, 2.1533); + tracePrimitives3('e', (byte) 127, (short) 15, 'E', -222, 77132, -0.22387f, -2.1332); + traceObjects1("", new byte[3], new byte[4][], new Integer[10], C1.class, new C1(), new C3(), "Hehe!"); + traceObjects1(null, new Byte[3], new byte[4][], new Integer[10], C1.class, new C1(), new C3(), "Hehe!"); + traceObjects1(null, new byte[2], new byte[4][], new Integer[10], C1.class, new C1(), new C3(), "Hehe!"); + traceObjects1(null, new byte[5], new byte[4][], new Integer[10], C1.class, new C1(), new C3(), "Hehe!"); + traceObjects1(null, new byte[3], new byte[4], new Integer[10], C1.class, new C1(), new C3(), "Hehe!"); + traceObjects1(null, new byte[3], new byte[3][], new Integer[10], C1.class, new C1(), new C3(), "Hehe!"); + traceObjects1(null, new byte[3], new byte[6][], new Integer[10], C1.class, new C1(), new C3(), "Hehe!"); + traceObjects1(null, new byte[3], new byte[4][], new byte[10], C1.class, new C1(), new C3(), "Hehe!"); + traceObjects1(null, new byte[3], new byte[4][], new Integer[9], C1.class, new C1(), new C3(), "Hehe!"); + traceObjects1(null, new byte[3], new byte[4][], new Integer[11], C1.class, new C1(), new C3(), "Hehe!"); + traceObjects1(null, new byte[3], new byte[4][], new Integer[10], null, new C1(), new C3(), "Hehe!"); + traceObjects1(null, new byte[3], new byte[4][], new Integer[10], C1.class, C1.class, new C3(), "Hehe!"); + traceObjects1(null, new byte[3], new byte[4][], new Integer[10], C1.class, new C2(), new C3(), "Hehe!"); + traceObjects1(null, new byte[3], new byte[4][], new Integer[10], C1.class, new C1(), new C2(), "Hehe!"); + traceObjects1(null, new byte[3], new byte[4][], new Integer[10], C1.class, new C1(), new C3(), "Hehe!!"); + traceObjects1(null, new byte[3], new byte[4][], new Integer[10], C1.class, new C1(), new C3(), "Heha!"); + traceObjects2(za1, map2, za, null, dl1, dl2, map3, oa2); + traceObjects2(map2, map2, za, null, dl1, dl2, map3, oa2); + traceObjects2(map1, map1, za, null, dl1, dl2, map3, oa2); + traceObjects2(map1, map2, new Object[0], "null", dl1, dl2, map3, oa2); + traceObjects2(map1, map2, za, "null", dl1, dl2, map3, oa2); + traceObjects2(map1, map2, za, null, new int[10], dl2, map3, oa2); + traceObjects2(map1, map2, za, null, map1, dl2, map3, oa2); + traceObjects2(map1, map2, za, null, dl1, dl1, map3, oa2); + traceObjects2(map1, map2, za, null, dl1, dl2, map2, oa2); + } + + protected void runAllTests() throws Exception { + File xmlFile = new File("generic_logger.xml").getAbsoluteFile(); + + try (InputStream is = GenericLoggingTest.class.getClassLoader() + .getResourceAsStream("org/openjdk/jmc/agent/test/sap/generic.xml")) { + Files.copy(is, xmlFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + + String filter1 = "value1Equals=false,value1NotEquals=true,value1StartsWith=fal,value1EndsWith=lse," + + "value1NotStartsWith=tr,value1NotEndsWith=ue,value1Contains=ls," + + "value1NotContains=ru,value1MatchesRegexp=a.s,value1NotMatchesRegexp=r.e," + + "minLongValue2=-1,maxLongValue2=2,minDoubleValue3=-7.2,maxDoubleValue3=1.1," + + "minLongValue4=67,maxLongValue4=67,minDoubleValue5=127.2,maxDoubleValue5=128.1," + + "minLongValue6=-7,maxLongValue6=-7,minDoubleValue7=0.15,maxDoubleValue7=0.25"; + String filter2 = "value1Equals=C,value1StartsWith=C,value1EndsWith=C,value1Contains=C," + + "value1MatchesRegexp=^[C]$,minDoubleValue2=0.9,maxDoubleValue2=1.1," + + "minLongValue3=7,maxLongValue3=7,minDoubleValue4=66.3,maxDoubleValue4=67.1," + + "minLongValue5=-3,maxLongValue5=-1,minDoubleValue6=6.9,maxDoubleValue6=7.1," + + "minLongValue7=-1,maxLongValue7=0,minDoubleValue8=2.15,maxDoubleValue8=2.25"; + String filter3 = "value1NotMatchesRegexp=E,value2MatchesRegexp=1?[12][76],value2EndsWith=7," + + "value2Contains=1,value3StartsWith=15,value3EndsWith=15,value3NotContains=3," + + "value3NotMatchesRegexp=7,value3Instanceof=java.lang.Short," + + "value3Instanceof=java.lang.Number,value3Instanceof=java.lang.Object," + + "value4Instanceof=java.lang.Character,value4NotInstanceof=java.lang.Number," + + "value4NotContains=e,value4MatchesRegexp=[eE],value5StartsWith=-," + + "value5EndsWith=2,value5MatchesRegexp=22,value6NotStartsWith=6,value6NotEndsWith=3," + + "value6NotContains=23,value6MatchesRegexp=.7.3,value7NotContains=6,value7MatchesRegexp=0[.]," + + "value7Instanceof=java.lang.Float,value8Instanceof=java.lang.Number," + + "value8Instanceof=java.lang.Double,value8NotInstanceof=java.lang.Float," + + "value8NotEquals=2.1432,value8NotContains=35,value8NotEndsWith=3,value8NotStartsWith=-"; + String filter4 = "value1IsType=null,value2IsNotType=object_array,value2IsType=array," + + "value2IsType=primitive_array,value2MinLength=3,value2MaxLength=4,value3IsType=array," + + "value3IsNotType=primitive_array,value3IsType=object_array,value3MinLength=4," + + "value3MaxLength=5,value4IsType=array,value4IsNotType=primitive_array," + + "value4IsType=object_array,value4MinLength=10,value4MaxLength=10,value5IsNotType=null," + + "value5Instanceof=org.openjdk.jmc.agent.sap.test.C1,value5Instanceof=java.lang.Object," + + "value5Instanceof=java.lang.Class,value5Instanceof=java.lang.Comparable," + + "value6Instanceof=org.openjdk.jmc.agent.sap.test.C1,value6Instanceof=java.lang.Object," + + "value6NotInstanceof=java.lang.Class,value6NotInstanceof=org.openjdk.jmc.agent.sap.test.C2," + + "value7Instanceof=org.openjdk.jmc.agent.sap.test.I3,value7Instanceof=org.openjdk.jmc.agent.sap.test.C2," + + "value7Instanceof=org.openjdk.jmc.agent.sap.test.C1,value7Instanceof=org.openjdk.jmc.agent.sap.test.I2," + + "value7Instanceof=org.openjdk.jmc.agent.sap.test.I1,value8StartsWith=He,value8EndsWith=!," + + "value8MatchesRegexp=.e.e,value8MinLength=5,value8MaxLength=5,value8Contains=e!"; + String filter5 = "printCollectionContent=true,value1MaxLength=1,value1MinLength=1," + + "value1IsNotType=array,value2MinLength=6,value2IsNotType=primitive_array," + + "value2IsNotType=object_array,value2IsNotType=null,value3IsType=primitive_array," + + "value4IsType=null,value4IsNotType=object_array,value4IsNotType=array," + + "value5MinLength=6,value5IsNotType=array,value6StartsWith=JustA,value6EndsWith=Dummy," + + "value6MatchesRegexp=.ust.Du[m-n].y,value6Contains=ADum,value6Equals=JustADummy," + + "value7MaxLength=2"; + String filter6 = "printCollectionContent=false"; + JavaAgentRunner runner = getRunner(xmlFile.getPath() + ",logGeneric1,logDest=stdout," + filter1 + + ",logGeneric2,logDest=stdout," + filter2 + ",logGeneric3,logDest=stdout," + filter3 + + ",logGeneric4,logDest=stdout," + filter4 + ",logGeneric5,logDest=stdout," + filter5 + + ",logGeneric6,logDest=stdout," + filter6); + runner.start("genericLogging4"); + runner.waitForEnd(); + assertLinesContains(runner.getStdoutLines(), "Values for generic logger 1: false -1 -7 C 128 -7 0.2 -2.2", + "Values for generic logger 2: C 1 7 C -2 7 -0.2 2.2", + "Values for generic logger 3: e 127 15 E -222 77132 -0.22387 2.1332", + "Values for generic logger 4: null {0, 0, 0} {null, null, null, null} " + + "{null, null, null, null, null, 5 skipped ...} " + + "class org.openjdk.jmc.agent.sap.test.C1 C1 C3 \"Hehe!\"", + "Values for generic logger 4: null {0, 0, 0} {null, null, null, null} " + + "{null, null, null, null, null, 5 skipped ...} " + + "class org.openjdk.jmc.agent.sap.test.C1 C1 C3 \"Hele!\"", + "Values for generic logger 5: {\"test\": C1} {\"test1\": C1, \"test2\": C2, " + + "\"test3\": C3, null: C1, \"test5\": C2, 1 skipped ...} " + + "{true, false, true, false, true} null {C1, C2, C3, C1, C2, 1 skipped ...} " + + "org.openjdk.jmc.agent.sap.test.DummyList(size 6) " + + "{\"map1\": {\"test\": C1}, \"map2\": {\"test1\": C1, \"test2\": C2, " + + "\"test3\": C3, null: C1, \"test5\": C2, 1 skipped ...}} " + + "{java.lang.Object[3][], java.lang.String[8], {\"test\": C1}, " + + "{\"map1\": {\"test\": C1}, \"map2\": {\"test1\": C1, \"test2\": C2, " + + "\"test3\": C3, null: C1, \"test5\": C2, 1 skipped ...}}, boolean[5], 1 skipped ...}", + "Values for generic logger 6: org.openjdk.jmc.agent.sap.test.DummyList(size 6) " + + "{\"just\", \"a\", \"test\", null, \"with\", 3 skipped ...} " + + "{true, false, true, false, true} java.util.HashMap(size 1) " + + "java.util.LinkedHashMap(size 6) {java.lang.Object[1], java.io.Serializable[2][], " + + "java.lang.String[3]} class java.lang.Class \"Jeje\""); + assertNrOfLines(runner.getStdoutLines(), 9); // Should contain no other than the lines check above. + } finally { + while (xmlFile.exists()) { + xmlFile.delete(); + } + } + } + + public static int tracePrimitives1(boolean v1, byte v2, short v3, char c4, int v5, long v6, float v7, double v8) { + return 0; + } + + public static int tracePrimitives2(char v1, byte v2, short v3, char c4, int v5, long v6, float v7, double v8) { + return 0; + } + + public static int tracePrimitives3(char v1, byte v2, short v3, char c4, int v5, long v6, float v7, double v8) { + return 0; + } + + public static int traceObjects1( + Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Object o7, Object o8) { + if (o2 != null) { + return 1; + } + + return 0; + } + + public static int traceObjects2( + Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Object o7, Object o8) { + return 0; + } + + public static int traceObjects3( + Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Object o7, Object o8) { + return 0; + } +} + +class C1 implements Comparable { + + @Override + public int compareTo(Object o) { + return 0; + } + + @Override + public String toString() { + return "C1"; + } +} + +interface I1 { + public void if1(); +} + +interface I2 extends I1 { + public void if2(); +} + +interface I3 { + public void if3(); +} + +class C2 extends C1 implements I2, I1 { + + @Override + public void if1() { + } + + @Override + public void if2() { + } + + @Override + public String toString() { + return "C2"; + } +} + +class C3 extends C2 implements I3 { + + @Override + public void if3() { + } + + @Override + public String toString() { + return "C3"; + } +} + +@SuppressWarnings("serial") +class DummyList extends ArrayList { + + private final boolean allowInspection; + + public DummyList(Collection toCopy, boolean allowInspection) { + super(toCopy); + this.allowInspection = allowInspection; + } + + @Override + public Iterator iterator() { + if (allowInspection) { + return super.iterator(); + } + + return new Iterator() { + + @Override + public boolean hasNext() { + return true; + } + + @Override + public E next() { + throw new ConcurrentModificationException(); + } + }; + } + + @SuppressWarnings("unchecked") + @Override + public E[] toArray() { + if (allowInspection) { + return (E[]) super.toArray(); + } + + throw new RuntimeException("Chould not be called."); + } + + @Override + public T[] toArray(T[] a) { + if (allowInspection) { + return super.toArray(a); + } + + throw new RuntimeException("Chould not be called."); + } + + @Override + public String toString() { + if (allowInspection) { + return super.toString(); + } + + return "JustADummy"; + } +} diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/JavaAgentRunner.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/JavaAgentRunner.java new file mode 100644 index 0000000000..d06f274434 --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/JavaAgentRunner.java @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.ProcessBuilder.Redirect; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; + +public class JavaAgentRunner { + + private final String classToRun; + private final String options; + private final String[] vmArgs; + private final StringBuilder stdout; + private final StringBuilder stderr; + private String commandLine = "java"; + private Thread stdoutWorker; + private Thread stderrWorker; + private Process process; + private static boolean dumpOnExit; + private static int debugPort = -1; + private static int MAX_WAIT_TIME = 60; + private static String[] additionalVmArgs = new String[0]; + + private static final boolean dumpOutputToFile = Boolean.getBoolean("dumpOutputToFile"); + private static final boolean useJmcAgentOption = Boolean.getBoolean("useJmcAgentOption"); + private static final boolean traceExecs = Boolean.getBoolean("traceExecs"); + + public JavaAgentRunner(Class classToRun, String options, String ... vmArgs) { + this.classToRun = classToRun.getName(); + this.options = options; + this.vmArgs = vmArgs; + this.stdout = new StringBuilder(); + this.stderr = new StringBuilder(); + } + + public static void setAdditionalVmArgs(String[] args) { + additionalVmArgs = args; + } + + private ArrayList getArgs(String[] javaArgs) { + ArrayList args = new ArrayList<>(); + args.add(getExe("java")); + args.add("-cp"); + args.add(System.getProperty("java.class.path")); + + if (useJmcAgentOption) { + args.add("-jmcagent:" + options); + } else { + args.add("-javaagent:" + getAgent() + "=" + options); + } + + for (String vmArg : additionalVmArgs) { + args.add(vmArg); + } + + args.add("-cp"); + args.add(System.getProperty("java.class.path")); + + for (String vmArg : vmArgs) { + args.add(vmArg); + } + + if (debugPort >= 0) { + args.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=" + debugPort); + System.out.println("Waiting for debugger on port " + debugPort + "."); + } + + args.add(classToRun); + + for (String javaArg : javaArgs) { + args.add(javaArg); + } + + commandLine = String.join(" ", args); + + return args; + } + + public String getCommandLine() { + return commandLine; + } + + private static String getAgent() { + Pattern pattern = Pattern.compile("^agent-[0-9]+[.][0-9]+[.][0-9]+(-SNAPSHOT)?[.]jar$"); + String javaHome = System.getProperty("java.home"); + String[] toSearch = new String[] {".", "target", javaHome + File.separator + "lib"}; + FilenameFilter filter = (File dir, String name) -> pattern.matcher(name).matches(); + + for (String dir : toSearch) { + File[] files = new File(dir).listFiles(filter); + + if (files.length == 1) { + return files[0].getAbsolutePath(); + } else if (files.length > 1) { + throw new RuntimeException("Found more than one agent: " + Arrays.toString(files)); + } + } + + throw new RuntimeException("Could not find agent in " + Arrays.toString(toSearch)); + } + + private static String getExe(String name) { + String javaHome = System.getProperty("java.home"); + File java = new File(javaHome + File.separator + "bin" + File.separator + name); + + if (java.exists() && java.canExecute()) { + return java.getAbsolutePath(); + } + + java = new File(java.getAbsolutePath() + ".exe"); + + if (java.exists() && java.canExecute()) { + return java.getAbsolutePath(); + } + + throw new RuntimeException("Could not locate '" + name + "'"); + } + + public void start(String ... javaArgs) throws IOException { + stdout.setLength(0); + stderr.setLength(0); + + ProcessBuilder pb = new ProcessBuilder(getArgs(javaArgs)); + commandLine = String.join(" ", pb.command()); + dumpToAll("------------------------", commandLine); + + if (traceExecs) { + System.out.println("Starting " + commandLine); + } + + process = pb.start(); + stdoutWorker = new Thread(new OutputReader(process.getInputStream(), stdout)); + stdoutWorker.setDaemon(true); + stdoutWorker.start(); + stderrWorker = new Thread(new OutputReader(process.getErrorStream(), stderr)); + stderrWorker.setDaemon(true); + stderrWorker.start(); + } + + public void waitForStdout(String tag) { + waitFor(stdout, tag); + } + + public void waitForStderr(String tag) { + waitFor(stderr, tag); + } + + public void loadAgent(String options) throws IOException { + if (process == null) { + throw new IOException("No process"); + } + + if (options.indexOf('=') >= 0) { + options = "'" + options + "'"; // jcmd can remove everything after the equals. + } + + long pid = process.pid(); + ArrayList args = new ArrayList<>(); + args.add(getExe("jcmd")); + args.add(Long.toString(pid)); + + if (useJmcAgentOption) { + args.add("JVMTI.jmc_agent_load"); + } else { + args.add("JVMTI.agent_load"); + args.add(getAgent()); + } + + args.add(options); + ProcessBuilder pb = new ProcessBuilder(args); + pb.redirectError(Redirect.DISCARD); + pb.redirectOutput(Redirect.DISCARD); + + if (traceExecs) { + System.out.println("Starting " + String.join(" ", args)); + } + + Process p = pb.start(); + + while (true) { + try { + int result = p.waitFor(); + + if (result != 0) { + kill(); + dumpOnExit(result); + throw new RuntimeException(pb.command().toString() + " return with exit code " + result); + } + + return; + } catch (InterruptedException e) { + // retry + } + } + } + + public int waitForEnd() { + long t1 = System.currentTimeMillis(); + + while (true) { + try { + boolean exited = process.waitFor(5, TimeUnit.SECONDS); + + if (!exited && !checkWaitTimeout(t1)) { + dumpOnExit(-1); + throw new RuntimeException("Waited over one minute for the process to end."); + } + + if (!exited) { + continue; + } + + int result = process.exitValue(); + dumpOnExit(result); + + return result; + } catch (InterruptedException e) { + // Retry + } + } + } + + private void waitForOutput() { + try { + stdoutWorker.join(); + stderrWorker.join(); + } catch (InterruptedException e) { + // Ignore + } + } + + public String[] getStdoutLines() { + return OutputReader.getLines(stdout); + } + + public String[] getStderrLines() { + return OutputReader.getLines(stderr); + } + + private void dumpLines(StringBuilder sb) { + String raw; + + synchronized (sb) { + raw = sb.toString(); + } + + System.out.println(raw); + } + + public static void setDumpOnExit(boolean dumpOnExit) { + JavaAgentRunner.dumpOnExit = dumpOnExit; + } + + public static void setDebugPort(int port) { + debugPort = port; + } + + private void dumpOnExit(int result) { + if (dumpOnExit && (result != 0)) { + waitForOutput(); + System.out.println("Command line: " + commandLine); + System.out.println("Output on stdout:"); + dumpLines(stdout); + System.out.println("Output on stderr:"); + dumpLines(stderr); + } + + if (dumpOutputToFile) { + waitForOutput(); + dumpToFile(getStdoutLines(), false); + dumpToFile(getStderrLines(), true); + dumpToAll("------------------------", getCommandLine() + " end with result " + result); + } + } + + private void dumpToAll(String ... lines) { + if (dumpOutputToFile) { + dumpToFile(lines, false); + dumpToFile(lines, true); + } + } + + private void dumpToFile(String[] lines, boolean stderr) { + File outputDir = new File("target", "output"); + + if (!outputDir.exists()) { + outputDir.mkdir(); + } + + String filename = classToRun.substring(classToRun.lastIndexOf('.') + 1) + (stderr ? ".stderr" : ".stdout"); + + try (PrintStream ps = new PrintStream(new FileOutputStream(new File(outputDir, filename), true))) { + for (String line : lines) { + ps.println(line); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void kill() { + int result = 0; + + try { + if (process.waitFor(10, TimeUnit.MILLISECONDS)) { + result = process.exitValue(); + } else { + process.destroyForcibly(); + result = -1; + } + + } catch (InterruptedException e) { + // Ignore. + } + + dumpOnExit(result); + } + + private boolean checkWaitTimeout(long t1) { + if (debugPort >= 0) { + return true; // Don't terminate if we are debugging. + } + + long elapsed = (System.currentTimeMillis() - t1) / 1000; + + // We should never wait this long. + if (elapsed > MAX_WAIT_TIME) { + kill(); + + return false; + } + + return true; + } + + private void waitFor(StringBuilder output, String tag) { + long t1 = System.currentTimeMillis(); + + while (true) { + synchronized (output) { + if (output.indexOf(tag) >= 0) { + return; + } + + if (!checkWaitTimeout(t1)) { + System.out.println("stdout:"); + synchronized (stdout) { + System.out.println(stdout); + } + System.out.println("stderr:"); + synchronized (stderr) { + System.out.println(stderr); + } + throw new RuntimeException("Waited over one minute for '" + tag + "'"); + } + + try { + output.wait(10000); + } catch (InterruptedException e) { + // Ignore. + } + } + } + } + + public void waitForDone() { + waitForStdout(TestBase.DONE + "*"); + } + + public void waitForDone(int index) { + waitForStdout(TestBase.DONE + index); + } +} diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/LocaleChangeTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/LocaleChangeTest.java new file mode 100644 index 0000000000..19884c5c45 --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/LocaleChangeTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +import java.util.Locale; +import java.util.Locale.Category; + +public class LocaleChangeTest extends TestBase { + + public static void main(String[] args) { + new LocaleChangeTest().dispatch(args); + } + + @Override + protected void runAllTests() throws Exception { + JavaAgentRunner runner = getRunner("traceLocaleChange,logDest=stdout"); + runner.start("changeLocale"); + runner.waitForEnd(); + assertLinesContainsRegExp(runner.getStdoutLines(), + "Changed default locale for category 'DISPLAY' from .+ to 'English [(]Canada[)]'", + "Changed default locale for category 'FORMAT' from .* to 'English [(]Canada[)]'"); + assertLinesContains(runner.getStdoutLines(), + "Changed default locale for category 'DISPLAY' from 'English (Canada)' to 'Chinese (Taiwan)'.", + "Changed default locale for category 'FORMAT' from 'English (Canada)' to 'Chinese (Taiwan)'.", + "Changed default locale for category 'DISPLAY' from 'Chinese (Taiwan)' to 'English (Canada)'", + "Changed default locale for category 'FORMAT' from 'Chinese (Taiwan)' to 'English (Canada)'.", + "Changed default locale for category 'DISPLAY' from 'English (Canada)' to 'Chinese (China)'.", + "Changed default locale for category 'DISPLAY' from 'Chinese (China)' to 'French (France)'.", + "Changed default locale for category 'FORMAT' from 'English (Canada)' to 'Italian'.", + "Changed default locale for category 'FORMAT' from 'Italian' to 'French (Canada)'."); + assertLinesNotContains(runner.getStdoutLines(), + "Changed default locale for category 'DISPLAY' from 'Chinese (Taiwan)' to 'Chinese (Taiwan)'.", + "Changed default locale for category 'FORMAT' from 'Chinese (Taiwan)' to 'Chinese (Taiwan)'.", + "Changed default locale for category 'DISPLAY' from 'Chinese (China)' to 'Chinese (China)'.", + "Changed default locale for category 'FORMAT' from 'Italian' to 'Italian'."); + } + + public static void changeLocale() { + Locale.setDefault(Locale.CANADA); + Locale.setDefault(Locale.TAIWAN); + Locale.setDefault(Locale.TAIWAN); + Locale.setDefault(Locale.CANADA); + Locale.setDefault(Category.DISPLAY, Locale.CHINA); + Locale.setDefault(Category.DISPLAY, Locale.CHINA); + Locale.setDefault(Category.DISPLAY, Locale.FRANCE); + Locale.setDefault(Category.FORMAT, Locale.ITALIAN); + Locale.setDefault(Category.FORMAT, Locale.ITALIAN); + Locale.setDefault(Category.FORMAT, Locale.CANADA_FRENCH); + } +} diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OpenFileStatisticTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OpenFileStatisticTest.java new file mode 100644 index 0000000000..fe3ba3864b --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OpenFileStatisticTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; + +public class OpenFileStatisticTest extends TestBase { + + public static void main(String[] args) { + new OpenFileStatisticTest().dispatch(args); + } + + private static void deleteTestFiles() { + for (int i = 1; i <= 6; ++i) { + File file = getFile(i); + + while (file.exists()) { + file.delete(); + } + } + } + + @Override + protected void runAllTests() throws Exception { + JavaAgentRunner runner = getRunner("traceOpenFiles,logDest=stdout"); + runner.start("test"); + runner.waitForDone(1); + runner.loadAgent("dump=openFiles,logDest=stderr"); + + if (!smokeTestsOnly()) { + runner.waitForDone(); + runner.loadAgent("dump=openFiles,logDest=stdout"); + } + + runner.kill(); + + String[] stderr = runner.getStderrLines(); + assertLinesContains(stderr, getFileName(1) + "', mode 'w'"); + assertLinesContains(stderr, getFileName(2) + "', mode 'wa'"); + assertLinesContains(stderr, getFileName(1) + "', mode 'r'"); + assertLinesContains(stderr, getFileName(3) + "', mode 'w'"); + assertLinesContains(stderr, getFileName(4) + "', mode 'wa'"); + assertLinesContains(stderr, getFileName(2) + "', mode 'r'"); + assertLinesContains(stderr, getFileName(5) + "', mode 'rw'"); + assertLinesContains(stderr, getFileName(5) + "', mode 'r'"); + assertLinesContains(stderr, getFileName(6) + "', mode 'rw'"); + assertLinesContains(stderr, getFileName(6) + "', mode 'r'"); + assertLinesContainsRegExp(stderr, "Printed [0-9]+ of [0-9][0-9]+ file.* currently opened"); + + if (!smokeTestsOnly()) { + assertLinesNotContains(runner.getStdoutLines(), getFileName(1)); + } + + deleteTestFiles(); + } + + public static String getFileName(int index) { + return "testopen" + index + ".txt"; + } + + public static File getFile(int index) { + return new File(getFileName(index)); + } + + @SuppressWarnings("resource") + public void test() throws IOException { + FileOutputStream fos1 = new FileOutputStream(getFileName(1)); + FileOutputStream fos2 = new FileOutputStream(getFileName(2), true); + FileInputStream fis1 = new FileInputStream(getFileName(1)); + FileOutputStream fos3 = new FileOutputStream(getFile(3)); + FileOutputStream fos4 = new FileOutputStream(getFile(4), true); + FileInputStream fis2 = new FileInputStream(getFile(2)); + RandomAccessFile raf1 = new RandomAccessFile(getFileName(5), "rw"); + RandomAccessFile raf2 = new RandomAccessFile(getFileName(5), "r"); + RandomAccessFile raf3 = new RandomAccessFile(getFile(6), "rw"); + RandomAccessFile raf4 = new RandomAccessFile(getFile(6), "r"); + FileChannel fc = FileChannel.open(getFile(1).toPath()); + fc.read(ByteBuffer.allocate(10)); + + done(1, 3000); + + fos1.close(); + fos2.close(); + fos3.close(); + fos4.close(); + fis1.close(); + fis2.close(); + raf1.close(); + raf2.close(); + raf3.close(); + raf4.close(); + fc.close(); + + FileInputStream dummy = null; + deleteTestFiles(); + + try { + dummy = new FileInputStream(getFileName(1)); + throw new RuntimeException("Should not be able to open the file"); + } catch (FileNotFoundException e) { + // This is what we expect. + } + + done(); + assertNotNull(dummy); + } +} diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OutputReader.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OutputReader.java new file mode 100644 index 0000000000..ed4ccdc23f --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OutputReader.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +public class OutputReader implements Runnable { + private final StringBuilder out; + private final InputStream is; + + public OutputReader(InputStream is, StringBuilder out) { + this.is = is; + this.out = out; + } + + public static String[] getLines(CharSequence cs) { + String raw; + + synchronized (cs) { + raw = cs.toString(); + } + + return raw.split("[\r\n]+"); + } + + public String[] getLines() { + return getLines(out); + } + + public void run() { + try { + byte[] buf = new byte[8192]; + int read; + + while ((read = is.read(buf)) > 0) { + + if (read > 0) { + byte[] part = new byte[read]; + System.arraycopy(buf, 0, part, 0, read); + String toAppend = new String(part, StandardCharsets.ISO_8859_1); + + synchronized (out) { + out.append(toAppend); + out.notifyAll(); + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SapIntegrationTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SapIntegrationTest.java new file mode 100644 index 0000000000..d8e99e13bb --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SapIntegrationTest.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +import java.util.ArrayList; + +import org.junit.Test; + +public class SapIntegrationTest { + + @Test + public void smokeTest() throws Exception { + ArrayList args = new ArrayList<>(); + + if (!System.getProperty("fullTest", "false").equals("true")) { + args.add("-smoke"); + } + + String port = System.getProperty("debugPort", ""); + + if (port.length() > 0) { + args.add("-debug"); + args.add(port); + } + + String singleTest = System.getProperty("singleTest", ""); + + if (singleTest.length() > 0) { + args.add(singleTest); + } + + TestRunner.main(args.toArray(new String[args.size()])); + } +} diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SysPropsChangeTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SysPropsChangeTest.java new file mode 100644 index 0000000000..5a6eb4998e --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SysPropsChangeTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +import java.io.File; +import java.util.Properties; + +// You can run it via (if the cwd is the agent directory): +// java -cp target/test-classes org.openjdk.jmc.agent.sap.test.SysPropsChangeTest +public class SysPropsChangeTest extends TestBase { + + public static void main(String[] args) { + new SysPropsChangeTest().dispatch(args); + } + + @Override + protected void runAllTests() throws Exception { + JavaAgentRunner runner = getRunnerWithJFR("traceSysPropsChange,logDest=stdout"); + runner.start("changeSystemProps"); + runner.waitForEnd(); + assertLinesContains(runner.getStdoutLines(), "System property 'TEST_KEY' changed from 'null' to 'TEST_VAL'", + "System properties 'TEST_KEY' with value 'TEST_VAL' removed", SysPropsChangeTest.class.getName()); + assertLinesNotContains(runner.getStdoutLines(), "TEST_KEY_NO_SYS"); + assertLinesContainsInOrder(getJfrOutput("jdk.log.*"), "fieldValue = \"TEST_VAL\"", "OldValue = N/A", + "IsSystemProperty = true", "RemovedValue = \"TEST_VAL\"", "IsSystemProperty = true", "OldValue = N/A", + "IsSystemProperty = false", "OldValue = \"TEST_ADD_VALUE\"", "RemovedValue = \"TEST_CHANGE_VALUE\"", + "RemovedValue = N/A"); + + // Check if we can omit the stack. + runner = getRunner("traceSysPropsChange,logDest=stderr,logWithStack=false"); + runner.start("changeSystemProps"); + runner.waitForEnd(); + assertLinesContains(runner.getStderrLines(), "System property 'TEST_KEY' changed from 'null' to 'TEST_VAL'", + "System properties 'TEST_KEY' with value 'TEST_VAL' removed"); + assertLinesNotContains(runner.getStderrLines(), SysPropsChangeTest.class.getName()); + + // Check if we get help + runner = getRunner("traceSysPropsChange,help"); + runner.start("changeSystemProps"); + runner.waitForEnd(); + assertLinesContains(runner.getStderrLines(), "Help for command 'traceSysPropsChange'", + "Traces changes to the system properties", "logWithStack"); + } + + public static void changeSystemProps() { + new File("testfile"); + System.setProperty("TEST_KEY", "TEST_VAL"); + System.getProperties().remove("TEST_KEY"); + Properties props = new Properties(); + props.put("TEST_KEY_NO_SYS", "TEST_ADD_VALUE"); + props.setProperty("TEST_KEY_NO_SYS", "TEST_CHANGE_VALUE"); + props.remove("TEST_KEY_NO_SYS"); + props.remove("TEST_KEY_NO_SYS"); + } +} diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestBase.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestBase.java new file mode 100644 index 0000000000..e765b7ab9b --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestBase.java @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.regex.Pattern; + +public abstract class TestBase { + + private int jfrFileIndex = 1; + private File jfrFile = null; + + private static boolean smokeTestsOnly; + public static String DONE = "DONE"; + public static long MAX_TEST_CASE_DURATION = 5 * 60; + + public void dispatch(String[] args) { + try { + if (args.length == 0) { + runAllTests(); + } else { + Thread killer = new Thread(() -> { + while (true) { + try { + Thread.sleep(MAX_TEST_CASE_DURATION * 1000); + System.err.println("Test run in timeout."); + System.exit(1); + } catch (InterruptedException e) { + // Ignore + } + } + }, "Timeout Thread"); + killer.setDaemon(true); + killer.start(); + + try { + Method m = this.getClass().getDeclaredMethod(args[0]); + m.invoke(this); + } catch (NoSuchMethodException e) { + throw new RuntimeException("Undefined test '" + args[0] + "'"); + } + } + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException("Test failed", e); + } + } + + public JavaAgentRunner getRunner(String options, String ... vmArgs) { + return new JavaAgentRunner(getClass(), options, vmArgs); + } + + private File getNewJfrFile() { + File outputDir = new File("target", "output"); + + if (!outputDir.exists()) { + outputDir.mkdirs(); + } + + jfrFile = new File(outputDir, getClass().getName().replace('.', '_') + jfrFileIndex + ".jfr").getAbsoluteFile(); + jfrFileIndex += 1; + + return jfrFile; + } + + public JavaAgentRunner getRunnerWithJFR(String options, String ... vmArgs) { + File jfrFile = getNewJfrFile(); + jfrFile.delete(); + + String[] newVmArgs = new String[vmArgs.length + 1]; + System.arraycopy(vmArgs, 0, newVmArgs, 0, vmArgs.length); + newVmArgs[vmArgs.length] = "-XX:StartFlightRecording=filename=" + jfrFile.getPath(); + + return new JavaAgentRunner(getClass(), options, newVmArgs); + } + + public String[] getJfrOutput(String idFilter) throws IOException, InterruptedException { + return getJfrOutput(idFilter, 8); + } + + public String[] getJfrOutput(String idFilter, int stackDepth) throws IOException, InterruptedException { + if (!jfrFile.exists()) { + throw new FileNotFoundException(jfrFile.getPath()); + } + + ProcessBuilder pb = new ProcessBuilder("jfr", "print", "--stack-depth", "" + stackDepth, "--events", idFilter, + jfrFile.getPath()); + Process process = pb.start(); + StringBuilder output = new StringBuilder(); + OutputReader reader = new OutputReader(process.getInputStream(), output); + Thread worker = new Thread(reader); + worker.setDaemon(true); + worker.start(); + process.waitFor(); + worker.join(); + + return reader.getLines(); + } + + protected abstract void runAllTests() throws Exception; + + private static void failLines(String[] lines, String msg) { + failLines(lines, msg, -1); + } + + private static void failLines(String[] lines, String msg, int markedLine) { + System.err.println(msg + ":"); + System.err.println("---- START"); + + for (int i = 0; i < lines.length; ++i) { + if (i == markedLine) { + System.err.println("=> " + lines[i]); + } else { + System.err.println(" " + lines[i]); + } + } + + System.err.println("---- END"); + throw new AssertionError(msg); + } + + public static void assertNrOfLines(String[] lines, int expectedNrOfLines) { + if (lines.length != expectedNrOfLines) { + failLines(lines, "Expected " + expectedNrOfLines + " lines but got " + lines.length, -1); + } + } + + public static void assertLinesContains(String[] lines, String ... substrings) { + outer: for (String substring : substrings) { + for (String line : lines) { + if (line.indexOf(substring) >= 0) { + continue outer; + } + } + + failLines(lines, "Could not find '" + substring + "' in the lines"); + } + } + + public static void assertLinesContainsInOrder(String[] lines, String ... substrings) { + int index = 0; + for (String line : lines) { + String substring = substrings[index]; + + if (line.indexOf(substring) >= 0) { + ++index; + + if (index == substrings.length) { + return; + } + } + } + + failLines(lines, "Could not find '" + substrings[index] + "' in the lines"); + } + + public static void assertLinesContainsRegExp(String[] lines, String ... regexps) { + outer: for (String regexp : regexps) { + Pattern pattern = Pattern.compile(regexp); + + for (String line : lines) { + if (pattern.matcher(line).find()) { + continue outer; + } + } + + failLines(lines, "Could not find regexp '" + regexp + "' in the lines"); + } + } + + public static void assertLinesNotContains(String[] lines, String ... substrings) { + for (String substring : substrings) { + for (String line : lines) { + if (line.indexOf(substring) >= 0) { + failLines(lines, "Unexpectedly found '" + substring + "' in the lines"); + } + } + } + } + + public static void assertLinesNotContainsRegExp(String[] lines, String ... regexps) { + for (String regexp : regexps) { + Pattern pattern = Pattern.compile(regexp); + + for (int i = 0; i < lines.length; ++i) { + if (pattern.matcher(lines[i]).find()) { + failLines(lines, "Unexpectedly found regexp '" + regexp + "' in the lines", i); + return; + } + } + } + } + + public static void assertNotNull(Object obj) { + if (obj == null) { + throw new AssertionError("Object is null"); + } + } + + public static void setSmokeTestOnly() { + smokeTestsOnly = true; + } + + public static boolean smokeTestsOnly() { + return smokeTestsOnly; + } + + public void assertRunnerFinished(JavaAgentRunner runner) { + int result = runner.waitForEnd(); + + if (result != 0) { + throw new AssertionError("Exit code " + result + " for " + runner.getCommandLine()); + } + } + + public static void sleep(long seconds) { + try { + Thread.sleep(seconds * 1000); + } catch (InterruptedException e) { + + } + } + + protected static void done(int index, long waitTime) { + System.out.println(DONE + index); + + try { + Thread.sleep(waitTime); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + protected static void done() { + System.out.println(DONE + "*"); + + while (true) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestRunner.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestRunner.java new file mode 100644 index 0000000000..9cc8038377 --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestRunner.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; + +public class TestRunner { + private static Class[] testClasses = new Class[] {UnsafeAllocationTest.class, SysPropsChangeTest.class, + TimeZoneChangeTest.class, LocaleChangeTest.class, OpenFileStatisticTest.class, GenericLoggingTest.class}; + + public static void main(String[] args, String[] additionalVmArgs) throws Exception { + JavaAgentRunner.setAdditionalVmArgs(additionalVmArgs); + main(args); + } + + public static void main(String[] args) throws Exception { + ArrayList leftArgs = new ArrayList<>(Arrays.asList(args)); + boolean vmAgnosticTests = false; + + while (leftArgs.size() > 0) { + String first = leftArgs.get(0); + + if (first.equals("-dump")) { + JavaAgentRunner.setDumpOnExit(true); + leftArgs.remove(0); + } else if (first.equals("-debug")) { + if (leftArgs.size() < 2) { + throw new Exception("Missing port to '-debug'"); + } + + JavaAgentRunner.setDebugPort(Integer.parseInt(leftArgs.get(1))); + leftArgs.remove(0); + leftArgs.remove(0); + } else if (first.equals("-smoke")) { + TestBase.setSmokeTestOnly(); + leftArgs.remove(0); + } else if (first.endsWith("-vm-agnostic-tests")) { + vmAgnosticTests = true; + leftArgs.remove(0); + } else { + break; + } + } + + HashSet toRun = new HashSet<>(leftArgs); + + for (Class testClass : testClasses) { + boolean run = false; + + if (leftArgs.size() == 0) { + run = true; + } else { + for (String arg : leftArgs) { + if (testClass.getName().endsWith("." + arg)) { + run = true; + toRun.remove(arg); + } + } + } + + if (vmAgnosticTests) { + if (!VmAgnostic.class.isAssignableFrom(testClass)) { + continue; + } + } + + if (run) { + Method mainMethod = testClass.getDeclaredMethod("main", String[].class); + mainMethod.invoke(null, new Object[] {new String[0]}); + } + } + + if (toRun.size() > 0) { + throw new RuntimeException("Could not find test " + toRun.iterator().next()); + } + } +} diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TimeZoneChangeTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TimeZoneChangeTest.java new file mode 100644 index 0000000000..19b50f9e69 --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TimeZoneChangeTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +import java.util.TimeZone; + +public class TimeZoneChangeTest extends TestBase { + private static final TimeZone zone0 = TimeZone.getDefault(); + private static final TimeZone zone1a = TimeZone.getTimeZone("Europe/Berlin"); + private static final TimeZone zone1b = TimeZone.getTimeZone("America/Los_Angeles"); + private static final boolean zone0is1a = zone0.toZoneId().equals(zone1a.toZoneId()); + private static final TimeZone zone1 = zone0is1a ? zone1b : zone1a; + + public static void main(String[] args) { + new TimeZoneChangeTest().dispatch(args); + } + + @Override + protected void runAllTests() throws Exception { + JavaAgentRunner runner = getRunner("traceTimeZoneChange,logDest=stdout"); + runner.start("changeTimeZones"); + runner.waitForEnd(); + assertLinesContainsRegExp(runner.getStdoutLines(), + "Changed default time zone to Central European.* Time [(]CET[)]", + "Changed default time zone to Greenwich Mean Time [(]Etc/GMT+0[)]", + "Changed default time zone to Central European Standard Time [(]Europe/Berlin[)]."); + runner = getRunnerWithJFR("traceTimeZoneChange,logDest=stdout"); + runner.start("changeForJFR"); + runner.waitForEnd(); + String[] lines = getJfrOutput("jdk.log.*"); + assertLinesContainsInOrder(lines, "fieldNewTimeZone = \"" + zone0.getDisplayName(), + "fieldNewTimeZoneId = \"" + zone0.toZoneId().getId(), "fieldOldTimeZone = \"" + zone0.getDisplayName(), + "fieldOldTimeZoneId = \"" + zone0.toZoneId().getId(), "fieldChangesDefault = false", + "fieldNewTimeZone = \"" + zone1.getDisplayName(), "fieldNewTimeZoneId = \"" + zone1.toZoneId().getId(), + "fieldOldTimeZone = \"" + zone0.getDisplayName(), "fieldOldTimeZoneId = \"" + zone0.toZoneId().getId(), + "fieldChangesDefault = true", "fieldNewTimeZone = \"" + zone0.getDisplayName(), + "fieldNewTimeZoneId = \"" + zone0.toZoneId().getId(), "fieldOldTimeZone = \"" + zone1.getDisplayName(), + "fieldOldTimeZoneId = \"" + zone1.toZoneId().getId(), "fieldChangesDefault = true"); + + } + + public void changeTimeZones() { + TimeZone.setDefault(TimeZone.getDefault()); + + for (int i = 0; i < 2; ++i) { + for (String id : TimeZone.getAvailableIDs()) { + TimeZone.setDefault(TimeZone.getTimeZone(id)); + } + } + } + + public void changeForJFR() { + TimeZone.setDefault(zone0); + TimeZone.setDefault(zone1); + TimeZone.setDefault(zone0); + } +} diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java new file mode 100644 index 0000000000..a93e0ba3c4 --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +// You can run it via (if the cwd is the agent directory): +// java -cp target/test-classes org.openjdk.jmc.agent.sap.test.UnsafeAllocationTest +public class UnsafeAllocationTest extends TestBase { + + private static Method allocateMemoryMethod; + private static Method reallocateMemoryMethod; + private static Method freeMemoryMethod; + private static Object theUnsafe; + private static String DO_ALLOCS = "runRandomAllocs"; + private static String DO_NATIVE_ALLOCS = "doNativeAllocs"; + private static String DO_DELAYED_ALLOCS = "doDelayedAllocs"; + private static String DO_NATIVE_ALLOCS_FOR_JFR = "doNativeAllocsForJfr"; + private static long DELAY = 10; + + private static void initUnsafe() { + try { + Class unsafeClass = Class.forName("jdk.internal.misc.Unsafe"); + Field theUnsafeField = unsafeClass.getDeclaredField("theUnsafe"); + theUnsafeField.setAccessible(true); + theUnsafe = theUnsafeField.get(null); + allocateMemoryMethod = unsafeClass.getDeclaredMethod("allocateMemory", long.class); + reallocateMemoryMethod = unsafeClass.getDeclaredMethod("reallocateMemory", long.class, long.class); + freeMemoryMethod = unsafeClass.getDeclaredMethod("freeMemory", long.class); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void main(String[] args) { + new UnsafeAllocationTest().dispatch(args); + } + + protected void runAllTests() throws Exception { + testNativeAllocs(); + testNativeAllocsForJfr(); + + if (smokeTestsOnly()) { + return; + } + + testDelayedDumping(); + testAgeFiltering(); + } + + public void testNativeAllocsForJfr() throws Exception { + JavaAgentRunner runner = getRunnerWithJFR("traceUnsafeAllocations", "--add-opens", + "java.base/jdk.internal.misc=ALL-UNNAMED"); + runner.start(DO_NATIVE_ALLOCS_FOR_JFR); + runner.waitForEnd(); + String[] lines = getJfrOutput("jdk.log.*", 16); + + // Find the allocated addresses. + long m1 = -1; + long m2 = -1; + + for (int i = 0; i < lines.length; ++i) { + String line = lines[i]; + + if (m1 == -1) { + if (line.endsWith("fieldSize = 12345")) { + m1 = Long.parseLong(lines[i + 1].split(" = ")[1]); + } + } else if (line.endsWith("fieldSize = 54321")) { + m2 = Long.parseLong(lines[i + 1].split(" = ")[1]); + break; + } + } + + assertLinesContainsInOrder(lines, "jdk.log.unsafeMemoryAlloc", "fieldSize = 72057594037927936", + "fieldAddress = 0", "jdk.log.unsafeMemoryAlloc", "fieldSize = 12345", "fieldAddress = " + m1, + "jdk.log.unsafeMemoryRealloc", "fieldOldAddress = " + m1, "fieldSize = 144115188075855872", + "fieldAddress = 0", "jdk.log.unsafeMemoryRealloc", "fieldOldAddress = " + m1, "fieldSize = 54321", + "fieldAddress = " + m2, "jdk.log.unsafeMemoryFree", "fieldAddress = " + m2); + } + + public void testNativeAllocs() throws IOException { + JavaAgentRunner runner = getRunner("traceUnsafeAllocations,logDest=stdout", "--add-opens", + "java.base/jdk.internal.misc=ALL-UNNAMED"); + runner.start(DO_NATIVE_ALLOCS); + runner.waitForDone(); + runner.loadAgent("dump=unsafeAllocations,logDest=stderr,mustContain=doNativeAllocs"); + runner.kill(); + assertLinesContainsRegExp(runner.getStderrLines(), "Allocated 570 bytes at"); + assertLinesContainsRegExp(runner.getStderrLines(), "Allocated 750 bytes at"); + assertLinesContainsRegExp(runner.getStderrLines(), "Printed 2 of 2 allocations with 1320 bytes"); + runner.start(DO_NATIVE_ALLOCS); + runner.waitForDone(); + runner.loadAgent("dump=unsafeAllocations,logDest=stderr,mustNotContain=reallocateMemory"); + runner.kill(); + assertLinesNotContainsRegExp(runner.getStderrLines(), "Allocated 570 bytes at"); + assertLinesContainsRegExp(runner.getStderrLines(), "Allocated 750 bytes at", + "Printed 1 of 2 allocations with 750 bytes"); + runner.start(DO_NATIVE_ALLOCS); + runner.waitForDone(); + runner.loadAgent("dump=unsafeAllocations,logDest=stderr,minStackSize=571"); + runner.kill(); + assertLinesNotContainsRegExp(runner.getStderrLines(), "Allocated 570 bytes at"); + assertLinesContainsRegExp(runner.getStderrLines(), "Allocated 750 bytes at", + "Printed 1 of 2 allocations with 750 bytes"); + runner.start(DO_NATIVE_ALLOCS); + runner.waitForDone(); + runner.loadAgent("dump=unsafeAllocations,logDest=stderr,minAge=1"); + runner.kill(); + assertLinesNotContainsRegExp(runner.getStderrLines(), "Allocated 570 bytes at", "Allocated 750 bytes at", + "Printed"); + } + + public void testRandomAllocs() throws IOException { + JavaAgentRunner runner = getRunner("traceUnsafeAllocations,dumpCount=1,dumpInterval=3s,logDest=stdout", + "--add-opens", "java.base/jdk.internal.misc=ALL-UNNAMED"); + runner.start(DO_ALLOCS); + runner.waitForDone(); + runner.loadAgent("dump=unsafeAllocations,logDest=stderr,maxFrames=8"); + runner.kill(); + assertLinesContainsRegExp(runner.getStdoutLines(), "^Printed [0-9]+ of [0-9] allocations with [0-9]+ bytes", + "^Printed [0-9]+ of [0-9] allocations with [0-9]+ bytes"); + } + + public static void doNativeAllocsForJfr() { + initUnsafe(); + + try { + allocateMemory(1L << 56); + } catch (OutOfMemoryError e) { + // Expected + } + + long m1 = allocateMemory(12345); + + try { + reallocateMemory(m1, 1L << 57); + } catch (OutOfMemoryError e) { + // Expected + } + + m1 = reallocateMemory(m1, 54321); + freeMemory(m1); + } + + public static void doNativeAllocs() { + initUnsafe(); + long a1 = 0; + + try { + a1 = allocateMemory(1L << 56); // Should fail. + } catch (OutOfMemoryError e) { + // Expected. + } + + try { + a1 = reallocateMemory(a1, 1L << 56); // Should fail. + } catch (OutOfMemoryError e) { + // Expected. + } + + a1 = allocateMemory(4027); + a1 = reallocateMemory(a1, 0); // Should act like a free + a1 = reallocateMemory(0, 570); // Should act like a malloc. + long a2 = allocateMemory(128); + freeMemory(a2); + a2 = allocateMemory(750); + done(); + } + + public void testDelayedDumping() throws IOException { + JavaAgentRunner runner = getRunner( + "traceUnsafeAllocations,dumpCount=2,minSize=7M,dumpInterval=1s," + + "minPercentage=300,logDest=stdout,exitAfterLastDump=true", + "--add-opens", "java.base/jdk.internal.misc=ALL-UNNAMED"); + runner.start(DO_DELAYED_ALLOCS); + runner.waitForStdout("Printed 2 of 2 allocations"); // Should be the last dump we see. + runner.waitForEnd(); + assertLinesNotContainsRegExp(runner.getStdoutLines(), "Printed 1 of 1 allocations"); + assertLinesContainsRegExp(runner.getStdoutLines(), "Printed 2 of 2 allocations with 8388608 bytes"); + assertLinesNotContainsRegExp(runner.getStdoutLines(), "Printed 3 of 3 allocations"); + assertLinesContainsRegExp(runner.getStdoutLines(), "Printed 4 of 4 allocations with 38797312 bytes"); + assertLinesNotContainsRegExp(runner.getStdoutLines(), DONE); + runner = getRunner( + "traceUnsafeAllocations,dumpCount=4,minSize=1M,dumpInterval=1s," + + "minPercentage=101,logDest=stdout,exitAfterLastDump=false", + "--add-opens", "java.base/jdk.internal.misc=ALL-UNNAMED"); + runner.start(DO_DELAYED_ALLOCS); + runner.waitForDone(); + runner.kill(); + assertLinesContainsRegExp(runner.getStdoutLines(), "Printed 1 of 1 allocations with 1048576 bytes", + "Printed 2 of 2 allocations with 8388608 bytes", "Printed 3 of 3 allocations with 17825792 bytes", + "Printed 4 of 4 allocations with 38797312 bytes"); + } + + public void testAgeFiltering() throws IOException { + JavaAgentRunner runner = getRunner("traceUnsafeAllocations,logDest=stdout", "--add-opens", + "java.base/jdk.internal.misc=ALL-UNNAMED"); + runner.start(DO_DELAYED_ALLOCS); + runner.waitForDone(); + runner.loadAgent("dump=unsafeAllocations,maxAge=27s,minAge=13s"); + runner.kill(); + assertLinesContainsRegExp(runner.getStderrLines(), "Printed 1 of 4 allocations with 9437184 bytes"); + runner.start(DO_DELAYED_ALLOCS); + runner.waitForDone(); + runner.loadAgent("dump=unsafeAllocations,minAge=13s"); + runner.kill(); + assertLinesContainsRegExp(runner.getStderrLines(), "Printed 3 of 4 allocations with 17825792"); + runner.start(DO_DELAYED_ALLOCS); + runner.waitForDone(); + runner.loadAgent("dump=unsafeAllocations,maxAge=27s"); + runner.kill(); + assertLinesContainsRegExp(runner.getStderrLines(), "Printed 2 of 4 allocations with 30408704 bytes"); + } + + public static void doDelayedAllocs() throws InterruptedException { + initUnsafe(); + allocateMemory(1 * 1024 * 1024); + sleep(DELAY); + allocateMemory(7 * 1024 * 1024); + sleep(DELAY); + allocateMemory(9 * 1024 * 1024); + sleep(DELAY); + allocateMemory(20 * 1024 * 1024); + sleep(DELAY); + done(); + } + + public static void runRandomAllocs(String[] args) { + initUnsafe(); + int increasePerAlloc = args.length > 1 ? Integer.parseInt(args[1]) : 256; + int maxDepth = args.length > 2 ? Integer.parseInt(args[2]) : 10; + long addr = 0; + long allocSize = increasePerAlloc; + + while (true) { + addr = doAlloc1(addr, allocSize, Math.max(2, (int) (Math.random() * maxDepth)), + (long) (Math.random() * Integer.MAX_VALUE)); + allocSize += increasePerAlloc; + } + } + + public static long doAllocImpl(long addr, long allocSize) { + long dummy = allocateMemory(1024); + addr = reallocateMemory(addr, Math.max(0, allocSize - 1024)); + addr = reallocateMemory(addr, allocSize); + freeMemory(dummy); + + return addr; + } + + public static long doAlloc1(long addr, long allocSize, int depth, long seed) { + if (depth == 0) { + return doAllocImpl(addr, allocSize); + } else if ((seed & 1) == 0) { + return doAlloc1(addr, allocSize, depth - 1, seed / 2); + } else { + return doAlloc2(addr, allocSize, depth - 1, seed / 2); + } + } + + public static long doAlloc2(long addr, long allocSize, int depth, long seed) { + if (depth == 0) { + return doAllocImpl(addr, allocSize); + } else if ((seed & 1) == 0) { + return doAlloc1(addr, allocSize, depth - 1, seed / 2); + } else { + return doAlloc2(addr, allocSize, depth - 1, seed / 2); + } + } + + private static long allocateMemory(long size) { + try { + return (Long) allocateMemoryMethod.invoke(theUnsafe, Long.valueOf(size)); + } catch (Exception e) { + if (e.getCause() instanceof OutOfMemoryError) { + throw (OutOfMemoryError) e.getCause(); + } + + e.printStackTrace(); + return 0; + } + } + + private static long reallocateMemory(long addr, long size) { + try { + return (Long) reallocateMemoryMethod.invoke(theUnsafe, Long.valueOf(addr), Long.valueOf(size)); + } catch (Exception e) { + if (e.getCause() instanceof OutOfMemoryError) { + throw (OutOfMemoryError) e.getCause(); + } + + e.printStackTrace(); + return 0; + } + } + + private static void freeMemory(long addr) { + try { + freeMemoryMethod.invoke(theUnsafe, Long.valueOf(addr)); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/VmAgnostic.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/VmAgnostic.java new file mode 100644 index 0000000000..2c1cc636b1 --- /dev/null +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/VmAgnostic.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.jmc.agent.sap.test; + +// Marker interface for tests which run on any VM (mostly because they don*t +// try to instrument classes of the VM). +public interface VmAgnostic { + +} diff --git a/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/duplicateClasses.xml b/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/duplicateClasses.xml new file mode 100644 index 0000000000..c7d3dcba01 --- /dev/null +++ b/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/duplicateClasses.xml @@ -0,0 +1,47 @@ + + + + + + + + Tracks two classes with the same name. + test/duplicateClasses + true + org.openjdk.jmc.agent.sap.test.DuplicateTracedClasses + + test + (Ljava/lang/String;)V + + + String Attribute + The first parameter + + + + ENTRY + + + diff --git a/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/generic.xml b/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/generic.xml new file mode 100644 index 0000000000..6b8c7bdf5d --- /dev/null +++ b/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/generic.xml @@ -0,0 +1,357 @@ + + + + + __JFREvent + false + true + + + + + generic + org.openjdk.jmc.agent.sap.test.GenericLoggingTest + true + false + jdk/test/generic + + tracePrimitives1 + (ZBSCIJFD)I + + + v1 + v1 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat1()V + + + v2 + v2 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat1()V + + + v3 + v3 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat1()V + + + v4 + v4 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat1()V + + + v5 + v5 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat1()V + + + v6 + v6 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat1()V + + + v7 + v7 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat1()V + + + v8 + v8 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logLastFormat1()V + + + + + + + generic + org.openjdk.jmc.agent.sap.test.GenericLoggingTest + true + false + jdk/test/generic + + tracePrimitives2 + (CBSCIJFD)I + + + v1 + v1 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat2()V + + + v2 + v2 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat2()V + + + v3 + v3 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat2()V + + + v4 + v4 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat2()V + + + v5 + v5 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat2()V + + + v6 + v6 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat2()V + + + v7 + v7 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat2()V + + + v8 + v8 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logLastFormat2()V + + + + + + + generic + org.openjdk.jmc.agent.sap.test.GenericLoggingTest + true + false + jdk/test/generic + + tracePrimitives3 + (CBSCIJFD)I + + + v1 + v1 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat3()V + + + v2 + v2 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat3()V + + + v3 + v3 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat3()V + + + v4 + v4 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat3()V + + + v5 + v5 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat3()V + + + v6 + v6 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat3()V + + + v7 + v7 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat3()V + + + v8 + v8 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logLastFormat3()V + + + + + + + generic + org.openjdk.jmc.agent.sap.test.GenericLoggingTest + true + false + jdk/test/generic + + traceObjects1 + (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I + + + v1 + v1 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat4()V + + + v2 + v2 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat4()V + + + v3 + v3 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat4()V + + + v4 + v4 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat4()V + + + v5 + v5 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat4()V + + + v6 + v6 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat4()V + + + v7 + v7 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat4()V + + + v8 + v8 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logLastFormat4()V + + + + + + + generic + org.openjdk.jmc.agent.sap.test.GenericLoggingTest + true + false + jdk/test/generic + + traceObjects2 + (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I + + + v1 + v1 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat5()V + + + v2 + v2 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat5()V + + + v3 + v3 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat5()V + + + v4 + v4 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat5()V + + + v5 + v5 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat5()V + + + v6 + v6 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat5()V + + + v7 + v7 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat5()V + + + v8 + v8 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logLastFormat5()V + + + + + + + generic + org.openjdk.jmc.agent.sap.test.GenericLoggingTest + true + false + jdk/test/generic + + traceObjects3 + (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I + + + v1 + v1 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat6()V + + + v2 + v2 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat6()V + + + v3 + v3 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat6()V + + + v4 + v4 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat6()V + + + v5 + v5 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat6()V + + + v6 + v6 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat6()V + + + v7 + v7 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logFormat6()V + + + v8 + v8 + org.openjdk.jmc.agent.sap.boot.converters.GenericLogger.logLastFormat6()V + + + + + + diff --git a/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/jconsoleMain.xml b/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/jconsoleMain.xml new file mode 100644 index 0000000000..d444ccbc5c --- /dev/null +++ b/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/jconsoleMain.xml @@ -0,0 +1,46 @@ + + + + + + + JConsole main method + test/jconsole + true + sun.tools.jconsole.JConsole + + main + ([Ljava/lang/String;)V + + + parameters + The parameters + + + + ENTRY + + + diff --git a/scripts/runagenttests.bat b/scripts/runagenttests.bat index 5703cb4d3e..3f0ab95005 100755 --- a/scripts/runagenttests.bat +++ b/scripts/runagenttests.bat @@ -3,4 +3,5 @@ echo "======== Building and testing agent =========" cd agent call mvn %MAVENPARAMS% verify || EXIT /B 4 +call mvn -P SapAgent -DfullTest=true %MAVENPARAMS% clean verify || EXIT /B 4 echo "======== Finished ===========================" diff --git a/scripts/runagenttests.sh b/scripts/runagenttests.sh index 3a990fbf45..2e69166286 100755 --- a/scripts/runagenttests.sh +++ b/scripts/runagenttests.sh @@ -4,4 +4,5 @@ set -e echo "======== Building and testing agent =========" cd agent sh -c "mvn ${MAVENPARAMS} verify" +sh -c "mvn -P SapAgent -DfullTest=true ${MAVENPARAMS} clean verify" echo "======== Finished ===========================" From fe2767058cfc6621bcc6f1f4410b503cb7198b01 Mon Sep 17 00:00:00 2001 From: Ralf Schmelter Date: Mon, 18 Aug 2025 15:14:21 +0200 Subject: [PATCH 15/25] Fixed problems in the unsafe allocation test. --- .../sap/boot/converters/UnsafeMemoryAllocationLogger.java | 4 ++-- .../org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/UnsafeMemoryAllocationLogger.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/UnsafeMemoryAllocationLogger.java index e6795f96a2..48f368c89b 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/UnsafeMemoryAllocationLogger.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/UnsafeMemoryAllocationLogger.java @@ -56,8 +56,8 @@ public class UnsafeMemoryAllocationLogger { MIN_SIZE, "The minimum size of the live allocations to dump the result.", MIN_STACK_SIZE, "The minimum size of a stack to be included in a dump.", MIN_PERCENTAGE, "The minimum percentage compared to the last dump to print a dump.", - MIN_AGE, "The minimum age in minutes to include an allocation in the output.", - MAX_AGE, "The maximum age in minutes to include an allocation in the output.", + MIN_AGE, "The minimum age to include an allocation in the output.", + MAX_AGE, "The maximum age to include an allocation in the output.", MUST_CONTAIN, "A regexp which must match at least one frame to be printed.", MUST_NOT_CONTAIN, "A regexp which must not match any frame to be printed."); command = new Command(dumpCommand, diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java index a93e0ba3c4..e19cf39c25 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java @@ -105,7 +105,7 @@ public void testNativeAllocsForJfr() throws Exception { public void testNativeAllocs() throws IOException { JavaAgentRunner runner = getRunner("traceUnsafeAllocations,logDest=stdout", "--add-opens", - "java.base/jdk.internal.misc=ALL-UNNAMED"); + "java.base/jdk.internal.misc=ALL-UNNAMED", "-XX:NativeMemoryTracking=off"); runner.start(DO_NATIVE_ALLOCS); runner.waitForDone(); runner.loadAgent("dump=unsafeAllocations,logDest=stderr,mustContain=doNativeAllocs"); @@ -129,7 +129,7 @@ public void testNativeAllocs() throws IOException { "Printed 1 of 2 allocations with 750 bytes"); runner.start(DO_NATIVE_ALLOCS); runner.waitForDone(); - runner.loadAgent("dump=unsafeAllocations,logDest=stderr,minAge=1"); + runner.loadAgent("dump=unsafeAllocations,logDest=stderr,minAge=1m"); runner.kill(); assertLinesNotContainsRegExp(runner.getStderrLines(), "Allocated 570 bytes at", "Allocated 750 bytes at", "Printed"); From 602bc5f08b0839d837e4fdfab96ef8499fb53d19 Mon Sep 17 00:00:00 2001 From: Ralf Schmelter Date: Mon, 18 Aug 2025 15:23:01 +0200 Subject: [PATCH 16/25] Increase version. --- agent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/pom.xml b/agent/pom.xml index f9639e09ee..f2da308a9b 100644 --- a/agent/pom.xml +++ b/agent/pom.xml @@ -107,7 +107,7 @@ SapAgent SapAgent - 0.9.0 + 0.9.1 From b26a6943efe58f111e85f9e16c9864363a6eca71 Mon Sep 17 00:00:00 2001 From: Ralf Schmelter Date: Thu, 21 Aug 2025 13:32:28 +0200 Subject: [PATCH 17/25] Fixed typo. --- .../java/org/openjdk/jmc/agent/sap/boot/util/Arguments.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Arguments.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Arguments.java index e26c104d14..9fcab9877f 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Arguments.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Arguments.java @@ -151,9 +151,9 @@ public double getDouble(String option, double defaultRersult) { return defaultRersult; } - private long parseUnits(String option, long defaultRersult, char[] suffixes, long[] scale) { + private long parseUnits(String option, long defaultResult, char[] suffixes, long[] scale) { if (!args.containsKey(option)) { - return defaultRersult; + return defaultResult; } String rest = getString(option, ""); From ac0e3a3d02179208d212f9daf6a553d66e323b57 Mon Sep 17 00:00:00 2001 From: Ralf Schmelter Date: Thu, 21 Aug 2025 13:57:56 +0200 Subject: [PATCH 18/25] Fixed another call. --- .../org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java index e19cf39c25..d61d032b6f 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java @@ -74,7 +74,7 @@ protected void runAllTests() throws Exception { public void testNativeAllocsForJfr() throws Exception { JavaAgentRunner runner = getRunnerWithJFR("traceUnsafeAllocations", "--add-opens", - "java.base/jdk.internal.misc=ALL-UNNAMED"); + "java.base/jdk.internal.misc=ALL-UNNAMED", "-XX:NativeMemoryTracking=off"); runner.start(DO_NATIVE_ALLOCS_FOR_JFR); runner.waitForEnd(); String[] lines = getJfrOutput("jdk.log.*", 16); From 18be95ae12e37575794b03035edbf8c472bddb1e Mon Sep 17 00:00:00 2001 From: Ralf Schmelter Date: Fri, 5 Sep 2025 10:43:10 +0200 Subject: [PATCH 19/25] Fixed agent version detection. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1a4ea65564..7d4747b7eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -74,7 +74,7 @@ jobs: echo GitHub Release Tag: $RELEASE_TAG echo "githubRelease=$(echo $RELEASE_TAG)" >> $GITHUB_OUTPUT - AGENT_REV=$(cd agent && grep -i \ pom.xml | sed 's/^[ \t]*//g;s/<\/revision>[ \t]*$//g') + AGENT_REV=$(cd agent && grep -i \ pom.xml | sed 's/^[ \t]*//g;s/<\/revision>[ \t]*$//g' | head -n 1) if [[ '${{ github.event.inputs.release || false }}' == true ]]; then AGENT_VERSION=${AGENT_REV} else From 104244fd005bc8bf7066ba621b400a733b47f04b Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Tue, 23 Jun 2026 22:49:56 +0200 Subject: [PATCH 20/25] Add required permission to build workflow (#159) * Add required permission to build workflow * Bump actions --- .github/workflows/build.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7d4747b7eb..187ae8ceda 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,7 +50,7 @@ jobs: commit: ${{ steps.buildcheck.outputs.commit }} steps: - name: Checkout JMC - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: ref: ${{ github.event.inputs.gitRef }} @@ -84,7 +84,7 @@ jobs: echo "agentVersion=$(echo $AGENT_VERSION)" >> $GITHUB_OUTPUT - name: Download existing release file - uses: robinraju/release-downloader@v1.9 + uses: robinraju/release-downloader@v1.13 continue-on-error: true with: tag: ${{ steps.versions.outputs.githubRelease }} @@ -141,22 +141,24 @@ jobs: env: MAVEN_OPTS: -Xmx2048m MAVEN_CALL: mvn --batch-mode --no-transfer-progress + permissions: + contents: write steps: - name: Delete old GitHub release ${{ needs.parameters.outputs.githubRelease }} if: ${{ needs.parameters.outputs.publish == 'true' && needs.parameters.outputs.release != 'true' }} continue-on-error: true - uses: dev-drprasad/delete-tag-and-release@v1.0 + uses: dev-drprasad/delete-tag-and-release@v1.1 with: tag_name: ${{ needs.parameters.outputs.githubRelease }} github_token: ${{ secrets.GITHUB_TOKEN }} - name: Checkout JMC - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: ref: ${{ needs.parameters.outputs.commit }} - name: Set up JDK 17 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: sapmachine java-version: '17' @@ -164,7 +166,7 @@ jobs: mvn-toolchain-id: 'JavaSE-17' - name: Set up JDK 21 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: sapmachine java-version: '21' @@ -172,12 +174,12 @@ jobs: mvn-toolchain-id: 'JavaSE-21' - name: Set up Maven - uses: stCarolas/setup-maven@v4.5 + uses: stCarolas/setup-maven@v5 with: maven-version: 3.9.8 - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v6 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} From e9da9b958c0d60fbf067a170f4c40957f7abb5cd Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Wed, 24 Jun 2026 13:01:54 +0200 Subject: [PATCH 21/25] Fix copyright checks for SAP JMC variant and a few license headers (#160) --- .../java/org/openjdk/jmc/agent/SapAgent.java | 38 +++++++++------- .../jmc/agent/SapTransformRegistry.java | 38 +++++++++------- .../org/openjdk/jmc/agent/SapTransformer.java | 38 +++++++++------- .../sap/boot/converters/AllocationSite.java | 38 +++++++++------- .../boot/converters/AllocationStatistic.java | 38 +++++++++------- .../AllocationStatisticDumpFilter.java | 38 +++++++++------- .../boot/converters/FileOpenCloseLogger.java | 38 +++++++++------- .../sap/boot/converters/GenericLogger.java | 38 +++++++++------- .../boot/converters/LocaleChangeLogger.java | 38 +++++++++------- .../converters/SystemPropChangeLogger.java | 38 +++++++++------- .../boot/converters/TimeZoneChangeLogger.java | 38 +++++++++------- .../UnsafeMemoryAllocationLogger.java | 38 +++++++++------- .../jmc/agent/sap/boot/util/Arguments.java | 38 +++++++++------- .../agent/sap/boot/util/ArgumentsHolder.java | 39 +++++++++------- .../jmc/agent/sap/boot/util/Command.java | 38 +++++++++------- .../jmc/agent/sap/boot/util/Commands.java | 38 +++++++++------- .../jmc/agent/sap/boot/util/Dumps.java | 38 +++++++++------- .../jmc/agent/sap/boot/util/LoggingUtils.java | 38 +++++++++------- .../agent/sap/boot/util/OutputCommand.java | 38 +++++++++------- .../jmc/agent/sap/test/CloneClassLoader.java | 38 +++++++++------- .../sap/test/DuplicateTracedClasses.java | 38 +++++++++------- .../agent/sap/test/GenericLoggingTest.java | 38 +++++++++------- .../jmc/agent/sap/test/JavaAgentRunner.java | 38 +++++++++------- .../jmc/agent/sap/test/LocaleChangeTest.java | 38 +++++++++------- .../agent/sap/test/OpenFileStatisticTest.java | 38 +++++++++------- .../jmc/agent/sap/test/OutputReader.java | 38 +++++++++------- .../agent/sap/test/SapIntegrationTest.java | 38 +++++++++------- .../agent/sap/test/SysPropsChangeTest.java | 38 +++++++++------- .../openjdk/jmc/agent/sap/test/TestBase.java | 38 +++++++++------- .../jmc/agent/sap/test/TestRunner.java | 38 +++++++++------- .../agent/sap/test/TimeZoneChangeTest.java | 38 +++++++++------- .../agent/sap/test/UnsafeAllocationTest.java | 38 +++++++++------- .../jmc/agent/sap/test/VmAgnostic.java | 38 +++++++++------- .../jmc/agent/test/sap/duplicateClasses.xml | 44 +++++++++++-------- .../openjdk/jmc/agent/test/sap/generic.xml | 37 ++++++++++------ .../jmc/agent/test/sap/jconsoleMain.xml | 43 +++++++++++------- scripts/checkcopyrightyear.sh | 10 ++--- 37 files changed, 839 insertions(+), 550 deletions(-) diff --git a/agent/src/main/java/org/openjdk/jmc/agent/SapAgent.java b/agent/src/main/java/org/openjdk/jmc/agent/SapAgent.java index d487b3abcd..9db2ac9385 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/SapAgent.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/SapAgent.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent; import java.io.ByteArrayInputStream; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/SapTransformRegistry.java b/agent/src/main/java/org/openjdk/jmc/agent/SapTransformRegistry.java index 63882f0845..3081b953c7 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/SapTransformRegistry.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/SapTransformRegistry.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent; import java.util.ArrayList; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/SapTransformer.java b/agent/src/main/java/org/openjdk/jmc/agent/SapTransformer.java index 9f41d61697..44f4ee4f51 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/SapTransformer.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/SapTransformer.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent; import java.lang.instrument.ClassFileTransformer; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationSite.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationSite.java index 7d1bce9a08..1f2f9e5f54 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationSite.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationSite.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.converters; import java.io.PrintStream; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatistic.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatistic.java index 5c117d710d..16db113cd3 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatistic.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatistic.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.converters; import java.io.PrintStream; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatisticDumpFilter.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatisticDumpFilter.java index 96dc20bd61..84cfcf753c 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatisticDumpFilter.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/AllocationStatisticDumpFilter.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.converters; import java.util.regex.Pattern; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/FileOpenCloseLogger.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/FileOpenCloseLogger.java index 6077dcf8e4..d925fd09d6 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/FileOpenCloseLogger.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/FileOpenCloseLogger.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.converters; import java.io.File; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/GenericLogger.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/GenericLogger.java index 66f5a9a1a7..2fa1fc2c2a 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/GenericLogger.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/GenericLogger.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.converters; import java.lang.reflect.Array; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/LocaleChangeLogger.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/LocaleChangeLogger.java index f278103014..ec5ad085db 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/LocaleChangeLogger.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/LocaleChangeLogger.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.converters; import java.util.Locale; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/SystemPropChangeLogger.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/SystemPropChangeLogger.java index 2dbeb0c006..aa04c2f42f 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/SystemPropChangeLogger.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/SystemPropChangeLogger.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.converters; import java.security.AccessController; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/TimeZoneChangeLogger.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/TimeZoneChangeLogger.java index 35ed931267..4cc0051193 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/TimeZoneChangeLogger.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/TimeZoneChangeLogger.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.converters; import java.util.TimeZone; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/UnsafeMemoryAllocationLogger.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/UnsafeMemoryAllocationLogger.java index 48f368c89b..6d823b501f 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/UnsafeMemoryAllocationLogger.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/converters/UnsafeMemoryAllocationLogger.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.converters; import org.openjdk.jmc.agent.sap.boot.util.ArgumentsHolder; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Arguments.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Arguments.java index 9fcab9877f..acd4c86cf0 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Arguments.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Arguments.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.util; import java.util.HashMap; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/ArgumentsHolder.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/ArgumentsHolder.java index 50243b4b74..05fca1b3f1 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/ArgumentsHolder.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/ArgumentsHolder.java @@ -1,27 +1,34 @@ /* - * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.util; public class ArgumentsHolder { diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Command.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Command.java index cbc682d196..64e583c993 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Command.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Command.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.util; import java.io.PrintStream; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Commands.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Commands.java index 49b343b673..d132818938 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Commands.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Commands.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.util; import org.openjdk.jmc.agent.sap.boot.converters.GenericLogger; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Dumps.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Dumps.java index 0922e74603..ac0620ccab 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Dumps.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/Dumps.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.util; import java.io.IOException; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/LoggingUtils.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/LoggingUtils.java index 011a5963b4..9184320348 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/LoggingUtils.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/LoggingUtils.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.util; import java.io.FileNotFoundException; diff --git a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/OutputCommand.java b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/OutputCommand.java index 38a2fca9ca..48a39095c6 100644 --- a/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/OutputCommand.java +++ b/agent/src/main/java/org/openjdk/jmc/agent/sap/boot/util/OutputCommand.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.boot.util; public class OutputCommand extends Command { diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/CloneClassLoader.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/CloneClassLoader.java index 7631385c57..4fdd131e9e 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/CloneClassLoader.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/CloneClassLoader.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; import java.io.IOException; diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/DuplicateTracedClasses.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/DuplicateTracedClasses.java index 0dcb2870df..bb53ab949b 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/DuplicateTracedClasses.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/DuplicateTracedClasses.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; import java.lang.reflect.Method; diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/GenericLoggingTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/GenericLoggingTest.java index ab044c880a..3b282ef72e 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/GenericLoggingTest.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/GenericLoggingTest.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; import java.io.File; diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/JavaAgentRunner.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/JavaAgentRunner.java index d06f274434..7fa2551ddc 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/JavaAgentRunner.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/JavaAgentRunner.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; import java.io.File; diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/LocaleChangeTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/LocaleChangeTest.java index 19884c5c45..de89344d98 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/LocaleChangeTest.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/LocaleChangeTest.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; import java.util.Locale; diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OpenFileStatisticTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OpenFileStatisticTest.java index fe3ba3864b..52b35e5de8 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OpenFileStatisticTest.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OpenFileStatisticTest.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; import java.io.File; diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OutputReader.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OutputReader.java index ed4ccdc23f..0b9c96b462 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OutputReader.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/OutputReader.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; import java.io.IOException; diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SapIntegrationTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SapIntegrationTest.java index d8e99e13bb..b7ae4b7b3e 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SapIntegrationTest.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SapIntegrationTest.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; import java.util.ArrayList; diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SysPropsChangeTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SysPropsChangeTest.java index 5a6eb4998e..21595b59b9 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SysPropsChangeTest.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/SysPropsChangeTest.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; import java.io.File; diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestBase.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestBase.java index e765b7ab9b..71e20f67d2 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestBase.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestBase.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; import java.io.File; diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestRunner.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestRunner.java index 9cc8038377..481b61ad0f 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestRunner.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TestRunner.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; import java.lang.reflect.Method; diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TimeZoneChangeTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TimeZoneChangeTest.java index 19b50f9e69..89b349b759 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TimeZoneChangeTest.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/TimeZoneChangeTest.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; import java.util.TimeZone; diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java index d61d032b6f..c5fe739cd5 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/UnsafeAllocationTest.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; import java.io.IOException; diff --git a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/VmAgnostic.java b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/VmAgnostic.java index 2c1cc636b1..cc30165fb7 100644 --- a/agent/src/test/java/org/openjdk/jmc/agent/sap/test/VmAgnostic.java +++ b/agent/src/test/java/org/openjdk/jmc/agent/sap/test/VmAgnostic.java @@ -1,27 +1,35 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. + * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at https://oss.oracle.com/licenses/upl + * + * or the following license: * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.openjdk.jmc.agent.sap.test; // Marker interface for tests which run on any VM (mostly because they don*t diff --git a/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/duplicateClasses.xml b/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/duplicateClasses.xml index c7d3dcba01..fe40ae362c 100644 --- a/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/duplicateClasses.xml +++ b/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/duplicateClasses.xml @@ -4,25 +4,33 @@ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - This code is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License version 2 only, as - published by the Free Software Foundation. - - This code is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - version 2 for more details (a copy is included in the LICENSE file that - accompanied this code). - - You should have received a copy of the GNU General Public License version - 2 along with this work; if not, write to the Free Software Foundation, - Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - - Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - or visit www.oracle.com if you need additional information or have any - questions. - --> + The contents of this file are subject to the terms of either the Universal Permissive License + v 1.0 as shown at https://oss.oracle.com/licenses/upl + + or the following license: + + Redistribution and use in source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials provided with + the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to + endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + --> diff --git a/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/generic.xml b/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/generic.xml index 6b8c7bdf5d..7b44fb2b95 100644 --- a/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/generic.xml +++ b/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/generic.xml @@ -4,23 +4,32 @@ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - This code is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License version 2 only, as - published by the Free Software Foundation. + The contents of this file are subject to the terms of either the Universal Permissive License + v 1.0 as shown at https://oss.oracle.com/licenses/upl - This code is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - version 2 for more details (a copy is included in the LICENSE file that - accompanied this code). + or the following license: - You should have received a copy of the GNU General Public License version - 2 along with this work; if not, write to the Free Software Foundation, - Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + Redistribution and use in source and binary forms, with or without modification, are permitted + provided that the following conditions are met: - Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - or visit www.oracle.com if you need additional information or have any - questions. + 1. Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials provided with + the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to + endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> diff --git a/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/jconsoleMain.xml b/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/jconsoleMain.xml index d444ccbc5c..42f1de83af 100644 --- a/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/jconsoleMain.xml +++ b/agent/src/test/resources/org/openjdk/jmc/agent/test/sap/jconsoleMain.xml @@ -4,23 +4,32 @@ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - This code is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License version 2 only, as - published by the Free Software Foundation. - - This code is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - version 2 for more details (a copy is included in the LICENSE file that - accompanied this code). - - You should have received a copy of the GNU General Public License version - 2 along with this work; if not, write to the Free Software Foundation, - Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - - Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - or visit www.oracle.com if you need additional information or have any - questions. + The contents of this file are subject to the terms of either the Universal Permissive License + v 1.0 as shown at https://oss.oracle.com/licenses/upl + + or the following license: + + Redistribution and use in source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials provided with + the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to + endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> diff --git a/scripts/checkcopyrightyear.sh b/scripts/checkcopyrightyear.sh index d10a0d4313..cc4c8700c7 100755 --- a/scripts/checkcopyrightyear.sh +++ b/scripts/checkcopyrightyear.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash # set remote for upstream repository -git remote -v | grep -w upstream || git remote add upstream https://github.com/openjdk/jmc.git +git remote -v | grep -w upstream || git remote add upstream https://github.com/SAP/jmc.git git fetch upstream CURRENT_YEAR=$(date +'%Y') -COMMITTED_FILES=$(git diff --name-only --diff-filter=d upstream/master...HEAD) +COMMITTED_FILES=$(git diff --name-only --diff-filter=d upstream/sap...HEAD) UNCOMMITTED_FILES=$(git diff --name-only --diff-filter=d) MODIFIED_FILES=$(echo -e "$COMMITTED_FILES\n$UNCOMMITTED_FILES" | sort -u | grep -v '^$') counter=0 @@ -26,13 +26,13 @@ do done if [ $counter -ne 0 ] then - # check if the PR branch is up-to-date with upstream/master + # check if the PR branch is up-to-date with upstream/sap # borrowed from: https://stackoverflow.com/a/39402294 - if git merge-base --is-ancestor upstream/master @ + if git merge-base --is-ancestor upstream/sap @ then echo "Branch is up-to-date." else - echo "Branch is out of date with upstream/master. Please rebase your branch and try again." + echo "Branch is out of date with upstream/sap. Please rebase your branch and try again." exit 1 fi echo "There is a total of $counter copyright year(s) that require updating." From 6a859e32ff58b63445f6d1d3a1852721657b0a3b Mon Sep 17 00:00:00 2001 From: Ralf Schmelter Date: Fri, 5 Jun 2026 11:34:41 +0200 Subject: [PATCH 22/25] Updated sap agent version to 0.9.3 --- agent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/pom.xml b/agent/pom.xml index be055b2a77..b5f7224c66 100644 --- a/agent/pom.xml +++ b/agent/pom.xml @@ -107,7 +107,7 @@ SapAgent SapAgent - 0.9.1 + 0.9.3 From 73c2013df6378eb7fe180f0f484b0ba5d55e5226 Mon Sep 17 00:00:00 2001 From: I571857 Date: Thu, 2 Jul 2026 10:29:23 +0200 Subject: [PATCH 23/25] fix --- .github/workflows/sync-fork-checks.yml | 276 +++++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 .github/workflows/sync-fork-checks.yml diff --git a/.github/workflows/sync-fork-checks.yml b/.github/workflows/sync-fork-checks.yml new file mode 100644 index 0000000000..c5391a43be --- /dev/null +++ b/.github/workflows/sync-fork-checks.yml @@ -0,0 +1,276 @@ +# +# Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2024, Datadog, Inc. All rights reserved. +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# The contents of this file are subject to the terms of either the Universal Permissive License +# v 1.0 as shown at https://oss.oracle.com/licenses/upl +# +# or the following license: +# +# Redistribution and use in source and binary forms, with or without modification, are permitted +# provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions +# and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or other materials provided with +# the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to +# endorse or promote products derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# Fires in the upstream repo context when a PR from a fork is opened or updated. +# Polls the fork repo's Actions API for the "Validation" +# run on the PR head commit, then mirrors every individual job as a native +# Check Run on the upstream PR — matching the appearance of the fork's own +# checks tab. No submit branches are created; no CI is re-run upstream. +name: 'Mirror Checks from Source Fork' + +on: + pull_request_target: + types: + - opened + - synchronize + - reopened + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + checks: write + pull-requests: read + +jobs: + mirror: + name: 'Sync Actions from Fork' + runs-on: ubuntu-24.04 + # Only act on fork PRs — same-repo PRs get CI directly from main.yml. + if: github.event.pull_request.head.repo.full_name != github.repository + steps: + - name: 'Poll fork CI and mirror per-job results' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + HEAD_REF: ${{ github.event.pull_request.head.ref }} + PR_NUMBER: ${{ github.event.pull_request.number }} + FORK_REPO: ${{ github.event.pull_request.head.repo.full_name }} + UPSTREAM_REPO: ${{ github.repository }} + run: | + # ── Phase 1: Wait for the fork workflow run to appear ─────────────── + # The fork may not have triggered its CI yet immediately after push. + MAX_WAIT=20 + ATTEMPT=0 + RUN_ID="" + + while [[ $ATTEMPT -lt $MAX_WAIT ]]; do + ATTEMPT=$((ATTEMPT + 1)) + echo "Waiting for workflow run on fork (attempt ${ATTEMPT}/${MAX_WAIT})..." + + RUN_ID=$(gh api \ + "repos/${FORK_REPO}/actions/runs?head_sha=${HEAD_SHA}&per_page=10" \ + --jq '.workflow_runs[] | select(.name == "Validation") | .id' \ + 2>/dev/null | head -1) + + if [[ -n "$RUN_ID" && "$RUN_ID" != "null" ]]; then + echo "Found workflow run on fork: ${RUN_ID}" + break + fi + + # Fallback for reopened PRs: no new run may exist for HEAD_SHA, + # so locate the latest pull_request run for this PR number/branch. + RUN_ID=$(gh api \ + "repos/${FORK_REPO}/actions/runs?event=pull_request&branch=${HEAD_REF}&per_page=50" \ + --jq '.workflow_runs[] + | select(.name == "Validation") + | select(any(.pull_requests[]?; .number == ('"${PR_NUMBER}"' | tonumber))) + | .id' \ + 2>/dev/null | head -1) + + if [[ -n "$RUN_ID" && "$RUN_ID" != "null" ]]; then + echo "Found workflow run on fork via PR fallback: ${RUN_ID}" + break + fi + + sleep 60 + done + + if [[ -z "$RUN_ID" || "$RUN_ID" == "null" ]]; then + echo "No workflow run found on fork within ${MAX_WAIT} minutes — giving up." + exit 1 + fi + + # ── Phase 2: Mirror each fork job as an upstream Check Run ────────── + # job name → upstream check run ID + declare -A JOB_CHECK_RUN_IDS + # job name → '1' once the check run has been finalized + declare -A JOB_DONE + # job name → fork job HTML URL + declare -A JOB_URLS + + MAX_POLL=180 + POLL=0 + OVERALL_CONCLUSION="" + + while [[ $POLL -lt $MAX_POLL ]]; do + POLL=$((POLL + 1)) + echo "Poll ${POLL}/${MAX_POLL} — syncing fork job statuses..." + + JOBS_JSON=$(gh api \ + "repos/${FORK_REPO}/actions/runs/${RUN_ID}/jobs?per_page=100" \ + 2>/dev/null) + + if [[ -z "$JOBS_JSON" ]]; then + sleep 60 + continue + fi + + JOB_COUNT=$(echo "$JOBS_JSON" | jq '.jobs | length') + + for i in $(seq 0 $((JOB_COUNT - 1))); do + JOB_NAME=$(echo "$JOBS_JSON" | jq -r ".jobs[$i].name") + JOB_STATUS=$(echo "$JOBS_JSON" | jq -r ".jobs[$i].status") + JOB_CONCLUSION=$(echo "$JOBS_JSON" | jq -r ".jobs[$i].conclusion") + JOB_URL=$(echo "$JOBS_JSON" | jq -r ".jobs[$i].html_url") + + # Create a Check Run for this job the first time we see it. + JOB_URLS[$JOB_NAME]="$JOB_URL" + if [[ -z "${JOB_CHECK_RUN_IDS[$JOB_NAME]}" ]]; then + echo " Creating check run: ${JOB_NAME}" + CR_ID=$(gh api \ + -X POST \ + "repos/${UPSTREAM_REPO}/check-runs" \ + -f name="${JOB_NAME}" \ + -f head_sha="${HEAD_SHA}" \ + -f status="in_progress" \ + -f output[title]="Waiting for fork job: ${JOB_NAME}" \ + -f output[summary]="Polling fork repository for job '${JOB_NAME}' on commit ${HEAD_SHA}. [View job](${JOB_URL})" \ + --jq '.id') + JOB_CHECK_RUN_IDS[$JOB_NAME]=$CR_ID + echo " → check run ID: ${CR_ID}" + fi + + # Finalize any job that has completed since the last poll. + if [[ "$JOB_STATUS" == "completed" && -z "${JOB_DONE[$JOB_NAME]}" ]]; then + CR_ID="${JOB_CHECK_RUN_IDS[$JOB_NAME]}" + # Guard against null conclusion (e.g. cancelled mid-queue). + [[ -z "$JOB_CONCLUSION" || "$JOB_CONCLUSION" == "null" ]] && JOB_CONCLUSION="cancelled" + + if [[ "$JOB_CONCLUSION" == "success" ]]; then + TITLE="Passed: ${JOB_NAME}" + SUMMARY="Job **${JOB_NAME}** passed on the fork. [View job](${JOB_URL})" + else + TITLE="${JOB_CONCLUSION^}: ${JOB_NAME}" + SUMMARY="Job **${JOB_NAME}** reported **${JOB_CONCLUSION}** on the fork. [View job](${JOB_URL})" + fi + + gh api \ + -X PATCH \ + "repos/${UPSTREAM_REPO}/check-runs/${CR_ID}" \ + -f status="completed" \ + -f conclusion="${JOB_CONCLUSION}" \ + -f output[title]="${TITLE}" \ + -f output[summary]="${SUMMARY}" \ + -f details_url="${JOB_URL}" + + JOB_DONE[$JOB_NAME]=1 + echo " ✓ Finalized ${JOB_NAME}: ${JOB_CONCLUSION}" + fi + done + + # Check whether the overall run has finished. + RUN_JSON=$(gh api \ + "repos/${FORK_REPO}/actions/runs/${RUN_ID}" \ + --jq '{status: .status, conclusion: .conclusion}' \ + 2>/dev/null) + + RUN_STATUS=$(echo "$RUN_JSON" | jq -r '.status') + OVERALL_CONCLUSION=$(echo "$RUN_JSON" | jq -r '.conclusion') + + if [[ "$RUN_STATUS" == "completed" ]]; then + echo "Workflow run on fork completed with conclusion: ${OVERALL_CONCLUSION}" + # Do one final job sync to catch any jobs that finished in this last window. + JOBS_JSON=$(gh api \ + "repos/${FORK_REPO}/actions/runs/${RUN_ID}/jobs?per_page=100" \ + 2>/dev/null) + JOB_COUNT=$(echo "$JOBS_JSON" | jq '.jobs | length') + for i in $(seq 0 $((JOB_COUNT - 1))); do + JOB_NAME=$(echo "$JOBS_JSON" | jq -r ".jobs[$i].name") + JOB_STATUS=$(echo "$JOBS_JSON" | jq -r ".jobs[$i].status") + JOB_CONCLUSION=$(echo "$JOBS_JSON" | jq -r ".jobs[$i].conclusion") + JOB_URL=$(echo "$JOBS_JSON" | jq -r ".jobs[$i].html_url") + if [[ -z "${JOB_CHECK_RUN_IDS[$JOB_NAME]}" ]]; then + CR_ID=$(gh api \ + -X POST \ + "repos/${UPSTREAM_REPO}/check-runs" \ + -f name="${JOB_NAME}" \ + -f head_sha="${HEAD_SHA}" \ + -f status="in_progress" \ + -f output[title]="Waiting for fork job: ${JOB_NAME}" \ + -f output[summary]="Polling fork repository for job '${JOB_NAME}' on commit ${HEAD_SHA}. [View job](${JOB_URL})" \ + --jq '.id') + JOB_CHECK_RUN_IDS[$JOB_NAME]=$CR_ID + fi + if [[ "$JOB_STATUS" == "completed" && -z "${JOB_DONE[$JOB_NAME]}" ]]; then + CR_ID="${JOB_CHECK_RUN_IDS[$JOB_NAME]}" + [[ -z "$JOB_CONCLUSION" || "$JOB_CONCLUSION" == "null" ]] && JOB_CONCLUSION="cancelled" + if [[ "$JOB_CONCLUSION" == "success" ]]; then + TITLE="Passed: ${JOB_NAME}" + SUMMARY="Job **${JOB_NAME}** passed on the fork. [View job](${JOB_URL})" + else + TITLE="${JOB_CONCLUSION^}: ${JOB_NAME}" + SUMMARY="Job **${JOB_NAME}** reported **${JOB_CONCLUSION}** on the fork. [View job](${JOB_URL})" + fi + gh api \ + -X PATCH \ + "repos/${UPSTREAM_REPO}/check-runs/${CR_ID}" \ + -f status="completed" \ + -f conclusion="${JOB_CONCLUSION}" \ + -f output[title]="${TITLE}" \ + -f output[summary]="${SUMMARY}" \ + -f details_url="${JOB_URL}" + JOB_DONE[$JOB_NAME]=1 + echo " ✓ Finalized ${JOB_NAME}: ${JOB_CONCLUSION}" + fi + done + break + fi + + sleep 60 + done + + # ── Phase 3: Handle timeout ───────────────────────────────────────── + if [[ -z "$OVERALL_CONCLUSION" || "$OVERALL_CONCLUSION" == "null" ]]; then + OVERALL_CONCLUSION="timed_out" + echo "Timed out — marking remaining open check runs." + for JOB_NAME in "${!JOB_CHECK_RUN_IDS[@]}"; do + if [[ -z "${JOB_DONE[$JOB_NAME]}" ]]; then + CR_ID="${JOB_CHECK_RUN_IDS[$JOB_NAME]}" + gh api \ + -X PATCH \ + "repos/${UPSTREAM_REPO}/check-runs/${CR_ID}" \ + -f status="completed" \ + -f conclusion="timed_out" \ + -f output[title]="Timed out: ${JOB_NAME}" \ + -f output[summary]="The polling window expired before job '${JOB_NAME}' completed. [View job](${JOB_URLS[$JOB_NAME]})" + fi + done + fi + + # Exit non-zero so the upstream PR shows a red check if CI did not pass. + if [[ "$OVERALL_CONCLUSION" != "success" ]]; then + exit 1 + fi From 601bed1776fc692cedc888e136df3f431cfd0385 Mon Sep 17 00:00:00 2001 From: I571857 Date: Thu, 2 Jul 2026 10:38:31 +0200 Subject: [PATCH 24/25] fix node --- .github/workflows/validate.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 601ccb1daf..f50a1eb851 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -48,7 +48,7 @@ jobs: shell: bash steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 - name : Check latest copyright year @@ -68,7 +68,7 @@ jobs: MAVENPARAMS: --batch-mode --no-transfer-progress steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up Java 17 uses: actions/setup-java@v4 with: From 94ee5d7bf3740b4e689d7dafdf2379d22619ec2a Mon Sep 17 00:00:00 2001 From: I571857 Date: Thu, 2 Jul 2026 10:45:32 +0200 Subject: [PATCH 25/25] fix --- .github/workflows/sync-fork-checks.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/sync-fork-checks.yml b/.github/workflows/sync-fork-checks.yml index c5391a43be..d1ce858d73 100644 --- a/.github/workflows/sync-fork-checks.yml +++ b/.github/workflows/sync-fork-checks.yml @@ -1,6 +1,5 @@ # -# Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. -# Copyright (c) 2019, 2024, Datadog, Inc. All rights reserved. +# Copyright (c) 2026 SAP SE. All rights reserved. # # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. #