Thread: [Webwork-devel] ValueStack abstraction
Brought to you by:
baldree,
rickardoberg
From: Sven K. <sv...@im...> - 2002-05-21 18:20:45
|
Some time ago, I told you about integrating Webwork into Cocoon2. Meanwhile, I have mostly finished this task. There is a WebWorkAdapterAction which enables Cocoon to act as a WW dispatcher, a WebWorkGenerator that clones XSLTServlet's behavior and a XSP taglib that is roughly equivalent to the JSP tags. The last component still needs some work (most notably implementing some ui:tags) before I can make it publicly available for interested parties. Surprisingly, the integration task was quite easy. I only had to modify WebWork itself in one point: WW's ValueStack depends on HttpServletRequest and ServletContext. Both of which are generally not available to Cocoon components. Instead, they use their own Request et al. fascades, which will be available even in C2's offline mode. In order to deal with this, I made a servlet agnostic AbstractValueStack which basically does the same thing as the WW original. Except that it delegates expression evaluation to abstract methods when needed. The required methods findInContext and getRequestParameter are implemented in a servlet aware ValueStack (and its Cocoon counter part). I have attached the two source files in question. Modifications are marked with SK. My question is whether such an architecture could find its way into the original WW dist. Or is there's even a smarter way to make ValueStack useable in a non-servlet context. The same question goes for ActionContext BTW. In that case, the modification is not strictly necessary, though. Sven.... begin 666 ValueStack.zip M4$L#!!0````(`%R<M2R=/D+XH0,``(\+```/````5F%L=653=&%C:RYJ879A MY5;;;MLX$'U.@/S#+- 'V7!E%/M6(X"-[ 7=17>-N)?'@I+&-A.9U)*4W"#( M;_9[.D.*NJ1NN]OM/JT20#0Y<V;FS(6:3R_.I_ 6L[?:W,YX`:NJ*F4NG-0* M?C'B@$<Z(BD6_$E:9V16.Y&5"+4JT)"\R/<(I(/*8LIB&T1P: X6]#8>@'"@ M*UKIVN28:K,CR?G%.6G?BAW"$3,VE-9.EHN+\XMS>:BT<7 C&O$^M6B:$EVZ M">]K_*M&ZQ:?D;JQ5;HFT"NM'+YW'FX^I0A@>O9&E#6"=6062+G$`RH7HMUJ M`P):$,B$Q0(L.2^,U"DK>X"EJ-V>)*\E.6X*^)"AV4%BPL_E019%B4=A\&FN M#Y50=RF])ZP*_HGZ+T5-.@A7*:R%N24FDT/86C92X1V!D6=H*B.)UHAQMFS0 M6/;VR34VDE?/X5GZXS-XPL=,:)T1Y9"7PEKPT6Y\L$0$JL+"*J,<BMSU1_?, M#WDVGP,Q1J=U[LC!I__\\3"M`SU^,H%[?\*/K2LTR63A-QZB99\<>J;P*U'O MJ)Z:09Y"8G:R004FI#Z%%UN6,PC2@M)1/2A0-<B2:W0&N4'A$+3BTO0R4719 M"2IO6K:0X.W&'VSSN)?YGDO"@]J]*$O(6,351F'1`84-']XCUUN1^9 8R^4V MY =VZ )1X_*.O@SH&R@%IRXAZ?<F'3N$N'*A53'9O%I=_?[NC]7+GUO:Z9%; M2%J$2U!U60YS!!VXPN,HD8N!3+1E3]N:!9!>Y2$N_#ZKM7$F,<Y.M"74"WYS MI50\5O(P`KYGN;20(==#(^ T4-/I7#+$4;J]%QD6PG>LE<& BPX,<GBZDBBC MD9!=3W_/^_^DO#J)EK\D\O<W"I#&<</I/4WP8B1S(D6+?M:N6ZEOF+/=K!VT MPZ9MAYAJMZ<;U^YU718\M+K"+&)E4B,$(B+"*]ZB_YSF'(EQ+R'=[5#3[:VW M?2V#U0%=Q+RPCO)6\ARM[4=C9>C.-^7=UV;ON/9;8AHMZ0+N\_C5Z<@QI7VI MCW)R8H!$QL8]_-_1)A7-IM\VZZX'_PTIL72_/ 8\(S&TRT$1#ACA)#G,.<0_ MLQM:P%:JXH6*%C:49+4#64R&+=PV><3^X52;CWHI!LW@?4,3ZH*;X35_;'4$ MH6JDT8H_S<9P#X ET?I9(R<'5+1Q31]EY=V,_4;ZBIIQA@JZ&79*&WQD)_QL M7X]I:AGI1^B:$X?TL38FZ^Q3KWI)]JJSPG_T^@A02P,$% ````@`6IRU+-M] M?+A%%@``+64``!<```!!8G-T<F%C=%9A;'5E4W1A8VLN:F%V8>T\;7/;-I.? MFYG\!T33>2K9#IW>W2>[OB>.XZ:>QB]G*^UU'$\'$B&)-D4R)&5'>1[_S?L] MM[L`"( $*<6)V]XSIP^)+"Z ?=_%8L'MC:=/-MBO8O1KFM]LX1>VGV5Q-.9E ME";LQYS/Q1T\`B@$?!T591Z-%B4?Q8(MDE#D`,_',\%@C$@*$2#8A1"L%/F\ M8.E$/V"\9&D&W])%/A9!FD\!<OOI$QA]PZ>"W8D1+A0LRBC>??KDZ9-HGJ4Y MC,FG`:<E@CB=_L=U<,!+,4WSY6X%HH>*CUD>G/&\$(<?QR)#"KJ <GN9:W[+ M@Y'@21%L[+J_1FEP`50GTW/!0QIE/XUY,@UR,8G%N SVQV-1%!$PYW1T#3]T MP1Z+<I:&G1!I&$VBQHK((4+RZ9/M#1 +V_CF%QXO!"M*X&7 ]MDO%RPJV*(0 M(1LM60G241)FQ;(HQ9SQ@G%VQ^%9RN;\1N D[!8G@0>W/(I)OC!V40#=-$.V M*&:,)R'+THS-"?<B8,.96+(Q3Q DH5E&(&GB@ES<3#")DG"C&HFPA/I+OH!? M<G8>@1[D(?N?D<BGK)_+/U_.HS",Q1W/Q?-Q.L]XL@S@_P$M11\]_I@O8(Q@ M!P$#Z=Z 8O;G\J>7MU$BEC"92$ ILSP"+=5S?//R5N0%JOJWY^(VPF_?XN^H MF(L1J"[C(U!Y/B[9..9%P?;5G\3Q"V3X/P">L>UM!G^5,( ]?]B'IE&+%G(J M8!F/F50^=C'</_CY]Y/]XT.VQWI:G7-1+.*RMTNCU;!CGDEL09I[+!%W["=> MS.#7_F 7$96:!V(#HY*KYM$M6)4>KRV,@<'!!/K/8"K*HP1@DK'H&_H#6FI M^HB,()6$SP8[B 7/2?9S:T54&M#.^:(H45G&/(Y!5:()`NJ1W/)!``M$ECPO M11@H`/7?MH=GMVD$"^'*DLRB/V!21/!IXPH]O]<4;+/]4KHY`'VX*!53WX+/ ME+9%WX"?:8SF#;05P>'QV?"WW]\>70QWG4'20;',^"F)V $,*O/%N 2-_T(= M:VIRQ2F+$V<2^($Z_;RN$F?D120[6)J ^T'UN+7<ERMA]A)8P.?P5<(8<)\* MD.S141%-?>F#);BE!*!J?4L>;0*Q1NCEE0!1=_;SG"_Q;ZT]%MML\("'H5Q- M6@BP%#]@64$H1HMIOT<L`4983-CI(7 #M$RE*^@/K,>(S'"6IW?HLON#`#0H M*4F<0Y"N<)2[(0UPY5H8DSR=KQ1&+LI%GD@I0!S(P'!;A:&X#V!2&A8_2_ M M-G/5M(9IN9BGM\)(*2BB3SC#<_:]Q6[P'>5XQOI'D(=\/%V4IY-7*>0D117] MF1CXUDD6<6S-0EXV)HP43^L2`C81>]I$M(:8/D-44EJV&1J)G1,%!0D`>8() MUII"T^ 6J$]L@!)3W*Y85Y</>[9'3/Q[74 [+W9783X\?W>(/KV&-?XDYEFY M;$,?O)Y (-\8'QVC-(4@@.'C$$$\Y"@JP0%T85VD\2VD-%4&A?DCYGB@71AQ MQ!RRBE:G98"])J1QE$%<R[(QR$L7Q*:RKU(#,\*B4H<0<%@0N.5??0MRUW@K M/2=DOW<P9(]->%P("Z!NL!5@%A >'J-T\W"6U4RQ1#L@BS@"YSOE\7X^72 O MJR']WOOD?;(/1ISG$.W2\7B1Y^!P[F81Y*88&75F:8C:8>\3G/U]K\<VK=7D MQQ+=)NN]A_E]4)G 1.<8`&%;(FVXX=Z5$"4;7.6A3/!GIKYO;+ ?(>^MO"QD MQ%$8>&(O(@?NLF#%8J2SE#)5ZT&J.^.@A44ZAX0)PJ;X6.+_R"D,'0(GQ[3A M981)+FX:0HO:(M#S2$TR.6V6IR6L"M#*6V.2?I0<R"6T>D6A41:+HEQ\@/U" MR4C9!:367T:7GLY'U[?5&C99JZE2!( \S^7L9WH>ES8EM^U*<'4_X AQ`NK( MV32Z%1!+8+J'FG\J>3Y.0:^++$U"4FB9$@&V^;(CK**@9%Q5A-" 0=W"BE;S M<O,A&HVN$-TZ^^<_Y70!, T\0;_7&]@S*V#6"WJ6CP#^#37BK!!37*V@'2/2 M0\:+H44^T(/^BZ _P&3T#2V/ODB$C.W1CQ=R[.65F7Z/?< QZDEA.2*D"F-R M5+S&J'R88- -P9X=-V1%></1`4IXAX%S8!]JYN_#1V,#R&B\+E]<&40,Q%'X M$8"^;S(-MW(H1 IK6RP"RK(TPNWJ5H.#4FNV] P4CW&\3D[MY(;6QCGERB^J M!W9J; 89K+[2QR*SLF59"\@!61%3]&S&/32"0@!;9B(7QEW@-"!L`E;>0B>@ M`4,^%N!*9NDB#G%C^6$1@?M![@E>+!7;"FLJ6 1ESL":Q[D`U()'H[^XBR@H M*CU E1TN,Z&TT=)'B\(2LDZU3YI,-(^LM(T^8PXTV\H8'+P[/S\\&>XXT[+: MKD?GTS] /MT(@+XL6050R H:X%J'S.1 06OJWH(4:*HL+ "=9(0_I7$H\D'K M:OV^#:;V>+BR,N&.I;27^]O?F-=!--:TG(0)`)?D'LA]03)QA;DHSAKTFDO; MZ7/C(4A<9[@@7]B_0EHSAB^E3I(AHH$39@6Y^4[17PS/CT[>['@7MS3O*/2P M!^T!UP>?,X4HJ]:6=BJ)1DM*$]@G:8%)A73]N1>ODW?'KP[/5^)%D@,73OKS MPHLBV@;FJ;H\T[GL_A#X\>K=\'"G92;BKIGJ&_WLXF?]!Y&ZYR9%-4XBGM7( M;1SZ4+US`M-#-:_3EAN/M[?7R<-/P!LOP'U5O)*QL4QO1!)$<TB3ZRO?=W < M7&UL5PW^!%\`V/#XCB\+F7XB5@FFU#J0`XHAU<:GJ3O0$^E-:-_<O/*M!'3= M"1:FR7<EK (!BX(;SX&AR/S%%/\'&5;<!0\PS\#.E.RBLLFG"@^I4JT^O-7E M7"AAJ'TT%E 0KT\B!^0P`^6EP1IW?S;2S3#$6#W-<!^.@*,W*US?K"RSYIZB MT\+/]L_WCP^'Y%L\UJLF]V7_*XVXAJ=47-A!WX(`;\02$R[6PYI$KQ-#K';X M'=\KN><FB#9OW%R1-N;=2_ZX__9BQ9H$LMMEHVFJ$TT[^QBE99G.U\]%SD]/ MASM?)PUIH%H`JHO,(++E9LPZ6_8X&BM9KC#9[51FG]/1LU"TTO#_%UR--GH\ ML;/MS\,I4D-P35AVPW"S2.+H1L2$[XQGF4BV&'@L7)2HX^-QN@"<,4I%&*F7 M0/G7]EX>7Q**"5_$Y5?+>?\T9:N4RB3-#73JM;@UU=(&_OS*N8]+M8?KY1+J MB3IL)D6D5&:GMUG;\BM4V\3?>+R];;(E<)24N6I-B\(=]AWF+#6_CPG4=Q54 M"5NR)IS<J!%DCPT>>9=\`@RDX"M9,^,%;&5%HA6PJ@6H&B#^+#4<I8QV>!?% ML37?2$PA4;>+I7B6ZMEQX\QA#H,1+DSO$NTQ[ VSJ5EE>9J)O(Q$L07(Z.,S MO:,OI%E4I[YQ7#S>WIIJ'.!]+NP:BW&5EL!DY;B/4=O5;EMU>L2R!-E@Z:CR MHB"86-R*6&N)W^TC1FB'%\:P-:2MW2;A5<<I#9.3S/Z5QS<[(!./0:Y=5["= MF6S/8+PZ#5?"7/K@/4G7^>G9X?GPMQW_`FRM9-_#A'6S_H;+^^STWRMWUJL( MPU0<SY54.19FDAN>NO/P[+?DQ^^BJX]L3+B\TLTP\H1&_BJ9@4L<H'3Z@RWF MR57;9D9N5I.V*-6:/%#&FZ08SB$V=#E0)_XI0"D=>MRO_K;HPD>#7A<QEHC] M$<?^4%BP#*8#^I[J6"O8HE=6W+Q\<15$R2WL>*6 MBC,R2HJ/%M!1AN/B;&5 M^6GV&>XACQ[*O?N61U7L7Q'KUU40U;\SX>!;0XF\>X#&NK!<4\#K2K>-:/_^ MTR*QYA05<>LY1-B!_G3Z^E_.'4Y3]']\@H=NDAWM7K#;#SZF)WQ$7ZCD"D3[ M_1Z[@^RL\H]!C_TISJR+!4<@.U[*S=B>M]0:*8A^%^ZT?Z&*3.'M?FH?J3*N MJ P@DSW!ZNE@E0QTVQ =H>Y9YYSJH',`Q 2)G*J;BQ)C:L"BKX.'LE'U2Y8\ M1SN6."D=50JVI1;KYH;LWX.==(G*F0CT.#Q?=JAPHAAQ0-OJ/85"(/LY9"D+ M\SV49"R2:3GK(!$WY7V<,:*J!OSW@S4Y_+VYN4HV9(BF-B?_[,+J,KKJY AS M;<ZB%>Q+NAMW-5SD!/Y>9?Q,VO^SVFAUGBTU236N8CV^!4YI$&ZEHX'EB58J ML13V&U&:X"["".QLU:@S!7Y(T"P3NZM&9.A2W&''/('(FP>HI_*7ODO?2MZY MRMH5L!QV9^U;F1;<`]C![A=#-&>7V6X3W<J9:EY#]O"L#'@NO;G(8C[&+70Y MT[MLI-]M<NPF2-)0( W*)ZQ&_[X3X/[S4SQ6V]'J0 ;A&$,Z9FS^4(Y!C9"V M3&^%LNB@IGR FR,K=I0IQ8M.F_VBM+2BD/J^?&2][S&A)]9@M325H'J/DZQV MD;%6U2R!M>79\#2NVNEESAHP7Q>;M0!;_>D=4H^=G!!U1*T@&64=]'WY2B ) M>2>D<DE:'M)X5XCABS-\NY5&'6Q3VE\5L=9+^@].W[X]/!@>G9[\"R3^RGO> MB*63<:U;>$#<:>P:OO_K;_C:F7_,LPZ,X:G,`(*HV >MG])!_(]Y.F_L/ 9K MD=3'*6V^(U/6#&1N5;M)9!N)V)^,]^G8*]B"Q&W*1?4.I%F#2^BO3;X[N\T) MJ6!_`#\HT*SB0IT^Y( *4.L1JNH^5YK$RW[_2#;.#-"(8,)$&]W5(Q")&Z]5 M--(9T%>6+\[IZ'<[V8\AVX-.%VT3;R"_#@OH8*:49Z!B,HG&$;A%>?1))P(< M]L>1K/D7ZS#2X%>QL\J1'DF7VMF*E3MU_0ZOC.:0)D;4I*TC)G9GES,,V2G MX(4^;,%:+8YU7/WZN9(;P2%7P `^6C)9IEID+$V$/)QA:=+6I"(_WD82V3/I M7=H^RWG^O!U%5#WGW.<']N*/#(9LW73RC%N=Q%3"JB[]!AVIU\JZN?<0VN;( M(Z1U*I>+EWCZ2?V)L+W!4]04CS>YJ:^C4O>3U.2=NN@X6$]'#O_[;/_D]4XK M)G;I4,$RJX;ZL".D=EZKG$W2@"61!Z5NS*Z3REG6V\#_\<5,O:(ATF!=RRJ^ MUA[S#SZ=6 E>;W%(HF(F0JFKU64T;QWZP6U(;*U.))?+JNJKQ^F2D WG2MJT M+D4A]BY16W[5D[0E6Y7P1B@Y>=6=H/N8P,3=J=!T^)1'26#][FW#K3IO_M/C MJ O;X_NT8OT.,.SC*^UV:=-Q:3_"%@-O$YCJ(7":'':]D'XA81^1(R:_*V_H M8:6!3IM-QZ;V<W:Q#]BV/JB'_Z$]U+4F--9QJQ6R(=F>#X.PHP:X+M]=H/IL M+JS+MGID=1.,,5N9L19Q8;7ZNY>_U%TOX^V,"-4CP -O9EDO!'F?]"J:\.DF M/-XS'_NQ[XB@WC_G.2@PEXD:UT BQ^K5\@2H!/AWUL/_\2KF#CZP/#F5@BSL M[M>D0M\L*/-6L;U1&BS?KP!<+])QQ+'2JXJ_H _F#F.KY' *=<T66><?I@3H MOMC!W,CMNL)+-74YP!N6]3-*]]1\^-5^78U]Y=<1AAR,M6KK#1!(@GV9M^$F MU*AS<91$Y9J+W=<D4[W5HETX7%<@21YK7;8<QU(@\@!?69Y]CF_!XD02FK[Y M@6L&>L<35) :4%55AC]AWY:G128W156.8=3 483JZ-L<>,OSM'&\I8T9D?-= MZ?2N8\2$[W\Q!^JR*J5ZO<@HQ[%[3;+SE%R=8VD8:D[$%_Z,T,=CL3\TND^+ M6&,-$O77K;@+T.W:J;4*SFC2=@OXE>#)43))V0A=E&%$FB-E^JE#(3.G:J]% M,<ZC#*"![UD(,XPB.K9L/"_<`W'OV6FHSUS9YF;42!_4H;%2XST`OXRN`KJ+ MP/7IL3=9.)@)O)(QH9R,WL/D[\\SDNLZ=*-34/TB*8B3\GTNP" Z_%"_=Q1 MM'0J@XRP5Y3NB>43/"TCA=B(B@T5HWR3D&(#RZM11<5Z%)EAN[S\A;_ITAR] M<TB/:NE2J*1S+:5S#=(Q2U52NNXZX%[1LN><-@T!MK=I5KB\[FP`JU3 &1$8 MNY<`YFA;-I=)IG7WEG57?3[_2(T=39,T;RLC>_<O]ZU]IK^*[W)Y3S!/037$ M,S94%XD2W"_I&PF%@"U\Y.\^-3I>'<G[S*BC>E=_(QL=.%>_40"K@UQ>_4.N M>;]%;QWQ"Z#)#!\G\#X2;KB,\<P]AQ+NON[-X?!W?:!)'E66#B"^X?FLW8I5 M5QP/IOI]:]FB-+RSU4S'(4VSIP&_A4+M&F1050M9S^T(!XJ/-J_<CGXQURH7 MJP96%NQK4:G[635&=I[4=>E9G6,!O5BL^!6RC'X/5*,GVT$,F$SP95.UUL%? MTB@,AK^='7KU#MCR"QW6MO00VBZ^Q67^=9VV1.&OX)$?X%7-+_4^I?_WL;:/ M-2;TEW:LF)9BAMQXIK)GIS1:UX9=K]%9%47;,4S1,7C+Q,X:3CH:BC'/HA(\ MP2>G4EDL1K)6T/]WG]I59U@MJ$3%(V#R;_ZJZ7K!JW+SNJL"MQSJMT$5?W#? M8=;V$%Y-`YH3>UYEXLBI6JJS6&W-Y ETGH)KQP&'=RZ%AO)G$)"_]Q_17=!; M5P..)WSC-%MJ_+?8BRT],WUW)_3;AX*O+7Y5Z?@ZA60[*S!2J7#Q%I ?)T7I M3"_VPQ!5#OV9:LMW] _['TYWV+L"-_U8&<8S2WH'9+%,QN#ZDN@3KQU0XMX8 MJ*3@AM_U_KC?5]O3:JL\"&A2UU580XEYN%G7QT@VG/.B43UBU\'=VE `G;"- M[FV.X\V>0^Q.;[,QNUN+U4Y0IQO;5<.I].)53: R+P`^MHH#7DM-E(V:A2QL MWZ2EQK6WB9";/<2S43FU5G)K/:J8J3(WJYO:7 ?8LIO.:Q6QN;8WL'[G*J]: M=R[?OJ0?T$1SBM+MK^[$7"5)3R?ZL!0W[*J74U8]NTJD\_8$E?!567=+RS8Y M,6OIFG<GS*F)'>=I40-+.B<IEK,DO=5KK) EQ@;)2+?H@4,S_"Q_E6M*RNOU M=_M9FP24( =JHL;[7)3DQ4=\6UO-SY.XP/(*T2$N":3:D[NN))"XS#4(=)*$ MDG7O@47F<L*N*SW]HN1Z8!O &'D%P39IG3#++G;5&Z^]M$?^]EC]!D9BR;%2 M5LR1?$#$G95 DCM40*J@?/LM*T4WF'>FZ.H:@+$1%/"UW2!?<_*NLU/J)C7S M6BFCVZ!N]1]+KEY;ZEN?6T[ U;3V^/:PHRKKONFK2H,UVI=@X!WL*%G4._3O M30KG+M#H0<J\TSH:H-_#^5E+/W!.6ZE:8%JW9.M?=ECO@L-G7&K0_&T[]U_G M'D/;/83KU?<0ZC<-:H\_8W_H&FR+!'Q;(:H66*.]VP/?+K8]]\(IC=(T$-:. M6SFWVK3-8V1C$D;+&I/2(PIT:MI!VQP6J8U)Y+/V:0R9]VY<DS0]:[Z21,4T M>EY-Y1*DPR&V$71$0PE;1</Z3 KU->=2T)[9FJ/LUYI8[W8_2A*15ZGJ`]_M MOBU//-'V;Z,0RWSRY5$\H5>X+H"ZF']:ZO<_TGN3Y3L:\1$>&^EYJD*.G22: MFI75)6"D_H5OJ-?3N.]6K1LTL0S^^5]02P$"%@L4````" !<G+4LG3Y"^*$# M``"/"P``#P`````````!`" `@($`````5F%L=653=&%C:RYJ879A4$L!`A8+ M% ````@`6IRU+-M]?+A%%@``+64``!<``````````0`@`("!S@,``$%B<W1R H86-T5F%L=653=&%C:RYJ879A4$L%!@`````"``(`@@```$@:```````` ` end |
From: Sven K. <sv...@im...> - 2002-05-21 19:35:10
|
Since a diff does not make much sense for this, I'll repost the files completely in plain ascii. Sorry for the inconvenience. Sven.... -- snip "AbstractValueStack.java" /* * WebWork, Web Application Framework * * Distributable under Apache license. * See terms of license at opensource.org */ package webwork.util; import org.apache.log4j.Category; import webwork.expr.ParseException; import webwork.expr.Parser; import java.beans.*; import java.io.StringReader; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; /** * Value stack. A VS is used by the WebWork system as a way to make * values available by using the push and pop methods. They can then * be accessed by using the find* methods. * * @author Rickard Öberg (ri...@mi...) * @author Maurice C. Parker (ma...@vi...) * @version $Revision$ */ public abstract class AbstractValueStack{ // Static ------------------------------------------------------- public static final String STACK_NAME = "webwork.result"; static Map classes = new HashMap(); // Method cache private static Category log = Category.getInstance(ValueStack.class); /** * Clear the method cache. This must be called if the * application is restarted. * */ public static void clearMethods() { classes = new HashMap(); } // Attributes ---------------------------------------------------- private List valueList = Collections.EMPTY_LIST; private Parser parser; // Constructor --------------------------------------------------- public AbstractValueStack() { } // Public -------------------------------------------------------- /** * Push a value onto the value stack. * * @param value the value */ public void pushValue(Object value) { if (valueList == Collections.EMPTY_LIST) { valueList = new ArrayList(); } valueList.add(value); // log.debug("Push to value stack:"); // log.debug(toString()); // new Throwable().printStackTrace(); } /** * Pop a value from the value stack. * * @return the popped value */ public Object popValue() { try { return valueList.remove(valueList.size() - 1); } catch (IndexOutOfBoundsException e) { return null; } finally { // log.debug("Pop from value stack:"); // log.debug(toString()); // new Throwable().printStackTrace(); } } /** * Returns the size of the value stack. * * @return size of value stack */ public int size() { return valueList != null?valueList.size():0; } /** * Returns TRUE is the value stack is empty. * * @return true is value stack is empty */ public boolean isEmpty() { return size() == 0; } /** * Resolve a WebWork expression statement. * * @param expression * @return the boolean result of the expression */ public boolean test(String expression) { Parser p = getParser(expression); boolean answer = false; try { answer = p.test(); } catch (ParseException pe) { throw new IllegalArgumentException("\n\nAn error occurred while parsing the expression: \n \"" + expression + "\"\n" + pe.getMessage()); } return answer; } // SK /** Find a value by id. AbstractValueStack expects subclasses to * have some context concept to evaluate @identified expressions. */ abstract protected Object findInContext(String id); /** Find a request parameter. AbstractValueStack expects subclasses to * have some request concept to evaluate $parameter expressions */ abstract protected String getRequestParameter(String id); // /SK /** * Find a value for a given name. * * @param expression * @return the object corresponding to the query */ public Object findValue(String query) throws IllegalArgumentException { if (query == null || query.equals("")) query = "."; // The query segments and the current segment Query q = Query.getQuery(query); QuerySegment[] segments = q.getSegments(); if (log.isDebugEnabled()) { log.debug("findValue() for: " + q); } QuerySegment segment = segments[0]; int segmentIdx = 1; // The working stack, its pointer, and the current object, List workList = null; int stackIdx = 0; Object value = null; ///////////////////////////////////////////////////////////////////////// // evaluate the first element of the expression to see where to // get the requested value. These should be quick and easy objects // to find or create. ///////////////////////////////////////////////////////////////////////// switch (segment.getType()) { // get the top value off of the stack case QuerySegment.CURRENT: if (valueList.size() < 1) return null; else value = valueList.get(valueList.size() - 1); if (value instanceof ValueHolder) value = ((ValueHolder) value).getValue(); if (value == null && log.isDebugEnabled()) log.debug("value for [" + query + "] is null."); return value; // return the id since it is the actual string case QuerySegment.STRING: return segment.getId(); // the integer is the first value and only value in the segment case QuerySegment.NUMBER: return segment.getValues().get(0); // get an attribute case QuerySegment.ATTRIBUTE: // get the attribute // SK value=findInContext(segment.getId()); // /SK if (value == null && log.isDebugEnabled()) { log.debug("value for [" + query + "] is null."); return null; //throw new IllegalArgumentException("No such attribute: " + token.image); } // get the real value if (value instanceof ValueHolder) value = ((ValueHolder) value).getValue(); // always have the next segment ready to go segment = segments[segmentIdx++]; // if we don't need to search through this attribute simply return it if (segment == null) return value; // Set the stack index to zero so that we don't try to search the stack stackIdx = 0; break; // return the http request parameter case QuerySegment.PARAMETER: // SK return getRequestParameter(segment.getId()); // /SK // the reserved keywork "true" case QuerySegment.TRUE: return Boolean.TRUE; // the reserved keywork "false" case QuerySegment.FALSE: return Boolean.FALSE; // get the root object off of the bottom of the stack case QuerySegment.ROOT: if (valueList.size() < 1) return null; // set up the stack, pointer, and current value workList = valueList; stackIdx = 0; value = workList.get(stackIdx); // always have the next segment ready to go segment = segments[segmentIdx++]; // if we don't need to search through the stack then return the value // this is very unlikely to happen, but we have account for it anyway if (segment == null) return value; break; default: if (valueList.size() < 1) return null; // set up the stack, pointer, and current value workList = valueList; stackIdx = workList.size() - 1; try { value = workList.get(stackIdx); } catch (IndexOutOfBoundsException e) { return null; //throw new IllegalArgumentException("Illegal valuestack query:"+query); } break; } //log.debug( "first segment id: '" + segment.getId() + "' segment type: '" + segment.getType() + "'" ); ///////////////////////////////////////////////////////////////////////// // Now that stack has been set up and the context set (valueIdx) we will // begin parsing the rest of the expression and drilling down through // the object properties, collection elements, and method calls. ///////////////////////////////////////////////////////////////////////// int saveSegmentIdx = segmentIdx; while (true) { //log.debug("beginning valuestack search at level: '" + stackIdx); int workStackIdx = stackIdx; if (value != null) { objectWalk: do { switch (segment.getType()) { // access a classes property case QuerySegment.PROPERTY: // get the real value if (value instanceof ValueHolder) value = ((ValueHolder) value).getValue(); //log.debug( "PROPERTY: attempting to get: " + segment.getId() ); try { Method[] methods = getMethod(value.getClass(), segment.getId()); if (methods == null) { //log.debug( "PROPERTY: method not found: '" + segment.getId() + "' current value: '" + value + "' (" + value.getClass() + ")"); value = null; break objectWalk; } else { value = methods[0].invoke(value, new Object[0]); //log.debug( "PROPERTY: found property value: " + value + " (" + value.getClass() + ")"); } } catch (Exception e) { //log.debug( "PROPERTY: method called failed: " + e.getMessage() ); value = null; break objectWalk; } break; // access a class method case QuerySegment.METHOD: // get the real value if (value instanceof ValueHolder) value = ((ValueHolder) value).getValue(); //log.debug( "going after method: " + segment.getId() ); try { Method[] methods = getMethod(value.getClass(), segment.getId()); if (methods == null) { //log.debug( "METHOD: " + segment.getId() + " was not found." ); value = null; break objectWalk; } Iterator it = segment.getValues().iterator(); List params = new ArrayList(); while (it.hasNext()) { Object param = findValue((String) it.next()); params.add(param); } Method target = findMethod(methods, params); // Convert if necessary int paramCount = target.getParameterTypes().length; for (int i = 0; i < paramCount; i++) { Class parameterClass = target.getParameterTypes()[i]; //log.debug(paramCount + ": " + parameterClass.getName()); if (!parameterClass.equals(String.class) && !parameterClass.equals(params.get(i).getClass())) { // Get property editor PropertyEditor pe; pe = PropertyEditorManager.findEditor(parameterClass); // Convert value if (pe != null) { pe.setAsText(params.get(i).toString()); Object param = pe.getValue(); //replace with the converted value params.set(i, param); } } } //log.debug("METHOD: trying call: " + segment.getId() + " param: " + params); value = target.invoke(value, params.toArray()); } catch (Exception e) { //log.debug("METHOD: \"" + segment.getId() + "\" exception: \"" + e.getMessage() + "\""); value = null; break objectWalk; //throw new IllegalArgumentException("Invalid single method access. " + // "Error accessing method \"" + token.image + // "\" using parameter: \"" + param + "\""); } break; // access the current value as a collection case QuerySegment.COLLECTION: // get the real value if (value instanceof ValueHolder) value = ((ValueHolder) value).getValue(); Object key = findValue(segment.getId()); if (key == null) { value = null; break objectWalk; } // Map if (Map.class.isAssignableFrom(value.getClass())) { value = ((Map) value).get(key.toString()); break; } // Resource Bundle else if (ResourceBundle.class.isAssignableFrom(value.getClass())) { value = ((ResourceBundle) value).getObject(key.toString()); break; } // Array else if (value.getClass().isArray()) { value = ((Object[]) value)[((Integer) key).intValue()]; break; } // List else if (List.class.isAssignableFrom(value.getClass())) { value = ((List) value).get(((Integer) key).intValue()); break; } // Collection else if (Collection.class.isAssignableFrom(value.getClass())) { // Not very efficient, but at least it works value = ((Collection) value).toArray()[((Integer) key).intValue()]; break; } // fail if the user tries to access something other than a Collection value = null; break objectWalk; // access the parent by going up one level on the stack case QuerySegment.PARENT: workStackIdx--; if (workStackIdx < 0) { value = null; break objectWalk; //throw new IllegalArgumentException("Parent object not available."); } else { value = workList.get(workStackIdx); } break; // currently we only allow to expand properties (no parameter methods) case QuerySegment.EXPAND: //log.debug( "EXPAND: going after: " + segment.getId() ); try { Object methodName = findValue(segment.getId()); if (methodName == null) { value = null; break objectWalk; } value = findValue(methodName.toString()); } catch (Exception e) { value = null; break objectWalk; } break; } //log.debug( "finished case statement" ); // always have the next segment ready to go segment = segments[segmentIdx++]; } while (segment != null); } // if we didn't find the value, then move one down the stack and // try again. if (value == null && stackIdx > 0) { stackIdx--; value = workList.get(stackIdx); // reset the segment index to reset the search segmentIdx = saveSegmentIdx; segment = segments[segmentIdx - 1]; } else { break; } } // get the real value if (value instanceof ValueHolder) value = ((ValueHolder) value).getValue(); if (value == null && log.isDebugEnabled()) log.debug("value for [" + query + "] is null."); return value; } /** * Return a string representation of the Stack * * @return the stack as a String */ public String toString() { String str = "Value stack\n"; str += "===========\n"; for (int i = 0; i < valueList.size(); i++) { Object val = valueList.get(i); str += val == null ? "null\n" : val.toString() + "\n"; } str += "===========\n"; return str; } /** * Get the parser associated with this ValueStack * * @return the Parser for this ValueStack */ private Parser getParser(String expression) { if (parser == null) { parser = new Parser(new StringReader(expression)); parser.setValueStack(this); } else { parser.ReInit(new StringReader(expression)); } return parser; } /** * Get a method with a given name. * * @param cl the class of the method * @param name the name of the method * @return the wanted method * @exception IntrospectionException */ private Method[] getMethod(Class cl, String name) throws IntrospectionException { Map methods = (Map) classes.get(cl); if (methods == null) { // Get methods that can be invoked for this class methods = new HashMap(); // Find get methods for properties BeanInfo bi = Introspector.getBeanInfo(cl); PropertyDescriptor[] pd = bi.getPropertyDescriptors(); for (int i = 0; i < pd.length; ++i) { Method method = pd[i].getReadMethod(); // Check if readable property if (method != null) { if (!Modifier.isPublic(cl.getModifiers())) { // Find a method in an interface that *is* public Class[] interfaces = bi.getBeanDescriptor().getBeanClass().getInterfaces(); for (int j = 0; j < interfaces.length; j++) { try { //log.debug("Try "+interfaces[j]); method = interfaces[j].getMethod(method.getName(), new Class[0]); break; } catch (Exception e) { // Ignore } } // We're in trouble! Try to sneak through security if (method.equals(pd[i].getReadMethod())) { AccessibleObject.setAccessible(new AccessibleObject[]{method}, true); } } // Save method in map //log.debug( "GET_METHOD: class: " + cl + " method: " + method.getName()); methods.put(pd[i].getName(), new Method[]{method}); } } // Find param methods Method[] getters = cl.getMethods(); for (int i = 0; i < getters.length; i++) { Method method = getters[i]; if (!method.getName().startsWith("set") && !method.getReturnType().equals(Void.TYPE)) { // Valid method // Check if public if (!Modifier.isPublic(cl.getModifiers())) { // Find a method in an interface that *is* public Class[] interfaces = cl.getInterfaces(); for (int j = 0; j < interfaces.length; j++) { try { method = interfaces[j].getMethod(method.getName(), method.getParameterTypes()); break; } catch (Exception e) { // Ignore } } // We're in trouble! Try to sneak through security if (method.equals(getters[i])) { AccessibleObject.setAccessible(new AccessibleObject[]{method}, true); } } // Get name String methodName = method.getName(); if (methodName.startsWith("get")) methodName = Introspector.decapitalize(methodName.substring(3)); else if (methodName.startsWith("is")) methodName = Introspector.decapitalize(methodName.substring(2)); // Save method in map Method[] current = (Method[]) methods.get(methodName); Method[] newlist = null; if (current == null) { newlist = new Method[]{method}; } else { newlist = new Method[current.length + 1]; System.arraycopy(current, 0, newlist, 0, current.length); newlist[current.length] = method; } methods.put(methodName, newlist); //log.debug( "GET_METHOD: class: " + cl + " method: " + method.getName()); } } // Add map to class map // RO: Use clone to avoid synchronization Map newClassMap = (Map) ((HashMap) classes).clone(); newClassMap.put(cl, methods); classes = newClassMap; //log.debug("Added "+cl+" to class map:"+methods); } // Get named method/property getter Method[] nameMethods = (Method[]) methods.get(name); //log.debug("Got "+cl+" "+name+":"+m); return nameMethods; } public Method findMethod(Method[] m, List params) { if (m.length == 1) return m[0]; List match = new ArrayList(); int noOfArgument = params.size(); for (int i = 0; i < m.length; i++) { if (m[i].getParameterTypes().length == noOfArgument) match.add(m[i]); } //log.debug("No of match for: " + m[0].getName() + " , " + noOfArgument + ", " + match.size()); if (match.size() == 1) return (Method) match.get(0); Method exact = null; List close = new ArrayList(); List convert = new ArrayList(); for (Iterator i = match.iterator(); i.hasNext();) { Method current = (Method) i.next(); Class[] paramClass = current.getParameterTypes(); boolean exactMatch = true; boolean closeMatch = true; boolean convertable = true; for (int j = 0; j < paramClass.length; j++) { Class p = params.get(j).getClass(); //log.debug("Argument: " + j + " , parameterClass: " + paramClass[j].getName() //+ " , argumentClass: " + p.getName()); if (paramClass[j].getName().equals(p.getName())) { continue; } else if (paramClass[j].isAssignableFrom(p)) { exactMatch = false; continue; } else { exactMatch = false; closeMatch = false; try { // Get property editor PropertyEditor pe; pe = PropertyEditorManager.findEditor(paramClass[j]); // Convert value pe.setAsText(params.get(j).toString()); pe.getValue(); } catch (Exception e) { convertable = false; } if (!convertable) break; } } if (exactMatch) { exact = current; break; } else if (closeMatch) { close.add(current); } else if (convertable) { convert.add(current); } } if (exact != null) return exact; else if (close.size() > 0) return (Method) close.get(0); else if (convert.size() > 0) return (Method) convert.get(0); else return null; } // Inner classes ------------------------------------------------- // Value providers that want to use lazy evaluation should use this // interface public interface ValueHolder { // Public ----------------------------------------------------- public Object getValue(); } } -- Snip ValueStack.java /* * WebWork, Web Application Framework * * Distributable under Apache license. * See terms of license at opensource.org */ package webwork.util; import javax.servlet.ServletRequest; import javax.servlet.jsp.PageContext; /** * Value stack implementation for a servlet based scenario. * * @author Rickard Öberg (ri...@mi...) * @author Maurice C. Parker (ma...@vi...) * @version $Revision: 1.31 $ */ public class ValueStack extends AbstractValueStack{ // Constructor --------------------------------------------------- public ValueStack() { super(); } /** * Get the value stack for a given request. If there is no * stack available, create one. * * @param request the request for which a stack shall be returned * @return the value stack */ public static ValueStack getStack(ServletRequest request) { ValueStack stack = (ValueStack) request.getAttribute(STACK_NAME); if (stack == null) { stack = new ValueStack(); request.setAttribute(STACK_NAME, stack); } stack.setRequest(request); return stack; } /** * Get the value stack for a given page context. If there is no * stack available, create one. * * @param context the page context to associate with the stack * @return the value stack */ public static ValueStack getStack(PageContext context) { ServletRequest request = context.getRequest(); ValueStack stack = (ValueStack) request.getAttribute(STACK_NAME); if (stack == null) { stack = new ValueStack(); request.setAttribute(STACK_NAME, stack); } stack.setRequest(request); stack.setContext(context); return stack; } private ServletRequest request; private PageContext context; // Private ------------------------------------------------------- /** * Set the request that should be associated with this stack. * This is called for each use of the stack so that attributes can be accessed * properly. * * @param request */ private void setRequest(ServletRequest request) { this.request = request; } /** * Set the page context that should be associated with this stack. * This is called for each use of the stack in a JSP context. * * @param request */ private void setContext(PageContext context) { this.context = context; } protected Object findInContext(String id){ if (context != null) { return context.findAttribute(id); // Used in a JSP environment } else { return request.getAttribute(id); // Rarely, if ever, used. Ignore } } protected String getRequestParameter(String id){ return request.getParameter(id); } } |
From: Sven K. <sv...@im...> - 2002-05-21 19:40:22
|
I forgot that one more file is affected: Index: Parser.jj =================================================================== RCS file: /cvsroot/webwork/webwork/src/main/webwork/expr/Parser.jj,v retrieving revision 1.16 diff -u -r1.16 Parser.jj --- Parser.jj 26 Apr 2002 19:31:14 -0000 1.16 +++ Parser.jj 21 May 2002 19:37:01 -0000 @@ -51,7 +51,7 @@ import javax.servlet.jsp.PageContext; import org.apache.log4j.Category; -import webwork.util.ValueStack; +import webwork.util.AbstractValueStack; /** * The WebWork Expression language Parser and Interpreter. @@ -62,7 +62,7 @@ { // Attributes ---------------------------------------------------- - private ValueStack valueStack; + private AbstractValueStack valueStack; private int nestDepth = 0; protected static Category log = Category.getInstance(Parser.class); @@ -71,7 +71,7 @@ * * @param request */ - public void setValueStack(ValueStack valueStack) + public void setValueStack(AbstractValueStack valueStack) { this.valueStack = valueStack; } |