Vous êtes sur la page 1sur 405

!

"#$%&'(&$") +),)
2




!"#$%&'(&$"! *!+! ,-.%/!
!"#$%$& (%)*+", !*-%".




!!!"#$%&'()*(&$#+#,#"*-.
3
















2012 Cecilio lvarez Caules. Todos los derechos reservados.

ISBN : 978-1-291-16766-5


!"#$%&'(&$") +),)
4
!"#$%&'()(&*+,-
LsLe llbro esLa dedlcado a la comunldad de desarrolladores !LL de CanLabrla puesLo
que muchos de los caplLulos se basan en reflexlones fundamenLadas en las dlsLlnLas
pregunLas que se me han formulado esLos anos en los cursos y consulLorlas reallzados
para su enLorno. ulchas aporLaclones me han proporclonado un anlmo esenclal para
escrlblr esLe llbro.
Agradezco al grupo de arqulLecLura !LL del goblerno de CanLabrla las dlsLlnLas
colaboraclones en las que hemos Lomado parLe esLos anos, ya que el presenLe llbro
recoge un cumulo de ldeas exLraldas dlrecLamenLe de esLas.
Agradezco, lgualmenLe, al equlpo humano de ConsulLec los dlsLlnLos proyecLos en los
que he parLlclpado esLos ulLlmos anos : me han hecho crecer como arqulLecLo y me han
ayudado a obLener una vlsln ms neuLral a nlvel Lecnolglco sobre las dlsLlnLas
plaLaformas y frameworks exlsLenLes.
Ml agradeclmlenLo va Lamblen para las aporLaclones de las personas con las que
Lraba[e mls prlmeros anos de profeslonal en Mundlvla. LsLa eLapa me ayud a adqulrlr
la vlsln necesarla sobre la orlenLacln de ml fuLuro perfll profeslonal, algo que con el
paso del Llempo ha sldo clave en la evolucln de ml carrera.
Craclas, asl mlsmo, a !esus MarLln lernndez y a Mlguel 8lanchard 8odrlguez por las
dlsLlnLas charlas e lnLercamblos de ldeas que hemos Lenldo esLos anos sobre !LL ,
adems de los enfoques y dlsLlnLas vlslones que me han venldo aporLado.
Agradecer a !ose Manuel San LmeLerlo erez de LmcanLa los dlsLlnLos procesos de
cerLlflcacln en los que parLlclpamos ambos ,que me permlLleron deflnlr el punLo de
parLlda de los conLenldos del llbro.
Ls Lamblen necesarlo agradecer a !ordl lvarez Caules y a Ana aLrlcla lernndez del
Llano la revlsln del documenLo y las ldeas ob[eLlvas y slnceras que me LransmlLleron
sobre cmo me[orar el conLenldo.
Agraceder a Clga elaez 1apla la revlsln compleLa del documenLo a nlvel de clarldad
de conLenldos .?a que sln ella Lengo claro que muchas ldeas no habrlan quedado claras.
or ulLlmo, agradezco a mls padres la educacln en la culLura del conoclmlenLo que me
han proporclonado, ya que sln ella no me hublera converLldo en arqulLecLo.

!!!"#$%&'()*(&$#+#,#"*-.
5


"#$%&'()'%#" *"+" ,-.&/" 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1
)234546 7589:2; )9<52= 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1
">:9?234@42AB6= 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 C
&AB:6?<334DA 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EC
E0 )6A634@42AB6= F:2846= 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EC
10 #2G<2:4@42AB6= ?2 =6HBI9:2 0000000000000000000000000000000000000000000000000000000000000000000000000000000 EJ
K0 &A=B95934DA ?25 2AB6:A6 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EJ
C0 )6AH4><:934DA ?25 2AB6:A6 00000000000000000000000000000000000000000000000000000000000000000000000000000000000 EL
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1M
E0N'O. 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 11
E0 )6A=B:<4: <A H6:@<59:46 N'O. 00000000000000000000000000000000000000000000000000000000000000000000000000 1K
10 +954?9346A2= ?2 *989,3:4FB 00000000000000000000000000000000000000000000000000000000000000000000000000000000000 1C
K0 "P9?4: H6:@9B6 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1J
C0 %=6 36::23B6 ?2 2B4G<2B9= 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1L
J0 "332=4Q454?9? ?2 59 F9>4A9 000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1R
L0 %=6 ?2 SN'O. 36@6 2=BTA?9:0 000000000000000000000000000000000000000000000000000000000000000000000000000 1R
R0 %=6 ?2 2=BTA?9:2= /UO 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1V
V0 %=6 ?2 *989,3:4FB /2>:9?9Q52 00000000000000000000000000000000000000000000000000000000000000000000000000000 KM
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 K1
10*989 ,2:82: W9>2= 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KC
!"#$%&'(&$") +),)
6
E0 ):2934DA ?2 <A9 B9Q59 .4Q:6= 0000000000000000000000000000000000000000000000000000000000000000000000000000000 KC
10 &A=B959: 25 ?:482: */X)0 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KJ
K0 ):2934DA ?2 59 FT>4A9 Y&A=2:B9:.4Q:60Z=F[ 000000000000000000000000000000000000000000000000000000 KL
C0 ):2934DA ?2 59 F9>4A9 O6=B:9:.4Q:6=0Z=F 000000000000000000000000000000000000000000000000000000000 KV
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 C1
K0/#\ ] *,W 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 CC
E0 "P9?4: A<289 359=2 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 CJ
10 O6?4H439: F9>4A9= *,W 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 CV
K0 "P9?4: ^45B:6 F6: 39B2>6:_9 0000000000000000000000000000000000000000000000000000000000000000000000000000000000 JM
C0 (5 F:4A34F46 /#\ ] 59= 36A=<5B9= ,$. 00000000000000000000000000000000000000000000000000000000000000000 J1
J0 (5 F:4A34F46 /#\ @`B6?6= ] F9:9@2B:6= 000000000000000000000000000000000000000000000000000000000 JJ
L0 #2=<5B,2B= 8= .4=B9= ?2 6QZ2B6= 0000000000000000000000000000000000000000000000000000000000000000000000000000 JR
R0 %=6 ?2 4AB2:H932= 9 A4825 ?2 .4Q:6 0000000000000000000000000000000000000000000000000000000000000000000000 Ja
V0 )42::2 ?2 36A2b46A2= ] :2H523B46A0 0000000000000000000000000000000000000000000000000000000000000000000000 LE
C0(?4B9:c X6::9: ] ^45B:9: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 LL
E0 "P9?4: 2A5932 ?2 Q6::9: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 LR
10 "P9?4: @`B6?6 Q6::9: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 LR
K0 "P9?4: FT>4A9 X6::9:.4Q:60Z=F 0000000000000000000000000000000000000000000000000000000000000000000000000000 LV
C0 "P9?4: 54Ad (?434DA 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 La
J0 O`B6?6 ?2 Qe=G<2?9 F6: 35982 000000000000000000000000000000000000000000000000000000000000000000000000000 RM
L0 "P9?4: H6:@<59:46 ?2 2?434DA ?2 3D?4>60 000000000000000000000000000000000000000000000000000000000 RM
R0 "P9?4: @`B6?6 =9589: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 RK
!!!"#$%&'()*(&$#+#,#"*-.
7
V0 "P9?4: F9>4A9 ,9589:.4Q:60Z=F 0000000000000000000000000000000000000000000000000000000000000000000000000000 RK
a0 "P9?4: @`B6?6 Q<=39:W6:)9B2>6:490 0000000000000000000000000000000000000000000000000000000000000000 RJ
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 VM
J0O9A2Z6 ?2 2b32F346A2= 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 V1
E0 ^5<Z6 ?2 2b32F346A2= ] 359<=<59= 39B3f 00000000000000000000000000000000000000000000000000000000000 VK
10 O9A2Z6 ?2 59= 359e=<59= Bf:6Ic Bf:6I= ] H5<Z6 ?2 2b32F346A2=0 000000000000000 VC
K0 ):2934DA ] 36A82:=4DA ?2 2b32F346A2= 000000000000000000000000000000000000000000000000000000000000 VL
C0 (b32F346A2= 9A4?9?9= 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 aM
J0 (b32F346A2= #<A'4@2 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 a1
L0 ):29: W9>4A9 ?2 (::6: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 aC
R0 O6?4H439: H43f2:6 I2Q0b@5 00000000000000000000000000000000000000000000000000000000000000000000000000000000000 aL
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 aR
L0.6>C* 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 aV
E0 &A=B95934DA ?2 56>CZ 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 aa
10 &AB:6?<334DA 9 56>CZ 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EMM
K0 )6A=B:<334DA ?2 <A 2Z2@F56 =2A34556 00000000000000000000000000000000000000000000000000000000000000 EME
C0 O2A=9Z2= ?2 2::6: ] A48252=0 000000000000000000000000000000000000000000000000000000000000000000000000000000 EMC
J0 O9A2Z6 ?2 .6>CZ0F:6F2:B42= 0000000000000000000000000000000000000000000000000000000000000000000000000000000 EMR
L0 %=6 ?2 56>CZ 2A A<2=B:9 9F543934DA0 00000000000000000000000000000000000000000000000000000000000000000 EMa
#2=<@2A 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EEE
R0(5 F:4A34F46 ,#W ] 25 @6?256 O+) 000000000000000000000000000000000000000000000000000000000000000000000000 EE1
E0 #2=F6A=9Q454?9?2= ?2 59 9F543934DA ] 25 F:4A34F46 ,#W 0000000000000000000000000000 EEK
!"#$%&'(&$") +),)
8
10 )6A=B:<4: <A =2:852B 36AB:659?6: 00000000000000000000000000000000000000000000000000000000000000000000 EEL
K0 O9F26 ?2 ,2:852B 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EER
C0 &A=2:34DA 36A @6?256 O+) 00000000000000000000000000000000000000000000000000000000000000000000000000000000 E1E
J0 X6::9: 2A @6?256 O+) 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 E1K
L0 (?4B9: 2A @6?256 O+) 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 E1J
R0 ^45B:9?6 2A O6?256 O+) 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000 E1R
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EKE
V0*,'. 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EK1
E0 &A=B95934DA ?2 *,'. 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EKK
10 &AB:6?<334DA 9 *,'. 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EKK
K0 (B4G<2B9= XT=439= *,'. 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EKC
C0 O6?4H439: O6=B:9:.4Q:60Z=F 0000000000000000000000000000000000000000000000000000000000000000000000000000000 EKJ
J0 O6?4H439: ^6:@<59:46 &A=2:B9: 0000000000000000000000000000000000000000000000000000000000000000000000000 EKL
L0 O6?4H439: ^6:@<59:46(?4B9:.4Q:60Z=F 000000000000000000000000000000000000000000000000000000000000 EKR
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EKR
a0(5 F:4A34F46 U)W ] @6?256 O+) 1 0000000000000000000000000000000000000000000000000000000000000000000000000 EKV
E0 (5 F:4A34F46 U)W ] 25 )6AB:659?6: 00000000000000000000000000000000000000000000000000000000000000000000 EKa
10 (5 F:4A34F46 U)W ] 25 F9B:DA )6@@9A? 000000000000000000000000000000000000000000000000000000000 ECM
K0 ):2934DA ?2 <A9 9334DA F:4A34F95 00000000000000000000000000000000000000000000000000000000000000000000 EC1
C0 ):29: Z2:9:G<_9 ?2 93346A2= 000000000000000000000000000000000000000000000000000000000000000000000000000000 ECK
J0 "F4 ?2 :2H523B46A ] 25 F:4A34F46 U)W 0000000000000000000000000000000000000000000000000000000000000000 ECR
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EJM
!!!"#$%&'()*(&$#+#,#"*-.
9
EM0N4Q2:A9B2 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EJ1
E0 &AB:6?<346A 95 36A32FB6 ?2 H:9@2I6:d ?2 F2:=4=B2A349 00000000000000000000000000 EJK
10 &A=B95934DA ?2 N4Q2:A9B2 000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EJC
K0 &AB:6?<334DA 9 N4Q2:A9B2 00000000000000000000000000000000000000000000000000000000000000000000000000000000000 EJJ
C0 )6AH4><:934DA N4Q2:A9B2 000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EJV
J0 &A=2:B9: .4Q:6 36A N4Q2:A9B2 0000000000000000000000000000000000000000000000000000000000000000000000000000 ELE
L0 ,2523346A9: UQZ2B6= 36A N4Q2:A9B2 00000000000000000000000000000000000000000000000000000000000000000 ELC
R0 ,2523346A9: <A eA436 UQZ2B6 000000000000000000000000000000000000000000000000000000000000000000000000000000 ELJ
V0 X6::9: <A 6QZ2B6 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ELL
a0 ^45B:9: 6QZ2B6= 36A N4Q2:A9B2 000000000000000000000000000000000000000000000000000000000000000000000000000 ELR
EM0 O4>:9: A<2=B:9 9F543934DA 9 N4Q2:A9B2 0000000000000000000000000000000000000000000000000000000 ELV
EE0 N4Q2:A9B2 ] )6A82A34DA =6Q:2 )6AH4><:934DA0 00000000000000000000000000000000000000000 ER1
E10 /#\ 2 N4Q2:A9B2 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ERC
EE0N4Q2:A9B2 ] #259346A2= 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EVM
E0 )6A=B:<4: 59 359=2 39B2>6:_9 ] @9F29:59 00000000000000000000000000000000000000000000000000000000 EV1
10 O6?4H439: 59 )9F9 ?2 F:2=2AB934DA ] =6F6:B9: 59 359=2 )9B2>6:_9 00000000 EVC
K0 ):2934DA ?2 :259346A2= 2AB:2 359=2= 0000000000000000000000000000000000000000000000000000000000000000 EVL
C0 #259346A2= ] F2:=4=B2A349 36A N4Q2:A9B2 000000000000000000000000000000000000000000000000000000 EVV
J0 #259346A2= ] 39F9 ?2 F:2=2AB934DA 00000000000000000000000000000000000000000000000000000000000000000 EaC
#2=<@2A 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EaR
E10*989 W2:=4=B2A32 "W& 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EaV
E0 &AB:6?<334DA 95 "W& ?2 *W" 000000000000000000000000000000000000000000000000000000000000000000000000000000000 1MM
!"#$%&'(&$") +),)
10
10 O4>:934DA ?2 "F543934DA 9 *W" 00000000000000000000000000000000000000000000000000000000000000000000000000 1MC
K0 O9A2Z6 ?2 (b32F346A2= 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1MR
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1MV
EK0(5 F:4A34F46 &,W ] 25 F9B:DA /"U 000000000000000000000000000000000000000000000000000000000000000000000000 1EM
UQZ2B486= " 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1EK
E0 ):29: 59= 359=2= .4Q:6/"U ] )9B2>6:49/"U0 0000000000000000000000000000000000000000000000000 1EK
10 %=6 ?2 4AB2:H932= 2A 36@F6A2AB2= /"U 0000000000000000000000000000000000000000000000000000000 1EV
K0 (5 F:4A34F46 /#\ ] 25 F9B:DA g2A2:43/"U 0000000000000000000000000000000000000000000000000000 11E
C0 #2A?4@42AB6 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 11V
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 11V
EC0(5 F:4A34F46 ?2 4A82:=4DA ?2 36AB:65 ] F9B:DA H93B6:] 00000000000000000000000000000000 1KM
E0 ):29: ^93B6:_9= 2 4@F52@2AB9: 25 F:4A34F46 ?2 &U)c 0000000000000000000000000000000000 1K1
10 (5 F:4A34F46 /#\ ] 25 F9B:DA "Q=B:93B ^93B6:] 00000000000000000000000000000000000000000000 1KR
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1CK
EJ0(5 W:4A34F46 /#\ ] 25 F9B:DA =2:84346 000000000000000000000000000000000000000000000000000000000000000 1CC
E0 (5 F:4A34F46 /#\ ] 25 9332=6 9 59 39F9 ?2 F2:=4=B2A349 00000000000000000000000000000 1CJ
10 ):2934DA ?2 <A9 359=2 ?2 ,2:84346 0000000000000000000000000000000000000000000000000000000000000000000 1CR
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1JE
EL0(5 F:4A34F46 &U)] 25 H:9@2I6:d ,F:4A> 000000000000000000000000000000000000000000000000000000000000 1J1
E0 ):2934DA ?2 2Z2@F56 ?2 H93B6:49= 00000000000000000000000000000000000000000000000000000000000000000000 1JJ
10 &A=B95934DA ?2 ,F:4A> 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1LE
K0 &A=B95934DA ?2 ,F:4A> 2A A<2=B:9 9F543934DA0 0000000000000000000000000000000000000000000000 1LL
!!!"#$%&'()*(&$#+#,#"*-.
11
#2=<@2A 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1La
ER0&A]23346A ?2 /2F2A?2A349 ] ,F:4A> H:9@2I6:d 000000000000000000000000000000000000000000 1RM
E0 &AB:6?<334DA 95 F:4A34F46 ?2 &A]2334DA ?2 /2F2A?2A349 000000000000000000000000 1RJ
10 ,F:4A> 2 4A]2334DA ?2 ?2F2A?2A3490 0000000000000000000000000000000000000000000000000000000000000000 1VM
K0 ,F:4A> ] H93B6:_9 F9:9 9F5439346A2= I2Q 0000000000000000000000000000000000000000000000000000000 1VK
C0 ,F:4A> 4A]2334DA ?2 ?2F2A?2A349 ] )9F9= /"U 000000000000000000000000000000000000000000 1VK
#2=<@2A 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1VR
EV0(5 F:4A34F46 /#\ ] ,F:4A> '2@F59B2= 0000000000000000000000000000000000000000000000000000000000000000 1VV
E0 (5 F9B:DA '2@F59B2 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1aM
10 ,F:4A> ] F59AB4559=0 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1aR
K0 ,F:4A> N2:2A349 W59AB4559= ] */"/"U,<FF6:B 000000000000000000000000000000000000000000000 KM1
#2=<@2A 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KMC
Ea0W:6>:9@934DA U:42AB9?9 9 "=F23B6 h"UWi 00000000000000000000000000000000000000000000000000000 KML
E0 &AB:6?<334DA 9 "UW 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KMV
10 %=9A?6 W:6b42= 36A ,F:4A> 00000000000000000000000000000000000000000000000000000000000000000000000000000000 KEC
K0 )6AH4><:934DA ?2 F:6b42= ] B:9A=93346A2=0 000000000000000000000000000000000000000000000000000 KEa
#2=<@2A 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 K1L
1M0%=6 ?2 9A6B9346A2= ] )U) 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000 K1V
E0 jW2:=4=B2A32)6AB2bB ] (AB4B]O9A9>2: 000000000000000000000000000000000000000000000000000000000 K1a
10 j#2F6=4B6:] ] @9A2Z6 ?2 2b32F346A2= 000000000000000000000000000000000000000000000000000000000 KK1
K0 "A6B934DA j,2:8432 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KKK
C0 "A6B9346A2= j"<B6k4:2? 0000000000000000000000000000000000000000000000000000000000000000000000000000000000 KKC
!"#$%&'(&$") +),)
12
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KKR
1E0*989 ,2:82: H932= 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KKV
E0 &AB:6?<334DA 9 *,^ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KKa
10 &A=B95934DA ?2 *,^ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KCM
K0 N659 O<A?6 36A *,^ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KC1
C0 )6A=B:<4: <A 36@Q6 36A *,^ 000000000000000000000000000000000000000000000000000000000000000000000000000000 KCL
J0 ):29: '9Q59 36A *,^ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KJM
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KJ1
1E0O4>:934DA 9 *989 ,2:82: ^932= 0000000000000000000000000000000000000000000000000000000000000000000000000000 KJC
E0 "P9?4: 36AB:659?6: ?2 *,^ ] 254@4A9: 25 2b4=B2AB2 000000000000000000000000000000000000 KJJ
10 ):2934DA O9A9>2?X29A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KJV
K0 ):29: O6=B:9:.4Q:60bfB@5 000000000000000000000000000000000000000000000000000000000000000000000000000000000 KL1
C0 X6::9: .4Q:6 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KLJ
J0 &A=2:34DA .4Q:6 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KLL
L0 ^<A346A954?9? ?2 (?434DA 00000000000000000000000000000000000000000000000000000000000000000000000000000000000 KLV
R0 ^45B:9: F6: 39B2>6:49= 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KRE
V0 O2Z6:9= (bF:2==46A .9A><9>2 10M 0000000000000000000000000000000000000000000000000000000000000000000 KR1
a0 &AB2>:934DA ?2 ,F:4A> 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KRC
EM0 *,^ 1 ] X<=4A2== UQZ23B= 00000000000000000000000000000000000000000000000000000000000000000000000000000000000 KRJ
#2=<@2A 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KRJ
1K0,2:84346= k2Q ] *"Slk, 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KRL
E0 &AB:6?<334DA 9 F:6>:9@934DA ?4=B:4Q<4?9 00000000000000000000000000000000000000000000000000 KRL
!!!"#$%&'()*(&$#+#,#"*-.
13
10 &AB:6?<334DA 9 ,2:84346= k2Q 000000000000000000000000000000000000000000000000000000000000000000000000000 KVM
K0 ,2:84346 k2Q 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KV1
C0 W<Q543934DA ?25 =2:84346 I2Q0 0000000000000000000000000000000000000000000000000000000000000000000000000000 KVR
J0 &A=B95934DA ?2 "F93f2 )S^ 000000000000000000000000000000000000000000000000000000000000000000000000000000000 KVR
L0 )6AH4><:934DA ?25 H:9@2I6:d 000000000000000000000000000000000000000000000000000000000000000000000000000 KVV
#2=<@2A 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 KaE
1C0"?@4A4=B:934DA ] F665= 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 Ka1
E0 (5 H:9@2I6:d ,F:4A> ] W665= 00000000000000000000000000000000000000000000000000000000000000000000000000000 KaK
10 W665 ?2 36A2b46A2= ] '6@39B 0000000000000000000000000000000000000000000000000000000000000000000000000000 KaC
K0 )6AH4><:934DA ?2 ,F:4A> 8_9 *m/&0 00000000000000000000000000000000000000000000000000000000000000000000 KaL
#2=<@2A 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 Kaa
1J0)6A35<=46A2= 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 CMM
n$<2 2= 56 @9= 4@F6:B9AB2o 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 CMM
E0 *(( <A 236=4=B2@9 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 CM1
#2=<@2A 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 CMK
X4Q546>:9H_9 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 CMC




!"#$%&'(&$") +),)
14
!"#$%&'(()*"




La ldea orlglnal de escrlblr esLe llbro vlene de las dlsLlnLas formaclones y consulLorlas
sobre !LL que he reallzado en los ulLlmos anos. Ln la plaLaforma !LL exlsLen muchos
llbros que LraLan sobre L!8s, !A, Sprlng eLc. ero casl slempre esLos llbros se cenLran
en un unlco producLo. Asl pues, para muchas personas resulLa realmenLe dlflcll adqulrlr
una vlsln global de cmo esLos producLos se lnLegran unos con oLros y conforman una
solucln empresarlal. Ll ob[eLlvo de esLe llbro no LraLa de hacernos experLos en
PlbernaLe o en Sprlng slno de ser capaces de comenzar a mane[ar cada uno de esLos
frameworks y adqulrlr una vlsln global como arqulLecLos de cmo consLrulr una
apllcacln empresarlal .ara ello vamos a consLrulr desde cero una apllcacln !LL
pequena que lr evoluclonando segun vayamos avanzando caplLulos y se apoyar en
los dlsLlnLos frameworks o esLndares exlsLenLes a la hora de abordar las dlsLlnLas
problemLlcas.

1. Conoc|m|entos prev|os
ara poder abordar los concepLos que se expllcan en esLe llbro no ser necesarlo Lener
unos conoclmlenLos ampllos de la plaLaforma !ava y de !LL .Ahora blen, sl es
recomendable conocer un mlnlmo del lengua[e !ava, asl como unos mlnlmos de !LL
,concreLamenLe los concepLos de ServleL y !S. or ulLlmo, sern necesarlos
conoclmlenLos sobre el lengua[e P1ML.
!!!"#$%&'()*(&$#+#,#"*-.
15
2. kequer|m|entos de software
una vez que Lenemos claros los conoclmlenLos necesarlos para abordar con garanLlas
los dlsLlnLos caplLulos, vamos a llsLar el sofLware que uLlllzaremos a la hora de crear
nuesLra apllcacln.
Cpen !uk 1.6 o !uk 1.6
llrelox
Web ueveloper
Lcllpse !LL
1omcaL 7
MySCL
ubunLu 10.10 o Wlndows 7

3. Insta|ac|n de| entorno
AnLes de comenzar a desarrollar nuesLra apllcacln debemos abordar una serle de
pasos prevlos relaLlvos a la lnsLalacln.
Insta|ac|n IDk 1.6: Ln esLe caso slmplemenLe nos ba[amos el [dk 1.6 para Wlndows o
blen lo lnsLalamos desde el gesLor de paqueLes synapLlc en caso de usar ubunLu (open
[dk).
I|refox y WebDeve|oper : no hay mucho que declr en esLa seccln slmplemenLe
obLendremos el navegador, lo lnsLalamos y anadlmos el plugln de web developer
correspondlenLe.
Lc||pse ILL : CbLendremos el enLorno de desarrollo ecllpse y lo descomprlmlmos en un
dlrecLorlo cualqulera ya que, al esLar desarrollado en [ava y Lener lnsLalado el [dk
,slmplemenLe con pulsar sobre su lcono el enLorno se lanzara sln mayores necesldades
de lnsLalacln.
1omcat 7: CbLendremos el servldor web 1omcaL de la paglna de apache y lo
descomprlmlmos en un dlrecLorlo paralelo al que Lenemos ublcado ecllpse !LL
MySL: 8a[amos el lnsLalador e lnsLalamos el servldor de MySCL con las opclones por
defecLo .Anadlmos las Cul 1ools o el MySCL Workbench para una gesLln ms sencllla
del servldor .Ln ubunLu podemos lnsLalar MySCL y sus herramlenLas grflcas a Lraves
de SynacLlc.
!"#$%&'(&$") +),)
16
4. Conf|gurac|n de| entorno
Pemos lnsLalado ya Lodo el sofLware que neceslLamos y acabamos de abrlr el ecllpse
(ver lmagen)

Ls momenLo de lnLegrar Lcllpse !LL con 1omcaL 7. LsLo puede reallzarse de una forma
muy sencllla en la pesLana de servers, pulsando boLn derecho New>Server (ver
lmagen)

Al pulsar esLa opcln pasaremos a eleglr el Llpo de servldor que deseamos anadlr a
nuesLro enLorno de desarrollo (1omcaL 7) (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
17

Llegldo el Llpo de servldor, nos sollclLar que especlflquemos en que dlrecLorlo se
encuenLra lnsLalado (ver lmagen).
!"#$%&'(&$") +),)
18

Selecclonamos el dlrecLorlo y podemos pulsar llnlsh" . Ln la pesLana de servldores nos
aparecer el nuevo servldor para que podamos uLlllzarlo.


Conflgurado el servldor , vamos a proceder a consLrulr nuesLra prlmera apllcacln web
y desplegarla en dlcho servldor. ara ello usaremos el menu de I||e>New>Dynam|c
Web ro[ect y crearemos un nuevo proyecLo web (ver lmagen) .
!!!"#$%&'()*(&$#+#,#"*-.
19

una vez que hayamos elegldo el Llpo de proyecLo, ecllpse nos sollclLar que lo alo[emos
en alguno de los servldores que Lenemos deflnldos. Ln nuesLro caso 1omcaL 7 (ver
lmagen)


1ras reallzar esLas operaclones, dlspondremos en ecllpse de un nuevo proyecLo web
sobre !LL con el que podremos comenzar a consLrulr nuesLra apllcacln como se
muesLra seguldamenLe.
!"#$%&'(&$") +),)
20



!"#$%"&
LsLe caplLulo ha servldo para lnLroduclr los ob[eLlvos del llbro asl como para conflgurar
el enLorno de desarrollo que vamos a uLlllzar en caplLulos posLerlores. Ln el prxlmo
caplLulo comenzaremos con el desarrollo de la apllcacln.

!!!"#$%&'()*(&$#+#,#"*-.
21

!"#$%&'(&$") +),)
22
!!!"#$




Ln esLe caplLulo vamos a comenzar a consLrulr una pequena apllcacln web sobre !LL
que nos ayudar a gesLlonar una coleccln de llbros. La apllcacln se encargar de
anadlr, borrar y modlflcar los dlsLlnLos llbros que Lenemos e lr evoluclonando duranLe
el Lranscurso de los dlsLlnLos caplLulos segun se vayan abordando las dlsLlnLas
Lecnologlas de la plaLaforma !LL.
Comenzaremos enLonces por la parLe ms sencllla: la consLruccln de un formularlo
P1ML a Lraves del cul lnserLaremos la lnformacln del llbro que deseamos guardar en
la apllcacln.
Cb[et|vo:
Crear un formularlo P1ML que nos permlLa dar de alLa nuevos llbros en la
apllcacln.
1areas:
1. ConsLrulr un formularlo P1ML que conLenga los campos necesarlos para dar de
alLa un nuevo llbro (lS8n, LlLulo, caLegorla).
2. ConsLruccln de las valldaclones de !avaScrlpL que el formularlo neceslLa para
poder gesLlonar la lnformacln.
3. Apllcar formaLo al formularlo uLlllzando una ho[a de esLllo CSS.
4. 8evlsln del uso correcLo de eLlqueLas P1ML en el formularlo.
3. uso de eLlqueLas de acceslbllldad en el formularlo.
6. uso de xP1ML como esLndar en el formularlo.
7. uso de uCM como esLndar a nlvel de !avaScrlpL.
8. uso de !avaScrlpL degradable en el formularlo.

!!!"#$%&'()*(&$#+#,#"*-.
23
Acabamos de deflnlr el con[unLo de Lareas a reallzar .Culz en esLe momenLo no
Lengamos claras Lodas ellas pero se lrn clarlflcando segun las vayamos abordando.
1. Constru|r un formu|ar|o n1ML
La prlmera Larea que debemos llevar a cabo es sencllla y se LraLa de consLrulr un
formularlo P1ML para dar de alLa nuevos llbros .ara ello vamos a deflnlr el con[unLo
lnlclal de campos que va a conLener .
Campos:
lS8n
1lLulo
CaLegorla
una vez deflnldos los campos, es momenLo de consLrulr el formularlo uLlllzando
eLlqueLas P1ML (ver lmagen)
Cdlgo 1.1: (lormularloLlbro01lnlclo.hLml)
<html>
<head>
<title>Formulario Libro</title>
</head>
<body>
<h1>Formulario alta Libro</h1>
<form>
ISBN:
<input type="text" name="isbn"><br>
Titulo:
<input type="text" name="titulo"><br>
Categoria:
<input type="text" name="categoria"><br>
<input type="button" value="Insertar" >
</form>
</body>
</html>

nuesLra prlmera versln del formularlo es realmenLe sencllla, como se muesLra (ver
lmagen).
!"#$%&'(&$") +),)
24


Ll formularlo se encuenLra ublcado denLro de un proyecLo web de ecllpse (ver lmagen)

2. Va||dac|ones de IavaScr|pt
Ll ob[eLlvo de esLe llbro es ayudarnos a Lomar buenas declslones orlenLadas a la
arqulLecLura, las valldaclones que vamos a usar en el formularlo sern senclllas y en
esLe caso unlcamenLe nos encargaremos de valldar sl el lS8n esLa vaclo. vamos a ver a
conLlnuacln el cdlgo de !avaScrlpL que se encarga de esLa funclonalldad denLro de la
pglna.


!!!"#$%&'()*(&$#+#,#"*-.
25
Cdlgo 1.2: (lormularloLlbro02!avaScrlpL.hLml)
<html>
<head>
<script type="text/javascript">
function validacion() {
if (document.forms[0].isbn.value == "")
alert("datos no validos");
else
document.forms[0].submit();
}
</script>
<title>Formulario Libro</title>
</head>
<body>
<h1>Formulario alta Libro</h1>
<form>
ISBN:
<input type="text" name="isbn"><br>
Titulo:
<input type="text" name="titulo"><br>
Categoria:
<input type="text" name="categoria"><br>
<input type="button" value="Insertar" onclick="validacion()">
</form>
</body>
</html>

Pemos anadldo una funcln de valldacln y un evenLo oncllck" al formularlo, el cul a
parLlr de esLe momenLo obllga a que lnLroduzcamos el lS8n .
3. Aad|r formato
ara anadlr formaLo a nuesLro formularlo usaremos una ho[a de esLllo mlnlma que
slmplemenLe presenLar el LexLo del formularlo en negrlLa (ver lmagen)
Cdlgo1.3 :(lormularloLlbro03CSS.hLml)
<style type="text/css">
font-weigth:bold;
</style>

!"#$%&'(&$") +),)
26
4. Uso correcto de et|quetas
Ls frecuenLe enconLrarmos con slLuaclones en las que, aunque se usa una Lecnologla,
esLa no se conoce en profundldad .LsLe es el caso de la pglna que acabamos de crear,
ya que usamos una eLlqueLa <h1> de cabecera para aslgnar un LlLulo al formularlo y
eLlqueLas <br> para separar el conLenldo, algo que no es correcLo, ya que exlsLen
eLlqueLas ms especlflcas que pueden reallzar esLas Lareas. 1ales eLlqueLas son, en
concreLo:
<f|e|d><]f|e|d>y <|egend><]|egend> :LLlqueLas encargadas de agrupar un con[unLo de
campos de un formularlo y aslgnar a esLe un LlLulo o leyenda.
<p><]p>:LLlqueLa que se encarga de deflnlr un prrafo
Asl pues, es preclso modlflcar las eLlqueLas de nuesLro formularlo de la slgulenLe forma.
Cdlgo1.4: (lormularloLlbro04usoLLlqueLas.hLml)
<form action="insertarLibro.jsp">
<fieldset>
<legend>Formulario alta libro</legend>
<p>ISBN:
<input type="text" name="isbn">
</p>
<p>
Titulo:
<input type="text" name="titulo">
</p>
<p>
Categora:
<input type="text" name="categoria">
</p>
<p>
<input type="button" value="Insertar" onclick="validacion()">
</p>
</fieldset>
</form>

Como podemos observar, no solo hemos anadldo las nuevas eLlqueLas slno que
Lamblen hemos ellmlnado las que no eran correcLas "<h1>".
!!!"#$%&'()*(&$#+#,#"*-.
27
S. Acces|b|||dad de |a pag|na
Ln esLos momenLos nuesLra paglna P1ML carece de las eLlqueLas hablLuales de
acceslbllldad, como por e[emplo la eLlqueLa <|abe|>, las cules deflnldas en el
formularlo permlLen una me[or acceslbllldad a usuarlos dlscapaclLados. ara solvenLar
esLe problema vamos a anadlrlas a nuesLro cdlgo (ver cdlgo).
Cdlgo 1.3: (lormularloLlbro03Acceslbllldad.hLml)
<fieldset>
<legend>Formulario alta libro</legend>
<p><label for="isbn">ISBN:</label>
<input type="text" name="isbn"/>
</p>
<p>
<label for="titulo">Titulo:</label>
<input type="text" name= "titulo"/>
</p>
<p>
<label for="categoria">Categoria :</label>
<input type="text" name="categoria"/>
</p>
<p>
<input type="button" value="Insertar" onclick="validacion()">
</p>
</fieldset>

uespues de anadlr esLas eLlqueLas, podemos pasar a las slgulenLes Lareas encargadas
de me[orar el uso de esLndares a nlvel de P1ML.
6. Uso de kn1ML como estndar.
xP1ML es hoy por hoy el esLndar que se uLlllza a la hora de consLrulr paglnas P1ML ,
en espera de que P1ML 3 se lmponga en el mercado. ara consegulr que nuesLra
paglna web cumpla con los requerlmlenLos de xP1ML, neceslLamos reallzar las
slgulenLes modlflcaclones a nuesLra pglna.
1. Anadlr declaracln xML al documenLo
2. Anadlr uCC1?L al documenLo
3. Anadlr espaclo de nombres (xml namespace)
4. 1odas las eLlqueLas deben ser declaradas en mlnusculas
3. 1oda eLlqueLa ablerLa debe ser cerrada

!"#$%&'(&$") +),)
28
Aunque en prlnclplo parecen basLanLes camblos, son rpldos de apllcar. vamos a ver
como queda modlflcado nuesLro cdlgo para cumpllr con xP1ML.
Cdlgo 1.6: (lormularloLlbro06xP1ML.hLml)
<?xml version="1.0" encoding="UTF-8"?>
1

<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"DTD/xhtml1-strict.dtd">
2

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es" lang="es">
3

<head>
<!omitimos JavaScript y cabecera-->
<title>Ejemplo01</title>
</head>
<body>
<form >
<fieldset>
<legend>Formulario alta libro</legend>
<!Omitimos etiquetas que no varan!
<p>
<input type="button" value="Insertar" onclick="validacion()"/>
</p>
</fieldset></form>
</body>
</html>

Pemos anadldo una serle de cabeceras al documenLo que permlLen valldar el
formularlo como xP1ML y nos hemos encargado Lamblen de abrlr y cerrar
correcLamenLe las eLlqueLas P1ML. Ln esLos momenLos podemos nuesLro documenLo
cumple los esLndares algo que podemos comprobar sl uLlllzamos la herramlenLa
Webueveloper de llrefox como muesLra la slgulenLe lmagen.




7. Uso de estndares DCM
uCM o uocumenL Cb[ecL Model es el esLndar que usan Lodos los navegadores para
represenLar en memorla la paglna como una serle de nodos enlazados enLre sl en forma
de rbol (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
29

uCM es usado por !avaScrlpL para acceder a los dlsLlnLos elemenLos de la pglna. Ln
nuesLro caso, el uso de uCM afecLa a la funcln de valldacln que hemos consLruldo en
!avaScrlpL. ara faclllLar y esLandarlzar el uso de uCM en nuesLra pglna,
modlflcaremos algunas de las eLlqueLas de nuesLro formularlo P1ML y les anadlremos
aLrlbuLos de ldenLlflcador ld"como muesLra el slgulenLe bloque de cdlgo.
Cdlgo 1.7: (lormularloLlbro07uCM.hLml)
<p><label for="isbn">ISBN:</label>
<input id="isbn" type="text" name="isbn"/></p>
<p>
<label for="titulo">Titulo:</label>
<input id="titulo" type="text" name= "titulo"/>
</p><p>
<label for="categoria">Categoria :</label>
<input id="categoria" type="text" name="categoria"/>
</p>

una vez reallzados esLos camblos a nlvel de esLrucLura P1ML, podremos usar el Al de
uCM de !avaScrlpL para acceder de una forma ms dlrecLa a los dlsLlnLos elemenLos de
la paglna .Ln esLe caso, haremos uso de la slgulenLe lnsLruccln.
Cdlgo 1 8: (lormularloLlbro07uCM.hLml)
document.getElementById(identificador);

!"#$%&'(&$") +),)
30
ulcha lnsLruccln slrve para acceder a un elemenLo deLermlnado del documenLo a
Lraves de su ldenLlflcador , de esLa forma, la funcln de !avaScrlpL pasar a Lener la
slgulenLe esLrucLura.
Cdlgo1.9: (lormularloLlbro08!avaScrlpLuCM.hLml)
function validacion() {
var isbn= document.getElementById("isbn");
var miformulario=document.getElementById("miformulario");
if(isbn.value==""){
alert("datos no validos");
return false;
}else{
miformulario.submit();
}
}
</script>

Ll uso de uCM a nlvel de !avaScrlpL vlslblemenLe nos permlLe ganar en clarldad y
senclllez a la hora de consLrulr nuesLras funclones de valldacln. Llegados a esLe punLo,
hemos Lermlnado de deflnlr las Lareas asocladas al uso de esLndares. La ulLlma Larea
pendlenLe esL orlenLada a me[orar el proplo funclonamlenLo de la pglna en el caso de
que el navegador no soporLe !avaScrlpL (usuarlos con dlscapacldad).
8. Uso de IavaScr|pt Degradab|e
Ls el momenLo de ver cmo nuesLro formularlo se comporLa en slLuaclones adversas
como puede ser el caso de que el navegador no dlsponga de !avaScrlpL. ara slmular
esLa slLuacln, usaremos e| p|ug|n WebDeve|oper que permlLe deshablllLar el
!avaScrlpL de una pglna en concreLo . La slgulenLe lmagen muesLra deshablllLar
!avaScrlpL usando esLa herramlenLa.
!!!"#$%&'()*(&$#+#,#"*-.
31
1ras deshablllLar el !avaScrlpL, nos podemos dar cuenLa de que el boLn del formularlo
ha de[ado de funclonar. LsLo se debe a que nuesLro formularlo no ha sldo dlsenado
para soporLar una degradacln correcLa de !avaScrlpL y de[a de funclonar en ausencla
de esLe. ara consegulr que el formularlo se degrade es necesarlo reallzar dos
modlflcaclones.
1. Camblar el Llpo de boLn que esLamos usando por Llpo "subm|t".
2. Camblar el evenLo de Llpo "onc||ck" a Llpo "onsubm|t" y ublcarlo a nlvel del
proplo formularlo
A conLlnuacln se muesLran las modlflcaclones que se preclsan reallzar en cdlgo.
Cdlgo 1.10:(lormularloLlbro09!avascrlpLuegradable.hLml)
<body>
<form action="destino.html" onsubmit="return validacion();" >
<!cdigo omitido-->
<input type="submit" value="Insertar" />
</form>


una vez reallzadas esLas modlflcaclones el formularlo funclonar de forma correcLa en
el caso de que el navegador no soporLe !avaScrlpL. Ln esLos momenLos dlsponemos de
una versln flnal de nuesLro formularlo. A conLlnuacln, pasaremos a modlflcar la CSS
de esLe para que enca[e de forma ms naLural con las ulLlmas modlflcaclones
reallzadas. A conLlnuacln se muesLra el cdlgo de la nueva ho[a.
Cdlgo1.11 : (formaLo.css)
legend,label {
font-weight:bold;
}
p {
text-align:right;
width:300px;
}

or ulLlmo modlflcaremos la pglna para que exLernallce correcLamenLe la ho[a de
esLllo y la funcln de !avaScrlpL.


!"#$%&'(&$") +),)
32
Cdlgo1.12: (valldaclon.[s)
<head>
<link rel="stylesheet" type="text/css" href="css/formato.css" />
<script type="text/javascript" src="js/validacion.js" >
</script>
</head>

una vez reallzadas esLas modlflcaclones podemos ver el resulLado flnal
!"#$%"&
LsLe caplLulo nos ha servldo para consLrulr un formularlo P1ML que usaremos mas
adelanLe en nuesLra apllcacln !LL .ero sobre Lodo nos ha servldo para lrnos
famlllarlzando con la esLrucLura de conLenldos que Lendrn los dlsLlnLos caplLulos.


!!!"#$%&'()*(&$#+#,#"*-.
33

!"#$%&'(&$") +),)
34
!!!"#" %&'#&' (")&*




Ln el caplLulo anLerlor hemos consLruldo un formularlo P1ML. Ln esLe caplLulo nos
encargaremos de consLrulr las prlmeras pglnas !S de nuesLra apllcacln, esLas se
encargarn de guardar los daLos de nuesLros llbros en base de daLos, asl como de
mosLrar una llsLa con los llbros que hemos almacenado en esLa. A conLlnuacln se
deLallan los ob[eLlvos del caplLulo.
Objetivos:
Crear la paglna lnserLarLlbro.[sp" que se encargar de lnserLar llbros en
nuesLra base de daLos.
Crear la paglna MosLrarLlbros.[sp" que se encargar de presenLar una llsLa con
los llbros almacenados en la base de daLos.
Tareas:
1. ConsLruccln de la Labla Llbros en un servldor MySCL.
2. lnsLalacln de un drlver !u8C naLlvo para acceder a la base de daLos desde !ava.
3. Creacln de la paglna lnserLarLlbro.[sp".
4. Creacln de la paglna MosLrarLlbros.[sp".
1. Creac|n de una tab|a L|bros
ara reallzar esLa Larea neceslLamos haber lnsLalado prevlamenLe un servldor MySCL y
anadldo un esquema denomlnado arqu|tectura[ava" a esLe. una vez reallzadas esLas
dos operaclones elemenLales, usaremos la herramlenLa MySCL Cuery8rowser para
crear una Labla con los slgulenLes campos:

!!!"#$%&'()*(&$#+#,#"*-.
35
lsbn: varchar (10).
1lLulo: varchar (30).
CaLegorla: varchar (30).

A conLlnuacln se muesLra una lmagen con la Labla ya creada denLro del esquema.

1ras crear la Labla en la base de daLos, la slgulenLe Larea que nos ayuda a lnsLalar un
drlver !u8C.
2. Insta|ar e| dr|ver ID8C.
Al crear la Labla en el servldor MySCL ser preclso acceder a ella desde nuesLra
apllcacln web , para ello neceslLaremos lnsLalar en la apllcacln un drlver !u8C naLlvo
para MySCL. Ll drlver se puede obLener de la slgulenLe url.
http://www.mysql.com/downloads/connector/j/

uespues de obLener el drlver (formaLo Lar.gz para ubunLu) lo vamos a descomprlmlr y
asl obLendremos el flchero mysq|-connector-[ava-S.1.12-b|n.[ar que conLlene las clases
que nos permlLen conecLarnos a MySCL desde !ava. 1ras obLener esLe flchero, lo
anadlremos a la carpeLa ||b de nuesLra apllcacln web (ver lmagen)

1ermlnadas ya esLas prlmeras Lareas orlenLadas ms hacla la admlnlsLracln que hacla
el desarrollo, podemos comenzar a consLrulr las pglnas de nuesLra apllcacln.
!"#$%&'(&$") +),)
36
3. Creac|n de |a pg|na "InsertarL|bro.[sp"
La pglna lnserLarLlbro.[sp" recoger los daLos envlados por el formularlo consLruldo
en el caplLulo anLerlor e lnserLar un nuevo reglsLro en la base de daLos .Ll slgulenLe
dlagrama muesLra la relacln enLre los Lres elemenLos.

Como podemos observar hemos renombrado el flchero del caplLulo anLerlor como
lormularlolnserLarLlbro.[sp
Aslgnndole .[sp para que, a parLlr de esLos momenLos, Lodas las paglnas comparLan la
mlsma exLensln. Ls el momenLo de pasar a consLrulr la paglna lnserLarLlbro.[sp", a
conLlnuacln se muesLra su cdlgo fuenLe.
Cdlgo 2.1: (lnserLarLlbro.[sp)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- sentencias de import necesarias para jdbc-->
<%@ page import="java.sql.Connection"%>
<%@ page import="java.sql.Statement"%>
<%@ page import="java.sql.DriverManager"%>
<%@ page import="java.sql.SQLException"%>

<%
//1
String isbn = request.getParameter("isbn");
String titulo = request.getParameter("titulo");
String categoria = request.getParameter("categoria");

Connection conexion = null;
Statement sentencia = null;

!!!"#$%&'()*(&$#+#,#"*-.
37
int filas=0;
try {
//2
Class.forName("com.mysql.jdbc.Driver");
conexion = DriverManager.getConnection(
"jdbc:mysql://localhost/arquitecturajava",
"root",
"java");

sentencia = conexion.createStatement();
//3
String consultaSQL = "insert into Libros (isbn,titulo,categoria) values ";
consultaSQL += "('" + isbn + "','" + titulo + "','" + categoria + "')";
//4
filas = sentencia.executeUpdate(consultaSQL);

response.sendRedirect("MostrarLibros.jsp");

} catch (ClassNotFoundException e) {

System.out.println("Error en la carga del driver"
+ e.getMessage());

} catch (SQLException e) {
System.out.println("Error accediendo a la base de datos"
+ e.getMessage());
} finally {
//5
if (sentencia != null) {

try {sentencia.close();}
catch (SQLException e)
{System.out.println("Error cerrando la sentencia" +
e.getMessage());}
}
if (conexion != null) {

try {conexion.close();}
catch (SQLException e)
{System.out.println("Error cerrando la conexion" +
e.getMessage());}
}
}%>

Ls evldenLe que el cdlgo de la paglna aunque senclllo, es Lamblen basLanLe exLenso ya
que se encarga de gesLlonar la conexln a la base de daLos y posLerlor e[ecucln de una
consulLa .A conLlnuacln se enumeran las prlnclpales operaclones que el cdlgo reallza.
!"#$%&'(&$") +),)
38
1. Lee la lnformacln que provlene de lormularlolnserLarLlbro.hLml usando el
ob[eLo requesL de !S.
2. Crea un ob[eLo de Llpo ConnecLlon(conexln) y un ob[eLo de Llpo SLaLemenL
(senLencla)
3. Crea una consulLa SCL de lnsercln con los daLos del llbro
4. L[ecuLa la senLencla con su SCL
3. Clerra los recursos (conexln ,senLencla eLc)
A conLlnuacln se muesLra una lmagen de la esLrucLura del proyecLo y el nuevo flchero
que acabamos de crear.




1ermlnada esLa prlmera pglna, es momenLo de abordar el segundo ob[eLlvo del
caplLulo.
4. Creac|n de |a pag|na MostrarL|bros.[sp
La pglna MosLrarLlbros.[sp" se encargar de mosLrar una llsLa compleLa de Lodos los
llbros que Lenemos almacenados en la base de daLos. ara ello har uso del Al de !u8C
(ver lmagen).



!!!"#$%&'()*(&$#+#,#"*-.
39
LsLe es el cdlgo fuenLe de la pglna.
Cd|go 2.2:MostrarL|bros.[sp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.Statement" %>
<%@ page import="java.sql.DriverManager" %>
<%@ page import="java.sql.SQLException" %>
<%@ page import="java.sql.ResultSet" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Lista de Libros</title>
</head>
<body>
<%
Connection conexion=null;
Statement sentencia=null;
ResultSet rs=null;
try {
Class.forName("com.mysql.jdbc.Driver");
//1
conexion =
DriverManager.getConnection("jdbc:mysql://localhost/arquitecturajava",
"root",
"java");

sentencia= conexion.createStatement();
//2
String consultaSQL= "select isbn,titulo,categoria from Libros";
//3 y 4
rs=sentencia.executeQuery(consultaSQL);
//5
while(rs.next()) { %>

<%=rs.getString("isbn")%>
<%=rs.getString("titulo")%>
<%=rs.getString("categoria")%>
<br/>


<% }

}catch (ClassNotFoundException e) {

System.out.println("Error en la carga del driver"
!"#$%&'(&$") +),)
40
+ e.getMessage());

}catch (SQLException e) {

System.out.println("Error accediendo a la base de datos"
+ e.getMessage());
}
finally {
//6
if (rs != null) {

try {rs.close();} catch (SQLException e)
{System.out.println("Error cerrando el resultset" + e.getMessage());}

}

if (sentencia != null) {

try {sentencia.close();} catch (SQLException e)
{System.out.println("Error cerrando la sentencia" + e.getMessage());}

}
if (conexion != null) {

try {conexion.close();} catch (SQLException e)
{System.out.println("Error cerrando la conexion" + e.getMessage());}
}
}
%>
<a href="FormularioInsertarLibro.jsp">Insertar Libro</a>
</body></html>

odemos apreclar que el cdlgo fuenLe de MosLrarLlbro.[sp reallza las slgulenLes Lareas.
1. Crea un ob[eLo conexln y un ob[eLo senLencla.
2. Crea una consulLa SCL de seleccln para Lodos los llbros de la Labla.
3. L[ecuLa la senLencla con su SCL.
4. uevuelve un !"#$%&'"& con Lodos los reglsLros.
3. 8ecorre el !"#$%&'"& y lo lmprlme en hLml.
6. Clerra los recursos (conexln ,senLencla, eLc).
una vez creadas ambas pglnas, podemos lnvocar la pglna MosLrarLlbros.[sp a Lraves
del navegador y asl ver cul es la llsLa lnlclal de llbros que presenLa(hemos lnserLado 2).
!!!"#$%&'()*(&$#+#,#"*-.
41

1ras cargar esLa pglna, podremos pulsar en el enlace que nos redlrlge al formularlo de
lnsercln (ver lmagen)

Ln el momenLo en que pulsemos al boLn de lnserLar un nuevo llbro, esLe ser
lnserLado en la Labla Llbros y la apllcacln volver a mosLrar la pglna MosLrarLlbros.[sp
(ver lmagen).
!"#$%&'(&$") +),)
42
or ulLlmo mosLramos la esLrucLura de flcheros flnal del caplLulo.

!"#$%"&
Ln esLe caplLulo hemos progresado al anadlr una nueva funclonalldad a nuesLra
apllcacln, que en esLos momenLos ya es capaz de lnserLar y selecclonar reglsLros en la
base de daLos.
!!!"#$%&'()*(&$#+#,#"*-.
43

!"#$%&'(&$") +),)
44
!!!"# % &'(




Ln el caplLulo anLerlor hemos consLruldo la funclonalldad de lnserLar y llsLar llbros . Sln
embargo, sl revlsamos el cdlgo de nuesLras paglnas, veremos que gran parLe es
ldenLlco en ambas. LsLo es muy hablLual en el desarrollo de apllcaclones y genera
problemas de manLenlmlenLo pues sl en algun momenLo hay que camblar parLe del
cdlgo, en vlsLa de que lo hemos repeLldo en Lodas las pglnas, ser necesarlo reallzar
las modlflcaclones una por una . ara solvenLar esLe problema, en esLe caplLulo
lnLroduclremos uno de los prlnclplos mas lmporLanLes de lngenlerla de sofLware e|
pr|nc|p|o Dk.
Dk : u8? o uon'L 8epeaL ?ourSelf lmpllca que, cualquler funclonalldad exlsLenLe en un
programa debe exlsLlr de forma unlca en el , o lo que es lo mlsmo, no debemos Lener
bloques de cdlgo repeLldos.

Cb[et|vos:
Apllcar el prlnclplo u8? a las pglnas que hemos consLruldo hasLa esLe
momenLo,ellmlnando cualquler repeLlcln de cdlgo.
Avanzar en la consLruccln de la apllcacln y anadlr un desplegable de
caLegorlas. 8evlsar el uso del prlnclplo u8? apoyndonos en dlcho desplegable





!!!"#$%&'()*(&$#+#,#"*-.
45
1areas:
1. Apllcar el prlnclplo u8? y crear una nueva clase que ayude a ellmlnar el cdlgo
repeLldo !u8C de las pglnas.
2. Modlflcar las pglnas !S para que deleguen parLe de su funclonalldad en la
nueva clase.
3. Anadlr desplegable de caLegorlas para segulr profundlzando en la apllcacln del
prlnclplo u8?.
4. Ll prlnclplo u8? y las consulLas SCL.
3. Ll prlnclplo u8? meLodos y parmeLros
6. 8esulLSeL vs llsLas de ob[eLos
7. uso de lnLerfaces a nlvel de llbro
8. Clerre de conexlones usando reflecLlon
1. Aad|r nueva c|ase
Ln nuesLro caso nos vamos a cenLrar en ellmlnar el cdlgo !u8C repeLldo en nuesLras
pglnas (ver lmagen).


!"#$%&'(&$") +),)
46
ara ello vamos a una nueva clase que se se va a denomlnar uaLa8asePelper y nos
ayudara a gesLlonar me[or el cdlgo !u8C. LsLa clase lmplemenLar los slgulenLes
meLodos:
pub||c stat|c kesu|tSet se|ecc|onarkeg|stros(Str|ng sq|): MeLodo que se encargar de
e[ecuLar una consulLa SCL de seleccln y devolvernos un con[unLo de reglsLros con una
esLrucLura de 8esulLSeL.
pub||c stat|c vo|d mod|f|carkeg|stro(Str|ng sq|) :MeLodo que se encargar de e[ecuLar
cualquler consulLa SCL de modlflcacln (lnserL,updaLe,deleLe eLc) y devolvernos un
enLero con el numero de fllas afecLadas.
A conLlnuacln se muesLra su cdlgo fuenLe.
Cdlgo 3.1: (uaLa8asePelper.[ava)
package com.arquitecturajava;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class DataBaseHelper {

private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost/arquitecturajava";
private static final String USUARIO = "root";
private static final String CLAVE = "java";

public int modificarRegistro(String consultaSQL) {

Connection conexion = null;
Statement sentencia = null;
int filasAfectadas = 0;

try {

Class.forName(DRIVER);
conexion = DriverManager.getConnection(URL,

USUARIO, CLAVE);

sentencia = conexion.createStatement();
filasAfectadas = sentencia.executeUpdate(consultaSQL);

} catch (ClassNotFoundException e) {
!!!"#$%&'()*(&$#+#,#"*-.
47

System.out.println("Error driver" + e.getMessage());
} catch (SQLException e) {

System.out.println("Error de SQL" + e.getMessage());
} finally {

if (sentencia != null) {

try {sentencia.close();} catch (SQLException e) {}

}
if (conexion != null) {

try {conexion.close();} catch (SQLException e) {}
}

}
return filasAfectadas;
}
public ResultSet seleccionarRegistros(String consultaSQL) {

Connection conexion = null;
Statement sentencia = null;
ResultSet filas = null;
try {
Class.forName(DRIVER);

conexion = DriverManager.getConnection(URL,
USUARIO, CLAVE);

sentencia = conexion.createStatement();

filas = sentencia.executeQuery(consultaSQL);
} catch (ClassNotFoundException e) {
System.out.println("Error Driver" + e.getMessage());
} catch (SQLException e) {
System.out.println("Error de SQL " + e.getMessage());
}
return filas;
}
}

una vez que esLa clase esLe consLrulda, las pglnas !S de nuesLra apllcacln
slmpllflcarn slgnlflcaLlvamenLe el cdlgo que conLlenen y delegarn en la clase
uaLa8asePelper para reallzar la mayor parLe de las operaclones !u8C (ver lmagen) .
!"#$%&'(&$") +),)
48

Acabamos de consLrulr la clase uaLa8asePelper, es momenLo de pasar a modlflcar las
paglnas !S para que deleguen en ella.
2. Mod|f|car pag|nas IS
1ras la consLruccln de la nueva clase, modlflcaremos el cdlgo de las pglnas que se
ven afecLadas lnserLarLlbro.[sp y MosLrarLlbros.[sp (ver cdlgo).
Cdlgo 3.2: (lnserLarLlbro.[sp)
<%@page import="com.arquitecturajava.DataBaseHelper"%>
<%
String isbn= request.getParameter("isbn");
String titulo= request.getParameter("titulo");
String categoria= request.getParameter("categoria");
//realizo la consulta usando el DBHelper y el codigo queda simplificado
String consultaSQL= "insert into Libros (isbn,titulo,categoria) values ";
consultaSQL+= "('" +isbn+ "','" +titulo + "','" +categoria+"')";
DataBaseHelper db= new DataBaseHelper();
int filas=db.modificarRegistro(consultaSQL);
response.sendRedirect("MostrarLibros.jsp");
%>

!!!"#$%&'()*(&$#+#,#"*-.
49
Como podemos ver la pglna lnserLarLlbros.[sp queda vlslblemenLe slmpllflcada .Sln
embargo, no ocurre lo mlsmo con MosLrarLlbros.[sp, (ver lmagen).
Cdlgo 3.3: (MosLrarLlbros.[sp)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>

<%@ page import="java.sql.ResultSet"%>
<%@ page import="java.sql.SQLException"%>
<%@page import="com.arquitecturajava.DataBaseHelper"%>
<!omitimos cabecera!
<body>
<%
ResultSet rs = null;
try {
String consultaSQL = "select isbn,titulo,categoria from Libros";
DataBaseHelper helper = new DataBaseHelper();
rs = helper.seleccionarRegistros(consultaSQL);
while (rs.next()) {
%>
<%=rs.getString("isbn")%>
<%=rs.getString("titulo")%>
<%=rs.getString("categoria")%>
<br />
<%
}
}
catch (SQLException e) {

System.out.println("Error accediendo a la base de datos"
+ e.getMessage());
} finally {

if (rs != null) {

try {
rs.close();
} catch (SQLException e) {
System.out.println("Error cerrando el resultset"
+ e.getMessage());
}

}
}
%>
<a href="FormularioInsertarLibro.jsp">Insertar Libro</a>
</body>
</html>

!"#$%&'(&$") +),)
50
ara poder slmpllflcar aun ms el cdlgo de la pglna MosLrarLlbros.[sp preclsaremos
apoyarnos de nuevo en el prlnclplo u8?. Sln embargo, con Lan poco cdlgo consLruldo,
es dlflcll ver cmo apllcarlo con mayor coherencla. Asl pues vamos a anadlr una nueva
funclonalldad a nuesLra apllcacln para en adelanLe ver las cosas con mayor clarldad.
3. Aad|r I||tro por categor|a
vamos a anadlr un desplegable de caLegorlas a la pglna MosLrarLlbros.[sp que nos
permlLlr posLerlormenLe reallzar fllLrados sobre la llsLa dependlendo de la caLegorla
que ell[amos (ver lmagen) .
ara consegulr que nuesLra pglna de MosLrarLlbros muesLre el desplegable Lendremos
que anadlrle el slgulenLe bloque de cdlgo.
Cdlgo 3.4: (MosLrarLlbros.[sp)
<select name="categoria">
<option value="seleccionar">seleccionar</option>
<%
ResultSet rs=null;
try {
String consultaSQL = "select distinct(categoria) from Libros";
DataBaseHelper helper = new DataBaseHelper();
rs=helper.seleccionarRegistros(consultaSQL);
while(rs.next()) { %>
<option value="<%=rs.getString("categoria")%>">
<%=rs.getString("categoria")%></option>
<% } %>
</select>
<br/>

!!!"#$%&'()*(&$#+#,#"*-.
51
Ln prlnclplo esLa accln no es muy compllcada, sln embargo sl revlsamos el formularlo
de lnsercln, nos daremos cuenLa de que hay dlsenarlo como desplegable (ver lmagen).

Ln la pglna de MosLrarLlbros.[sp uLlllzaremos el desplegable para fllLrar la llsLa de
llbros por caLegorla, mlenLras que el formularlo permlLlr al usuarlo selecclonar las
caLegorlas de forma ms sencllla, evlLando cualquler Llpo de error de escrlLura al esLar
prefl[adas. Ahora blen, la consulLa SCL esL repeLlda en ambas pglnas como se
muesLra en la slgulenLe lmagen.
!"#$%&'(&$") +),)
52

or lo LanLo nos enconLramos en una slLuacln slmllar a la anLerlor , slo que en esLa
ocasln en vez de Lener cdlgo !u8C repeLldo Lenemos consulLas SCL.
4. L| pr|nc|p|o Dk y |as consu|tas SL
ara evlLar la repeLlcln de SCLs a lo largo de las dlsLlnLas pglnas !S (con los
problemas de manLenlmlenLo asoclados) nos apoyaremos en la ldea anLerlor y
crearemos una nueva clase que se encargue de gesLlonar las consulLas.
uenomlnaremos a la nueva clase L|bro : esLa almacenar Lodas las consulLas que
mane[en los daLos que la Labla Llbro conLlene. A conLlnuacln se muesLra una lmagen
sobre cmo enca[a la nueva clase en la esLrucLura que ya Lenlamos deflnlda.

!!!"#$%&'()*(&$#+#,#"*-.
53

Clarlflcado asl donde enca[a la nueva clase en nuesLra arqulLecLura, vamos a mosLrar su
cdlgo fuenLe.
Cdlgo 3.3 : (Llbro.[ava)
public class Libro {
public static ResultSet buscarTodasLasCategorias() {
String consultaSQL = "select distinct(categoria) from Libros";
DataBaseHelper helper = new DataBaseHelper();
ResultSet rs = helper.seleccionarRegistros(consultaSQL);
return rs;
}
public static void insertar(String isbn, String titulo, String categoria) {
String consultaSQL = "insert into Libros (isbn,titulo,categoria) values ";
consultaSQL += "('" + isbn + "','" + titulo + "','" + categoria + "')";
DataBaseHelper helper = new DataBaseHelper();
helper.modificarRegistro(consultaSQL);
}
public static ResultSet buscarTodos() {
String consultaSQL = "select isbn,titulo,categoria from Libros";
DataBaseHelper helper = new DataBaseHelper();
ResultSet rs = helper.seleccionarRegistros(consultaSQL);
return rs;
}}
!"#$%&'(&$") +),)
54
Como podemos ver, la clase alberga Lres meLodos.
1. buscar1odos()
2. buscarorCaLegorla()
3. lnserLar()
Cada uno de ellos se encarga de e[ecuLar una de las consulLas necesarlas para la Labla
Llbros. una vez creada esLa clase, las paglnas !S podrn delegar en ella y ellmlnar las
consulLas SCL de las pglnas. A conLlnuacln se muesLra la paglna lnserLarLlbro.[sp"
como e[emplo del uso de la clase Llbro en las pglnas !S.
Cdlgo 3.6: (lnserLarLlbro.[sp)
<%@page import="com.arquitecturajava.Libro"%>
<% String isbn= request.getParameter("isbn");
String titulo= request.getParameter("titulo");
String categoria= request.getParameter("categoria");
//realizo la consulta usando el DBHelper y el codigo queda simplificado
Libro.insertar(isbn,titulo,categoria);
response.sendRedirect("MostrarLibros.jsp");%>

Pemos ellmlnado las consulLas SCL de nuesLras pglnas apllcando el prlnclplo u8?. Sln
embargo es buen momenLo para volver a revlsar esLe prlnclplo de cara a la nueva clase
Llbro que hemos consLruldo. Sl nos fl[amos en la flrma del meLodo lnserLar,
Cdlgo3.7: (Llbro.[ava)
public static void insertar(String isbn, String titulo, String categoria)

nos podemos dar cuenLa de que probablemenLe no sea el unlco meLodo que lncluya
esLos parmeLro,s ya que el meLodo modlflcar y el meLodo borrar Lendrn parmeLros
slmllares cuando se consLruyan:
Cdlgo 3.8: (Llbro.[ava)
public static void editar(String isbn, String titulo, String categoria)
public static void borrar(String isbn)

arece claro que Lodos comparLen un mlsmo grupo de parmeLros. Ls una ocasln
perfecLa para volver a apllcar el prlnclplo u8? y ellmlnar esLa repeLlcln de parmeLros.
!!!"#$%&'()*(&$#+#,#"*-.
55
S. L| pr|nc|p|o Dk mtodos y parametros
Ln programacln orlenLada a ob[eLo, una clase slempre se compone de propledades y
meLodos o funclones. Ln nuesLro caso, la clase Llbro no dlspone de propledades y de
ahl los problemas con Lodos los parmeLros(ver lmagen).

or lo LanLo, vamos a modlflcar nuesLra clase para que dlsponga de las propledades
necesarlas y los meLodos se puedan apoyar en ellas evlLando repeLlclones lnnecesarlas.
La slgulenLe lmagen clarlflca la nueva esLrucLura de la clase y como esLa se apoya en el
prlnclplo u8?.

una vez Lenemos claro las modlflcaclones que afecLaran a la clase, vamos a ver su
cdlgo fuenLe.
!"#$%&'(&$") +),)
56

Cdlgo 3.9: (Llbro.[ava)
public class Libro {
private String isbn;
private String titulo;
private String categoria;
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitulo() {
return titulo;
}
public void setTitulo(String titulo) {
this.titulo = titulo;
}
public String getCategoria() {
return categoria;
}
public void setCategoria(String categoria) {
this.categoria = categoria;
}
public Libro(String isbn, String titulo, String categoria) {
this.isbn = isbn;
this.titulo = titulo;
this.categoria = categoria;
}
public static ResultSet buscarTodasLasCategorias() {
String consultaSQL = "select distinct(categoria) from Libros";
DataBaseHelper helper = new DataBaseHelper();
ResultSet rs = helper.seleccionarRegistros(consultaSQL);
return rs;}
public void insertar() {
String consultaSQL = "insert into Libros (isbn,titulo,categoria) values ";
consultaSQL += "('" + this.isbn + "','" + this.titulo + "','"
+ this.categoria + "')";
DataBaseHelper helper = new DataBaseHelper();
helper.modificarRegistro(consultaSQL);
}
public static ResultSet buscarTodos() {
String consultaSQL = "select isbn,titulo,categoria from Libros";
DataBaseHelper helper = new DataBaseHelper();
ResultSet rs = helper.seleccionarRegistros(consultaSQL);
return rs;
}}

!!!"#$%&'()*(&$#+#,#"*-.
57
vlsLo asl el cdlgo fuenLe, es momenLo de mosLrar las modlflcaclones que debemos
reallzar a nlvel de las pglnas !S. Ln esLe caso volveremos a apoyarnos en la pglna
lnserLarLlbro.[sp.
Cdlgo 3.10: (lnserLarLlbro.[sp)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="com.arquitecturajava.Libro"%>
<% String isbn= request.getParameter("isbn");
String titulo= request.getParameter("titulo");
String categoria= request.getParameter("categoria");
Libro libro= new Libro(isbn,titulo,categoria);
libro.insertar();
response.sendRedirect("MostrarLibros.jsp");
%>

vemos que el meLodo lnserLar ya no neceslLa reclblr nlngun Llpo de parmeLro ya que
obLlene Loda la lnformacln necesarla de las propledades que son aslgnadas a nlvel del
consLrucLor del ob[eLo. Ll avance ha sldo slgnlflcaLlvo, sln embargo Lodavla quedan
algunas cuesLlones pendlenLes. nos referlmos a los meLodos de busqueda que en esLos
momenLos devuelven 8esulLSeLs (ver cdlgo).
Cdlgo 3.11(Llbro.[ava)
public ResultSet buscarTodos();
public ResultSet buscarCategorias();

6. kesu|tSets vs L|stas de ob[etos

ara las paglnas !S serla mucho ms senclllo a la hora de Lraba[ar el reclblr una llsLa de
ob[eLos (llsLa de Llbros) ya que no Lendrla que encargarse cerrar el 8esulLSeL y gesLlonar
las poslbles excepclones. or lo LanLo, nuesLra Larea ser modlflcar los meLodos de
busqueda para que devuelvan esLrucLuras de Llpo llsLa .vamos a ver como esLos camblos
se lmplemenLan a nlvel de cdlgo.

.



!"#$%&'(&$") +),)
58
Cdlgo 3.12: (Llbro.[ava)
public static ArrayList<Libro> buscarTodos() {
String consultaSQL = "select isbn,titulo,categoria from Libros";
DataBaseHelper helper = new DataBaseHelper();
ResultSet rs = helper.seleccionarRegistros(consultaSQL);
ArrayList<Libro> listaDeLibros= new ArrayList<Libro>();
try {
while (rs.next()) {
listaDeLibros.add(new Libro(rs.getString("isbn"),
rs.getString("titulo"),
rs.getString("categoria")));

}
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return listaDeLibros;
}

una vez modlflcado el meLodo buscar1odos() para que devuelva una llsLa de llbros, la
paglna MosLrarLlbros.[sp podr apoyarse en el nuevo meLodo a la hora de mosLrar los
daLos.
Cdlgo 3.13: (Llbro.[ava)
<%
ArrayList<Libro> listaDeLibros=null;
listaDeLibros=Libro.buscarTodos();
for(Libro libro:listaDeLibros){ %>
<%=libro.getIsbn()%>
<%=libro.getTitulo()%>
<%=libro.getCategoria()%>
<br/>
<% }
%>

Asl, ya no exlsLen referenclas a !u8C en la paglna, el mlsmo camblo se puede apllcar al
meLodo de buscar1odasLasCaLegorlas(). A conLlnuacln se muesLra su cdlgo fuenLe.



!!!"#$%&'()*(&$#+#,#"*-.
59
Cdlgo 3.14: (Llbro.[ava)
public static ArrayList<String> buscarTodasLasCategorias() {
String consultaSQL = "select distinct(categoria) as categoria
from Libros";
DataBaseHelper helper = new DataBaseHelper();
ResultSet rs = helper.seleccionarRegistros(consultaSQL);
ArrayList<String> listaDeCategorias= new ArrayList<String>();
String categoria=null;
try {
while (rs.next()) {
categoria= rs.getString("categoria");
listaDeCategorias.add(categoria);
}
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return listaDeCategorias;
}

7. Uso de |nterfaces a n|ve| de L|bro
Ln esLos momenLos dlsponemos de meLodos de busqueda de Llbros o CaLegorlas que
devuelven un ArrayLlsL de un Llpo deLermlnado <Llbro> o< SLrlng> (ver cdlgo).
Sl queremos Lener una mayor flexlbllldad en el parmeLro de reLorno, se debe camblar
el Llpo ArrayLlsL por el Interface L|st (ver cdlgo).


!"#$%&'(&$") +),)
60
A conLlnuacln se muesLra como queda el meLodo una vez modlflcado.
Cdlgo 3.13: (Llbro.[ava)
public static List<Libro> buscarTodos() {
String consultaSQL = "select isbn,titulo,categoria from Libros";
DataBaseHelper helper = new DataBaseHelper();
ResultSet rs = helper.seleccionarRegistros(consultaSQL);
List<Libro> listaDeLibros= new ArrayList<Libro>();
try {
while (rs.next()) {
listaDeLibros.add(new Libro(rs.getString("isbn"),
rs.getString("titulo"),
rs.getString("categoria")));
}} catch (SQLException e) {
System.out.println(e.getMessage());
}
return listaDeLibros;
}

nos puede parecer que hemos Lermlnado de consLrulr la clase llbro y sl es clerLo que
no Lenemos que modlflcar nada a nlvel de esLrucLura general. Ahora blen, sl revlsamos
el cdlgo, veremos que el meLodo #"%"(()*+,-!".)#&-*# de la clase /,&,0,#"1"%2"- no
clerra la conexln cuando nos devuelve el !"#$%&'"& (ver cdlgo).
Cdlgo 3.16: (uaLa8asePelper.[ava)
public ResultSet seleccionarRegistros(String consultaSQL) {
Connection conexion = null;
Statement sentencia = null;
ResultSet filas = null;
try {
Class.forName(DRIVER);
conexion = DriverManager.getConnection(URL, USUARIO,
CLAVE);
sentencia = conexion.createStatement();
filas = sentencia.executeQuery(consultaSQL);
} catch (ClassNotFoundException e) {
System.out.println("Error de Driver" + e.getMessage());
} catch (SQLException e) {
System.out.println("Error de SQL " + e.getMessage());
}
return filas;
}

!!!"#$%&'()*(&$#+#,#"*-.
61
LsLo lamenLablemenLe es necesarlo ahora ya que sl cerramos la conexln a esLe nlvel la
clase Llbro no podr recorrer el 8esulLSeL y cargar la llsLa de Llbros (ver lmagen).

8. C|erre de conex|ones y ref|ect|on.
ara poder solvenLar el problema de clerre de conexlones, vamos a pasar a modlflcar la
clase uaLa8asePelper: la converLlremos en una clase Cenerlca de Lal forma que ella
mlsma, dependlendo del Llpo de clase que reclba como parmeLro en los meLodos de
busqueda, nos generar una llsLa de ob[eLos de ese Llpo concreLo (ver lmagen).
!"#$%&'(&$") +),)
62

Ahora blen, para que la clase uaLa8asePelper pueda hacer uso de generlcos y sea capaz
de consLrulr dlsLlnLos Llpos de llsLas de ob[eLos, hay que usar el Al de reflecLlon de
!ava: ser la encargada de, a parLlr de una consulLas SCL cualqulera, generar
auLomLlcamenLe una llsLa de ob[eLos del Llpo que nosoLros sollclLamos (ver lmagen).

A conLlnuacln se muesLra el cdlgo fuenLe que se encarga de reallzar esLa conversln
no |o vamos a exp||car deta||adamente , su |mportanc|a es muy re|at|va pues en
!!!"#$%&'()*(&$#+#,#"*-.
63
cap|tu|os poster|ores ut|||zaremos un framework de pers|stenc|a para rea||zar este
t|po de operac|ones. Aun asl, a conLlnuacln se muesLra el cdlgo una vez modlflcado.
Cdlgo 3.17: (uaLa8asePelper.[ava)
public class DataBaseHelper<T> {
public List<T> seleccionarRegistros(String consultaSQL,Class clase) {
Connection conexion = null;
Statement sentencia = null;
ResultSet filas = null;
List<T> listaDeObjetos=new ArrayList<T>();
try {
Class.forName(DRIVER);
conexion = DriverManager.getConnection(URL, USUARIO, CLAVE);
sentencia = conexion.createStatement();
filas = sentencia.executeQuery(consultaSQL);
while (filas.next()) {
T objeto=(T) Class.forName(clase.getName()).newInstance();
Method[] metodos=objeto.getClass().getDeclaredMethods();
for (int i=0;i<metodos.length;i++) {
if (metodos[i].getName().startsWith("set") ) {
metodos[i].invoke(objeto,
filas.getString(metodos[i].getName().substring(3)));
}
if (objeto.getClass().getName().equals("java.lang.String")) {
objeto=(T)filas.getString(1);
}
}
listaDeObjetos.add(objeto);
}
} catch (Exception e) {
System.out.println("Error al seleccionar registros" + e.getMessage());
}
finally {
if (sentencia != null) {
try {sentencia.close();} catch (SQLException e) {}
}
if (conexion != null) {
try {conexion.close();} catch (SQLException e) {}
}
return listaDeObjetos;
}


!"#$%&'(&$") +),)
64
Comprobamos que ahora sl se reallza un correcLo clerre de conexlones. 1ermlnada esLa
operacln, los meLodos de la clase Llbro que uLlllzan el uaLa8asePelper<1> quedarn
muy slmpllflcados( ver cdlgo).
Cdlgo 3.18: (Llbro.[ava)
public static List<Libro> buscarTodos() {
String consultaSQL = "select isbn,titulo,categoria from Libros";
DataBaseHelper<Libro> helper = new DataBaseHelper<Libro>();
List<Libro> listaDeLibros = helper.seleccionarRegistros(consultaSQL,
Libro.class);
return listaDeLibros;
}
public static List<String> buscarTodasLasCategorias() {
String consultaSQL = "select distinct(categoria) as categoria from Libros";
DataBaseHelper<String> helper = new DataBaseHelper<String>();
List<String>listaDeCategorias = helper.seleccionarRegistros(consultaSQL,
String.class);
return listaDeCategorias;
}

1ras esLos camblos, vamos a mosLrar cmo queda el cdlgo flnal de la paglna MosLrarLlbros.[sp
en lo que a las llsLas se reflere.
Cdlgo 3.19: (MosLrarLlbros.[sp)
<select name="categoria">
<% List<String> listaDeCategorias=null;
listaDeCategorias=Libro.buscarTodasLasCategorias();
for(String categoria:listaDeCategorias) { %>
<option value="<%=categoria%>"><%=categoria%></option>
<% } %>
</select>
<%List<Libro> listaDeLibros=null;
listaDeLibros=Libro.buscarTodos();
for(Libro libro:listaDeLibros){ %>
<%=libro.getIsbn()%><%=libro.getTitulo()%><%=libro.getCategoria()%>
<br/>
<% }
%>
<a href="FormularioInsertarLibro.jsp">Insertar Libro</a>
</body></html>


!!!"#$%&'()*(&$#+#,#"*-.
65
kesumen
Ln esLe caplLulo nos hemos cenLrado en expllcar el prlnclplo u8? y apllcarlo en nuesLra
apllcacln. Como resulLado, han aparecldo dos nuevas clases Llbro y uaLa8asePelper.
La arqulLecLura de nuesLra apllcacln ha aumenLado su nlvel de comple[ldad pero
como conLrapresLacln hemos reducldo slgnlflcaLlvamenLe la engorrosa repeLlcln de
cdlgo , reduclendose Lamblen el esfuerzo de desarrollo.

!"#$%&'(&$") +),)
66
!"!"#$%&' )*&&%& + ,#-$&%&





Ln el caplLulo anLerlor hemos lnLroducldo el prlnclplo u8?. Ln esLe caplLulo nos
cenLraremos en anadlr una nueva funclonalldad a nuesLra apllcacln. veremos las
capacldades de edlcln, borrado y fllLrado de Llbros ayudndonos a asenLar los
concepLos aprendldos en el caplLulo anLerlor.

Cb[et|vos :
Anadlr la funclonalldad que nos permlLa borrar llbros.
Anadlr funclonalldad que nos permlLa edlLar llbros.
Anadlr un fllLro por caLegorlas a los llbros.
1areas:
1. Anadlr un nuevo enlace de borrar a MosLrarLlbros.[sp" .
2. Anadlr el meLodo borrar() a la clase Llbro.
3. Anadlr una nueva pglna 8orrarLlbro.[sp" que se encargue de e[ecuLar la
funclonalldad de borrar.
4. Anadlr un nuevo enlace de edlcln a MosLrarLlbros.[sp.
3. Anadlr el meLodo buscarorClave() que busque un llbro por lS8n a la clase
Llbro.
6. Anadlr una nueva pglna (lormularloLdlLarLlbro.[sp) que muesLre los daLos del
llbro que deseamos modlflcar.
7. Anadlr el meLodo salvar() a la clase llbro que guarda las modlflcaclones
reallzadas.
8. Anadlr una nueva paglna SalvarLlbro.[sp que se encargue de e[ecuLar la
funclonalldad de salvar
9. Anadlr el meLodo de buscarorCaLegorla() a la clase Llbro
!!!"#$%&'()*(&$#+#,#"*-.
67
10. Modlflcar la paglna MosLrarLlbros.[sp para que se apoye en el meLodo
buscarorCaLegorla.
1. Aad|r en|ace de borrar
ara que nuesLra apllcacln sea capaz de borrar llbros, debemos anadlr un nuevo
enlace a la pglna MosLrarLlbros.[sp (ver cdlgo).

ara ello, neceslLamos anadlr una nueva llnea de cdlgo a MosLrarLlbros.[sp" como se
muesLra en el cdlgo.
Cdlgo 4.1: (MosLrarLlbro.[sp)
<%=libro.getIsbn()%>
<%=libro.getTitulo()%>
<%=libro.getCategoria()%>
<a href="BorrarLibro.jsp?isbn=<%=libro.getIsbn()%>">Borrar</a>
<br/>
2. Aad|r mtodo borrar
Al crear el enlace, es necesarlo anadlr un nuevo meLodo a la clase Llbro que se
encargue de borrar el reglsLro de la Labla. A conLlnuacln se muesLra el cdlgo de esLe
meLodo.


!"#$%&'(&$") +),)
68

Cdlgo 4.2: (Llbro.[ava)
public void borrar() {

String consultaSQL = "delete from Libros where isbn='"+ this.isbn+"'";
DataBaseHelper<Libro> helper = new DataBaseHelper<Libro>();
helper.modificarRegistro(consultaSQL);
}

una vez modlflcada la clase Llbro, procederemos a consLrulr la pglna 8orrarLlbro.[sp.
3. Aad|r pg|na 8orrarL|bro.[sp
La pglna que se encarga de borrar los llbros es muy sencllla, slmplemenLe obLlene el
lS8n de la peLlcln, se encarga de crear un ob[eLo llbro e lnvocar al meLodo borrar.
veamos su cdlgo fuenLe.
Cdlgo 4.3:(8orrarLlbro.[sp)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="com.arquitecturajava.Libro"%>
<%
String isbn= request.getParameter("isbn");
Libro libro= new Libro(isbn);
libro.borrar();
response.sendRedirect("MostrarLibros.jsp");
%>

1ras Lodos esLos pasos, dlspondremos de una nueva pglna en nuesLro proyecLo (ver
lmagen).

!!!"#$%&'()*(&$#+#,#"*-.
69
Con esLas prlmeras Lres Lareas complemenLamos el prlmer ob[eLlvo del caplLulo: que
nuesLra apllcacln sea capaz de borrar Llbros. A conLlnuacln se muesLra una lmagen
del flu[o enLre pglnas y clases que ayuda a clarlflcar los pasos reallzados.

Ls el momenLo de pasar a las slgulenLes Lareas que se encargaran del segundo ob[eLlvo:
la edlcln de Llbros.
4. Aad|r ||nk Ld|c|n
Como en el caso de borrar, la prlmera Larea ser la de anadlr un nuevo enlace a la
paglna MosLrarLlbros.[sp" que permlLa edlLar.
!"#$%&'(&$") +),)
70

A conLlnuacln se muesLran las modlflcaclones del cdlgo fuenLe.
Cdlgo 4.4:(MosLrarLlbro.[sp)
<%=libro.getIsbn()%>
<%=libro.getTitulo()%>
<%=libro.getCategoria()%>
<a href="BorrarLibro.jsp?isbn=<%=libro.getIsbn()%>">Borrar</a>
<a href="FormularioEditarLibro.jsp?isbn=<%=libro.getIsbn()%>">Editar</a>
<br/>

Anadldo de esLa forma el enlace, pasaremos a deflnlr la slgulenLe Larea.
S. Mtodo de bsqueda por c|ave
ara poder edlLar un reglsLro neceslLaremos prlmero selecclonarlo, para ello crearemos
un nuevo meLodo para la clase Llbro que se denomlnara buscarorC|ave(). LsLe
meLodo nos buscar un llbro a Lraves de su lS8n. A conLlnuacln se muesLra el cdlgo
fuenLe del nuevo meLodo.
Cdlgo 4.3:(Llbro.[ava)
public static Libro buscarPorClave (String isbn) {
String consultaSQL = "select isbn,titulo,categoria from Libros where
isbn='"+ isbn+"'";
DataBaseHelper<Libro> helper = new DataBaseHelper<Libro>();
List<Libro> listaDeLibros =
helper.seleccionarRegistros(consultaSQL,Libro.class);
return listaDeLibros.get(0);
}

6. Aad|r formu|ar|o de ed|c|n de cd|go.
una vez anadldo el meLodo de buscarorClave, pasaremos a anadlr una nueva pglna a
nuesLra apllcacln denomlnada lormularloLdlLarLlbro.[sp" (ver lmagen).

!!!"#$%&'()*(&$#+#,#"*-.
71
llnallzada asl esLa operacln, podremos apoyarnos en el meLodo que acabamos de
consLrulr para que la nueva pglna formularloLdlLarLlbro.[sp muesLre los daLos del
reglsLro que nos lnLeresen. veamos como quedarla:

una vez Lenemos claro que daLos debe presenLar la paglna vamos a ver su cdlgo
fuenLe.


!"#$%&'(&$") +),)
72
Cdlgo 4.6: (MosLrarLlbro.[sp)
<%@ page import="java.util.List" %>
<%@page import="com.arquitecturajava.Libro"%>
<%Libro libro= Libro.buscarPorClave(request.getParameter("isbn"));%>
<!-- cabecera y javascript omitido-->
<body>
<form id="formularioEdicion" action="SalvarLibro.jsp">
<fieldset>
<legend>Formulario alta libro</legend>
<p><label for="isbn">ISBN:</label>
<input type="text" id="isbn" name="isbn" value="<%=libro.getIsbn()%>"/></p>
<p><label for="titulo">Titulo:</label><input type="text" id="titulo" name="titulo"
value="<%=libro.getTitulo() %>" /></p>
<p><label for="categoria">Categoria :</label>
<select name="categoria">
<%
List<String> listaDeCategorias=null;
listaDeCategorias=Libro.buscarTodasLasCategorias();
for(String categoria:listaDeCategorias) {

if (libro.getCategoria().equals(categoria)) { %>
<option value="<%=categoria%>" selected="selected">
<%=categoria%></option>
<%}else{ %>
<option value="<%=categoria%>"><%=categoria%></option>
<% }
} %>
</select>
<br/>
</p>
<p><input type="submit" value="Salvar" /></p>
</fieldset>
</form>
</body>
</html>

Como vemos, el cdlgo es ldenLlco al formularlo de lnserLar con el que hemos
Lraba[ado en caplLulos anLerlores, con la unlca salvedad del slgulenLe bloque de cdlgo.
Cdlgo4.7: (MosLrarLlbro.[sp)
Libro libro=Libro.buscarPorClave(request.getParameter(isbn)

LsLa llnea es la encargada de buscarnos el llbro que deseamos edlLar y guardarlo en la
varlable llbro". una vez dlsponemos de los daLos del llbro slmplemenLe los mosLramos
!!!"#$%&'()*(&$#+#,#"*-.
73
a Lraves de las eLlqueLas <lnpuL> y <selecL> usando scrlpLleL de [sp a la hora de aslgnar
la propledad value, como muesLra el slgulenLe bloque de cdlgo.
Cdlgo 4.8: (MosLrarLlbro.[sp)
<input type="text" id="isbn" name="isbn" value="<%=libro.getIsbn()%>"/></p>

7. Aad|r mtodo sa|var
una vez que hemos consLruldo esLe formularlo, podemos modlflcar los daLos del llbro
que prevlamenLe hemos selecclonado. 8eallzados esLos camblos, es necesarlo
guardarlos en la base de daLos. ara ello anadlremos a la clase Llbro el slgulenLe
meLodo:
Cdlgo4. 9: (Llbro.[ava)
public void salvar() {
String consultaSQL = "update Libros set titulo='"+ this.titulo+"',
categoria='"+ categoria+"' where isbn='"+ isbn+"'";
DataBaseHelper<Libro> helper = new DataBaseHelper<Libro>();
helper.modificarRegistro(consultaSQL);
}

or ulLlmo, es preclso llgar el meLodo salvar con el formularlo de edlcln que acabamos
de consLrulr. La slgulenLe Larea abordara esLo.

8. Aad|r pag|na Sa|varL|bro.[sp
ara llgar el formularlo y el meLodo salvar anadlremos una nueva pglna a la apllcacln
denomlnada SalvarLlbro.[sp (ver lmagen).
!"#$%&'(&$") +),)
74

A conLlnuacln se muesLra el cdlgo fuenLe de esLa pglna
Cdlgo 4.9: (SalvarLlbro.[sp)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="com.arquitecturajava.Libro"%>
<% String isbn= request.getParameter("isbn");
String titulo= request.getParameter("titulo");
String categoria= request.getParameter("categoria");
Libro libro= new Libro(isbn,titulo,categoria);
libro.salvar();
response.sendRedirect("MostrarLibros.jsp");%>

una vez consLruldos Lodos los meLodos, vamos a ver una lmagen flnal aclaraLorla.
!!!"#$%&'()*(&$#+#,#"*-.
75


9. Aad|r mtodo buscarorCategor|a.
vamos a dar un ulLlmo paso y anadlr la funclonalldad de fllLro por caLegorla a nuesLra
apllcacln. ara ello, lo prlmero que debemos hacer es anadlr un nuevo meLodo a la
clase Llbro que nos devuelva a una llsLa de llbros para una caLegorla concreLa. vamos a
ver el cdlgo fuenLe de esLe meLodo .
Cdlgo 4.10: (Llbro.[ava)
public static List<Libro> buscarPorCategoria (String categoria) {
String consultaSQL = "select isbn,titulo,categoria from Libros where
categoria='"+ categoria+"'";
DataBaseHelper<Libro> helper = new DataBaseHelper<Libro>();
List<Libro> listaDeLibros = helper.
seleccionarRegistros(consultaSQL,Libro.class);
return listaDeLibros;
}
}
!"#$%&'(&$") +),)
76
una vez consLruldo esLe nuevo meLodo, hay que modlflcar la pglna MosLrarLlbros.[sp
para que pueda lnvocarlo. ara ello anadlremos a esLa pglna un nuevo boLn de
fllLrado(ver lmagen).

vamos a mosLrar a conLlnuacln el nuevo cdlgo de la pglna MosLrarLlbros.[sp
orlenLado a las modlflcaclones suscepLlbles de reallzarse a nlvel del fllLro.
Cdlgo 4.11: (MosLrarLlbro.[sp)
List<Libro> listaDeLibros=null;
if (request.getParameter("categoria")==null ||
request.getParameter("categoria").equals("seleccionar")) {
listaDeLibros=Libro.buscarTodos();
}
else {
listaDeLibros=Libro.
buscarPorCategoria(request.getParameter("categoria"));

}
for(Libro libro:listaDeLibros){ %>
<%=libro.getIsbn()%>
<%=libro.getTitulo()%>
<%=libro.getCategoria()%>
<a href="BorrarLibro.jsp?isbn=<%=libro.getIsbn()%>">Borrar</a>
<a href="FormularioEditarLibro.jsp?isbn=<%=libro.getIsbn()%>
Editar</a>
<br/>
<% }
%>

!!!"#$%&'()*(&$#+#,#"*-.
77

Ln esLa caso la operacln no es muy compllcada y slmplemenLe selecclona el meLodo
buscar1odos() o buscarorCaLegorla(), dependlendo de sl pasamos parmeLros o no. A
conLlnuacln se muesLra una lmagen aclaraLorla de la llgazn exlsLenLe enLre la paglna
[sp y las dlsLlnLas clases que hemos consLruldo.


Llegados a esLe punLo, hemos Lermlnado el ulLlmo ob[eLlvo del caplLulo. A conLlnuacln
se muesLra el cdlgo fuenLe de la clase Llbro que se ha vlsLo suceslvamenLe modlflcada.






!"#$%&'(&$") +),)
78
Cdlgo 4.12: (Llbro.[ava)
package com.arquitecturajava;
import java.util.List;
public class Libro {
private String isbn;
private String titulo;
private String categoria;
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitulo() {
return titulo;
}

public void setTitulo(String titulo) {
this.titulo = titulo;
}

public String getCategoria() {
return categoria;
}

public void setCategoria(String categoria) {
this.categoria = categoria;
}
public Libro(String isbn) {
super();
this.isbn = isbn;
}
public Libro() {
super();
}
public Libro(String isbn, String titulo, String categoria) {
super();
this.isbn = isbn;
this.titulo = titulo;
this.categoria = categoria;
}
public static List<String> buscarTodasLasCategorias() {
String consultaSQL = "select distinct(categoria) as categoria from
Libros";
DataBaseHelper<String> helper = new DataBaseHelper<String>();
List<String> listaDeCategorias = helper.seleccionarRegistros(
consultaSQL, String.class);
return listaDeCategorias;
}
!!!"#$%&'()*(&$#+#,#"*-.
79
public void insertar() {

String consultaSQL = "insert into Libros (isbn,titulo,categoria) values ";
consultaSQL += "('" + this.isbn + "','" + this.titulo + "','"
+ this.categoria + "')";
DataBaseHelper<Libro> helper = new DataBaseHelper<Libro>();
helper.modificarRegistro(consultaSQL);
}
public void borrar() {

String consultaSQL = "delete from Libros where isbn='" + this.isbn
+ "'";
DataBaseHelper<Libro> helper = new DataBaseHelper<Libro>();
helper.modificarRegistro(consultaSQL);
}
public void salvar() {

String consultaSQL = "update Libros set titulo='" + this.titulo
+ "', categoria='" + categoria + "' where isbn='" + isbn + "'";
DataBaseHelper<Libro> helper = new DataBaseHelper<Libro>();
helper.modificarRegistro(consultaSQL);
}
public static List<Libro> buscarTodos() {

String consultaSQL = "select isbn,titulo,categoria from Libros";
DataBaseHelper<Libro> helper = new DataBaseHelper<Libro>();
List<Libro> listaDeLibros = helper.seleccionarRegistros(consultaSQL,
Libro.class);
return listaDeLibros;
}
public static Libro buscarPorClave(String isbn) {
String consultaSQL = "select isbn,titulo,categoria from Libros where
isbn='"+ isbn + "'";
DataBaseHelper<Libro> helper = new DataBaseHelper<Libro>();
List<Libro> listaDeLibros = helper.seleccionarRegistros(consultaSQL,
Libro.class);
return listaDeLibros.get(0);
}
public static List<Libro> buscarPorCategoria(String categoria) {

String consultaSQL = "select isbn,titulo,categoria from Libros where
categoria='"+ categoria + "'";
DataBaseHelper<Libro> helper = new DataBaseHelper<Libro>();
List<Libro> listaDeLibros = helper.seleccionarRegistros(consultaSQL,
Libro.class);
return listaDeLibros;
}
}
!"#$%&'(&$") +),)
80
!"#$%"&
Ln esLe caplLulo hemos aflanzado concepLos mlenLras anadlamos dlsLlnLas
funclonalldades a nuesLra apllcacln. Con ello hemos conseguldo una clase Llbro que se
encarga de reallzar Lodas las consulLas SCL que la 1abla Llbros neceslLa. A esLas clases
que mapean Lodas las operaclones sobre una Labla concreLa se las denomlna clases
AcLlve8ecord, ya que lmplemenLan el paLrn AcLlve 8ecord (deflnldo en !"##$%&' )*
+&#$%,%-'$ .,,/-0"#-)& .%01-#$0#2%$, de MarLln lowler) . La conclusln de esLe caplLulo
y del anLerlor es que apllcar prlnclplos de lngenlerla de sofLware como el prlnclplo u8?
suele llevar a dlsenos basados en paLrones.


!!!"#$%&'()*(&$#+#,#"*-.
81

!"#$%&'(&$") +),)
82
!"!"#$%& ($ $)*$+*,&#$-





Ln el caplLulo anLerlor hemos anadldo funclonalldad a la apllcacln y consLruldo una
clase Llbro que cumple con el paLrn AcLlve8ecord. A parLlr de esLe caplLulo no
anadlremos mucha ms funclonalldad slno que nos cenLraremos en lr apllcando
dlsLlnLos refacLorlngs que permlLan un me[or comporLamlenLo de la apllcacln. Ln esLe
caplLulo nos encargaremos de me[orar la gesLln de excepclones .
Cb[et|vos:
Slmpllflcar el mane[o de excepclones de la apllcacln
Tareas:
1. 8evlsln de el flu[o de excepclones y uso de la clausulas Lry/caLch.
2. Mane[o de la clusula Lhrow , Lhrows y flu[o de excepclones.
3. Creacln y conversln de excepclones.
4. AnldamlenLo de excepclones.
3. Lxcepclones de 1lpo 8un1lme.
6. Creacln de una pglna [sp de error.
7. Modlflcacln del flchero web.xml.








!!!"#$%&'()*(&$#+#,#"*-.
83
1. !"#$% '( ()*(+*,%-(. / *"0#.#"0. *01*2

Como punLo de parLlda, vamos a anallzar cmo se gesLlonan las excepclones en la
apllcacln en esLos momenLos. ara ello, nos vamos a apoyar en los slgulenLes flcheros.
Clase uaLa8asePelper
Clase Llbro
MosLrarLlbros.[sp
Sl revlsamos el cdlgo de mane[o de excepclones que Llene la clase uaLa8asePelper,
veremos que se encarga de capLurar Lodas las excepclones que se producen usando
clausulas Lry/caLch e lmprlmlendo los errores por la consola (ver lmagen).

Aunque esLa gesLln en un prlmer momenLo pueda parecernos correcLa, presenLa un
problema: al capLurar Lodos los mensa[es de error, esLos nunca llegan a las paglnas !S
y por lo LanLo, un usuarlo hablLual de la apllcacln no reclblr nlngun mensa[e por
muchos errores que se produzcan (ver lmagen).
!"#$%&'(&$") +),)
84

Sl los usuarlos no reclben nlngun mensa[e de error, no podrn avlsar a los
desarrolladores de los problemas que la apllcacln les presenLa, a lo sumo, podrn
lndlcar que la apllcacln no reallza una funclonalldad cualqulera, pero no nos podrn
aporLar ms lnformacln. Sl deseamos que los usuarlos puedan aporLarnos lnformacln
adlclonal, es necesarlo que reclban unos mensa[es de error claros. La slgulenLe Larea
aborda esLa problemLlca.

2. !"#$%& ($ )"* !"#$%&"#% !"#$%& !"#$%& ( !"#$% !" "$%"&%'()"*+
ara consegulr que los usuarlos puedan reclblr lnformacln sobre los errores de la
apllcacln es esenclal reallzar las slgulenLes modlflcaclones.
1. Ln la clase uaLa8asePelper una vez capLurada la excepcln y reallzado log del
mensa[e de error, volveremos a lanzar las mlsmas excepclones uLlllzando la
clausula throw.
2. Ln la clase Llbro modlflcaremos la flrma de cada mtodo para que no capLure
nlnguna excepcln y esLas puedan flulr hasLa las paglnas !S.
3. Ln cada una de las paglnas !S anadlremos clausulas Lry/caLch para capLurar las
excepclones.
!!!"#$%&'()*(&$#+#,#"*-.
85
A conLlnuacln se muesLra cmo queda el meLodo modlflcar8eglsLro de la clase
uaLa8asePelper una vez apllcados los camblos .Ll resLo de meLodos ser slmllar.
Cdlgo 3.1: (uaLa8asePelper.[ava)
public int modificarRegistro(String consultaSQL) throws ClassNotFoundException,
SQLException {
try {
!......................
} catch (SQLException e) {
System.out.println("Error de SQL" + e.getMessage());
throw e;
}
!..............

8eallzado el prlmer camblo, podemos ver cmo la clusula Lhrow relanza la excepcln y
cmo la clausula Lhrows deflne que con[unLo de excepclones esL soporLada. uel
mlsmo modo que hemos modlflcado la clase uaLa8asePelper modlflcaremos a
conLlnuacln los meLodos de la clase Llbro. Los cules unlcamenLe marcan el meLodo
con las excepclones que puede produclr.
Cdlgo 3.2: (Llbro.[ava)
public void insertar() throws ClassNotFoundException, SQLException {
!...........
}

Ll ulLlmo paso es modlflcar nuesLra pglna !S de lnsercln y capLurar las excepclones
con un bloque Lry/caLch .
Cdlgo3.3: (MosLrarLlbro.[sp)
try {
LibroAR libro = new LibroAR(isbn, titulo, categoria);
libro.insertar();
} catch (Exception e) {%>
<%=e.getMessage()%>
<%}%>

A conLlnuacln se muesLra un dlagrama aclaraLorlo de cmo Lodos esLos camblos
Lraba[an unldos para consegulr que los mensa[es de error lleguen al usuarlo.
!"#$%&'(&$") +),)
86

3. !"#$%&'( * %+(,#"-&'( .# #/%#0%&+(#-
Pemos avanzado en nuesLra gesLln de excepclones y ahora los usuarlos reclben
lnformacln sobre los errores que se producen. Sln embargo, sl revlsamos la flrma del
nuevo meLodo lnserLar de la clase Llbro, nos enconLraremos con lo slgulenLe.
Cdlgo 3.4: (Llbro.[ava)
public void insertar() throws ClassNotFoundException, SQLException

Como podemos ver, la clusula Lhrows lanza varlos Llpos de excepclones. LsLas
clusulas se repeLlrn meLodo Lras meLodo por Lodo nuesLro cdlgo y en algunos casos
sern ms comple[as, por e[emplo en el meLodo buscar1odos:

!!!"#$%&'()*(&$#+#,#"*-.
87
Cdlgo 3.3: (Llbro.[ava)
public static List<Libro> buscarTodos() throws ClassNotFoundException, SQLException,
InstantiationException, IllegalAccessException, InvocationTargetException {
}

ara evlLar esLe problema y slmpllflcar el mane[o de compllcados con[unLos de
excepclones, consLrulremos para nuesLra apllcacln una nueva excepcln denomlnada
uaLa8aseLxcepLlon". A conLlnuacln mosLramos el dlagrama uML que nos permlLe ver
de que clase hereda, asl como su cdlgo fuenLe.
Cdlgo3.6: (uaLa8aseLxcepLlon.[ava)
package com.arquitecturajava;
public class DataBaseException extends Exception {
private static final long serialVersionUID = 1L;
public DataBaseException() {
super();
}
public DataBaseException(String message, Throwable cause) {
super(message, cause);
}
public DataBaseException(String message) {
super(message);
}
public DataBaseException(Throwable cause) {
super(cause);
}}

una vez creada esLa nueva excepcln, modlflcaremos el cdlgo fuenLe de nuesLra clase
uaLa8asePelper para que convlerLa Lodas las excepclones que produce !u8C a nuesLro
nuevo Llpo de excepcln (ver lmagen).

!"#$%&'(&$") +),)
88

A conLlnuacln se muesLra el cdlgo fuenLe modlflcado de uno de los meLodos de la
clase uaLa8asePelper.
Cdlgo 3.7: (uaLa8asePelper.[ava)
public int modificarRegistro(String consultaSQL) throws DataBaseException {
Connection conexion = null;
Statement sentencia = null;
int filasAfectadas = 0;
try {
Class.forName(DRIVER);
conexion = DriverManager.getConnection(URL, USUARIO,
CLAVE);
sentencia = conexion.createStatement();
filasAfectadas = sentencia.executeUpdate(consultaSQL);
} catch (ClassNotFoundException e) {
System.out.println("Clase no encontrada" + e.getMessage());
throw new DataBaseException("Clase no encontrada");
} catch (SQLException e) {
System.out.println("Error de SQL" + e.getMessage());
throw new DataBaseException("Error de SQL");
} finally {
if (sentencia != null) {
try {sentencia.close();} catch (SQLException e) {
}
if (conexion != null) {
try {conexion.close();} catch (SQLException e) {}
}
}
return filasAfectadas;
}
!!!"#$%&'()*(&$#+#,#"*-.
89
una vez reallzadas esLas modlflcaclones, los flcheros !S slmplemenLe reallzaran una
capLura sencllla (ver cdlgo).
Cdlgo 3.8: (lnserLarLlbro.[sp)
<% try {
String isbn= request.getParameter("isbn");
String titulo= request.getParameter("titulo");
String categoria= request.getParameter("categoria");
Libro libro= new Libro(isbn,titulo,categoria);
libro.insertar();
response.sendRedirect("MostrarLibros.jsp");
} catch (DataBaseException e) {
out.println(e.getMessage());
}
%>

A conLlnuacln se muesLra la lmagen que agluLlna los ulLlmos camblos.

!"#$%&'(&$") +),)
90
4. !"#$%#&'($) +(&,+,+)

1ras consegulr homogenelzar la gesLln de excepclones creando nuesLra nueva clase
uaLa8aseLxcepLlon, nos damos cuenLa que cuando se produce un error reclblmos el
mensa[e de Lrror de SCL" (ver lmagen).
Sln embargo, aunque aparece el mensa[e de error no es el mensa[e de error orlglnal
que se produ[o. LsLo se debe a que hemos consLruldo nuevas excepclones
subsLlLuyendo las excepclones orlglnales por esLas , perdlendo asl los mensa[es de error
orlglnales del apl de [ava . ue esLa forma se compllca sobremanera saber cul es el
error real que nuesLra apllcacln ha producldo. ara poder acceder a la lnformacln
orlglnal del error, debemos redlsenar nuesLro slsLema de excepclones para que soporLe
excepclones anldadas . LsLe Llpo de excepclones es capaz de mosLrar su mensa[e de
error, asl como el mensa[e de error orlglnal que las apls de [ava produ[eron (ver cdlgo)
Cdlgo 3.9: (uaLa8asePelper.[ava)

} catch (ClassNotFoundException e) {
System.out.println("Error de acceso al driver" + e.getMessage());
throw new DataBaseException("Error de SQL",e);
}

A conLlnuacln se muesLra un dlagrama que conLlene una excepcln de Llpo
uaLa8aseLxcepLlon la cul Llene anldada una excepcln de SCL para ayudar a clarlflcar.
!!!"#$%&'()*(&$#+#,#"*-.
91


una vez reallzado esLe camblo, es necesarlo reallzar una modlflcacln en el flchero !S
que se encarga de capLurar las excepclones que provlenen de la capa de negoclo, ya
que debemos obLener la lnformacln de la excepcln orlglnal que se produ[o.



!"#$%&'(&$") +),)
92
Cdlgo3.10: (lnserLarLlbro.[sp)

try {
LibroAR libro = new LibroAR(isbn, titulo, categoria);
libro.insertar();
} catch (DataBaseException e) {%>
<%=e.getMessage()%>
<%=e.getException().getMessage()%>
<%}%>


Las excepclones anldadas nos han ayudado a guardar la lnformacln orlglnal de los
errores (ver lmagen).


S. !"#$%#&'($) +,(-&.$
Cueremos avanzar en la slmpllflcacln del mane[o de excepclones, para ello
modlflcaremos nuesLra clase uaLa8aseLxcepLlon para que, en vez de que su clase padre
sea la clase Lxcepcln, lo sea la clase 8un1lmeLxcepLlon (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
93
Al hacerlo de esLa manera, podremos ellmlnar Lodas las clusulas Lhrows de nuesLras
clases ya que esLe Llpo de excepclones [ava no obllga a capLurarlas y pueden flulr
llbremenLe por Lodo el cdlgo como muesLra la flgura.
!"#$%&'(&$") +),)
94
una vez reallzado esLe camblo, los meLodos de nuesLras clases quedarn deflnldos de
la slgulenLe forma:
Cdlgo3.11: (uaLa8asePelper.[sp)
public int modificarRegistro(String consultaSQL) // no hay excepciones
public void insertar() //no hay excepciones

6. !"#$" &$'()$ *# +"","
arece que hemos Lermlnado, sln embargo sl revlsamos el esLado de nuesLras pglnas
!S respecLo a la capLura de excepclones, nos daremos cuenLa de que Lodas las paglnas
conLlenen el mlsmo bloque Lry/caLch (ver lmagen).

!!!"#$%&'()*(&$#+#,#"*-.
95
LsLe es oLro caso Llplco de repeLlcln de cdlgo, donde podemos hacer uso del prlnclplo
u8? para exLraer la responsabllldad de la gesLln de errores de la pglna !S y
cenLrallzarla en oLra nueva pglna denomlnada pglna de error, la cul se encargar de
gesLlonar los errores (ver lmagen).

vamos a ver a conLlnuacln el cdlgo fuenLe de esLa pglna que Llene como
pecullarldad el usar a nlvel de dlrecLlva [page del aLrlbuLo lsLrrorage que la ldenLlflca
como paglna de error.
Cdlgo 3.12: (Lrror.[sp)
<%@ page isErrorPage="true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title></head>
<body>
Ha ocurrido un error en la aplicacion :<%=exception.getMessage()%>
Error Interno:<%=exception.getCause().getMessage()%>
</body></html>
!"#$%&'(&$") +),)
96
una vez creada la pglna !S, debemos conflgurar nuesLra apllcacln web para que se
apoye en esLa nueva pglna de error. ara ello, modlflcaremos el flchero web.xml.
7. !"!"#"$%& #"$()&* +),-./0
Ll flchero web.xml es el flchero de conflguracln de Loda apllcacln web [ava y se
encuenLra ublcado en la carpeLa WL8-lnl . A conLlnuacln se muesLra el bloque de
cdlgo que anadlremos a esLe para dar de alLa correcLamenLe la pglna de error en la
apllcacln.
Cdlgo 3.13: (web.xml)
<web-app>
<error-page>
<exception-type>java.lang.RuntimeException</exception-type>
<location>/Error.jsp</location>
</error-page>
!.............
</web-app>

8eallzada esLa operacln, las paglnas ya no conLendrn bloques Lry/caLch (ver cdlgo)
Cdlgo3.14: (lnserLarLlbro.[sp)
<%
String isbn = request.getParameter("isbn");
String titulo = request.getParameter("titulo");
String categoria = request.getParameter("categoria");
LibroAR libro = new LibroAR(isbn, titulo, categoria);
libro.insertar();
response.sendRedirect("ListaLibros.jsp");
%>

Modlflcado el flchero web.xml y las pglnas [sp, Lodas delegan ahora en la pglna de
error.[sp a la hora de gesLlonar los dlsLlnLos errores, cumpllendo con el prlnclplo u8?
(ver lmagen).



!!!"#$%&'()*(&$#+#,#"*-.
97

!"#$%"&
Ln esLe caplLulo nos hemos cenLrado en slmpllflcar el mane[o de excepclones de la
apllcacln, para lo cul hemos reallzado basLanLes camblos, enLre los que desLacan:
1. uso de excepclones de Llpo 8un1lmeLxcepLlon para slmpllflcar el flu[o de
excepclones de la apllcacln.
2. uso del prlnclplo u8? y consLruccln de una paglna de Lrror para cenLrallzar la
gesLln de excepclones.

!"#$%&'(&$") +),)
98
!!"#$%&






Ln el caplLulo anLerlor nos hemos encargado de slmpllflcar la gesLln de excepclones de
nuesLra apllcacln. Sln embargo, slempre llgado a la gesLln de excepclones se
encuenLra la gesLln de los flcheros de log . PasLa esLe momenLo no hemos LraLado el
caso a fondo y nos hemos llmlLado lmprlmlr mensa[es por la consola con bloques de
cdlgo del slgulenLe esLllo.
Cdlgo 6.1: (uaLa8asePelper.[sp)
System.out.println(e.getMessage())

Ls evldenLe que esLa forma de Lraba[ar no es la adecuada cuando se LraLa de
apllcaclones reales. Asl pues, en esLe caplLulo nos encargaremos de lnLroduclr un Al
de log y modlflcaremos nuesLra apllcacln para que haga uso de ella . Ln nuesLro caso
vamos a usar log4[ que es un sLandard de facLo en la plaLaforma !ava. ue esLa manera,
los ob[eLlvos del caplLulo sern:
Cb[et|vos:
lnLroduccln y mane[o de log4[
AcLuallzacln de la apllcacln para que use log4[.
1areas:
1. lnsLalacln del apl de log4[.
2. lnLroduccln del apl de log4[.
3. ConsLruccln de un e[emplo senclllo.
4. Mensa[es de error y nlveles.
!!!"#$%&'()*(&$#+#,#"*-.
99
3. Mane[o de Log4.properLles.
6. lnLegracln de log4[ en la apllcacln.

1. !"#$%&%'()" +, &-./0
ara poder Lraba[ar con el apl de log4[ debemos obLener el producLo de la web
descargndolo de la slgulenLe url.
hLLp://www.apache.org/dyn/closer.cgl/logglng/log4[/1.2.16/apache-log4[-
1.2.16.Lar.gz
una vez obLenldo crearemos un nuevo proyecLo Iava (No [ava Web) en el ecllpse, ya
que lo prlmero que vamos a hacer es un con[unLo de e[emplos senclllos para lnLroduclr
al lecLor a esLe apl. A conLlnuacln se muesLra una lmagen del proyecLo.

una vez creado el proyecLo, anadlremos una carpeLa ||b a esLe y ublcaremos en ella el
flchero |og4[-1.2.16.[ar . Ll cual obLenemos del paqueLe Lar.gz que acabamos de ba[ar .
ublcado el flchero en la carpeLa, lo mapeamos como se muesLra en la flgura.


!"#$%&'(&$") +),)
100

8eallzada esLa operacln, unlcamenLe deberemos referenclar la llbrerla en nuesLro
proyecLo para Lenerla a nuesLra dlsposlcln. ara ello, accederemos a las propledades
del proyecLo y en el aparLado de [ava bulld paLh mapearemos la llbrerla (ver lmagen).
una vez lnsLalada la llbrerla, podemos comenzar a uLlllzarla. La slgulenLe Larea nos
lnLroduclr en ella.
2. !"#$%&'(()*" , -%./0
Ll Al de log4[ no es compllcada de mane[ar pero sl que es en muchos casos poco
conoclda por parLe de los desarrolladores. A conLlnuacln reallzaremos una
lnLroduccln a sus concepLos prlnclpales.
Sl nos pregunLamos cmo funclona un slsLema de log mucha genLe nos responder con
algo como lo slgulenLe: un slsLema de log genera mensa[es con un formaLo
deLermlnado y los almacena en una ublcacln para posLerlor anllsls .La slgulenLe
lmagen muesLra la ldea a nlvel concepLual.
!!!"#$%&'()*(&$#+#,#"*-.
101
Ln el caso del apl de log4[ la esLrucLura es muy slmllar y esL compuesLa por el slgulenLe
dlagrama de clases, que slrve para paralellzar los concepLos anLerlores.

vamos a comenLar a conLlnuacln cada una de esLas clases.
Str|ng : Clase del Al de !SL que represenLa el concepLo de mensa[e (o cadena)
a nlvel del Al de log4[.
Layout : Clase del Al de log4[ que se encarga de selecclonar el formaLo en el
cul los mensa[es son lmpresos.
Appender: Clase del Al de log4[ que hace referencla al recurso en el cul los
mensa[es de error han de ser escrlLos (Consola, llchero,8ase de uaLos eLc.). Se
apoyar en la clase LayouL para aslgnar un formaLo a los mensa[es
Logger: Clase del Al de log4[ que se encarga de la gesLln de los mensa[es de
error y los lmprlme al appender o appenders que se le hayan aslgnado,
uLlllzando el formaLo que se deflna en el LayouL.
Aunque las deflnlclones son senclllas, no hay nada me[or que un e[emplo concreLo de
cdlgo para clarlflcar como funclona Log4[ .
3. !"#$%&'(()*# ,- '# -.-/01" $-#()11"
vamos a consLrulr un e[emplo elemenLal de uso de log4[. ara ello hemos consLruldo el
slgulenLe bloque de cdlgo que hace un uso del apl y que pasaremos a anallzar.
!"#$%&'(&$") +),)
102
Cdlgo6.2: (Log2usandoLog.[ava)
package com.arquitecturajava.logs;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
public class log02UsandoLog {
public static void main(String[] args) {
PatternLayout patron= new PatternLayout("%m %n");
ConsoleAppender consola= new ConsoleAppender(patron);
Logger log= Logger.getLogger("milog");
log.addAppender(consola);
log.info("realizando un log sencillo");
}
}

una vez consLruldo el cdlgo vamos a ver que resulLado muesLra su e[ecucln
Como podemos ver, lmprlme una llnea de LexLo por la consola. vamos a conLlnuacln a
anallzar cada una de las llneas de nuesLro cdlgo.
Cdlgo 6.3: (Log2usandoLog.[ava)
PatternLayout patron= new PatternLayout("%m %n");

LsLa clase deflne el formaLo en el cul el mensa[e ha de ser lmpreso. A conLlnuacln, se
expllcan cada uno de los elemenLos o paLrones que se han uLlllzado.
m :Cbllga a que se lmprlma el LexLo del mensa[e
n : Cbllga a que cada vez que se lmprlma un mensa[e haya un reLorno de
carro y se salLe de llnea

!!!"#$%&'()*(&$#+#,#"*-.
103
una vez deflnldo el Llpo de layouL, es momenLo de consLrulr el appender o recurso en
el que se van a lmprlmlr los dlsLlnLos mensa[es de error , el appender reclblr un layouL
como parmeLro.
Cdlgo6.4: (Log2usandoLog.[ava)
ConsoleAppender consola= new ConsoleAppender(patron);

Ln esLe caso hemos consLruldo el appender ms senclllo que lmprlme los mensa[es a la
consola cumpllendo con el paLron especlflcado. Ll slgulenLe paso ser la creacln de un
Logger u ob[eLo de log que se encarga de gesLlonar esLos mensa[es. LsLe logger debe
Lener un nombre (mllog").
Cdlgo 6. 3: (Log2usandoLog.[ava)
Logger log= Logger.getLogger("milog");

una vez creado el ob[eLo de log, es necesarlo aslgnarle el appender al cul va a escrlblr
en esLe caso la consola.
Cdlgo 6.6: (Log2usandoLog.[ava)
log.addAppender(consola);

or ulLlmo, unlcamenLe nos queda lnvocar al ob[eLo de log y mandarle lmprlmlr un
mensa[e a Lraves del meLodo lnfo, que ms adelanLe expllcaremos deLalladamenLe.
Cdlgo 6.7: (Log2usandoLog.[ava)
log.info("realizando un log sencillo");

Ll resulLado de Lodo esLe bloque de cdlgo es que, al e[ecuLar el programa, se
lmprlmlr un mensa[e por la consola (ver lmagen).
!"#$%&'(&$") +),)
104

LsLe senclllo e[emplo nos ha servldo para lnLroduclr el funclonamlenLo del apl de log4[
Ahora segulremos avanzando y haremos especlal hlncaple en los nlveles de mensa[es
de error.
4. !"#$%&"$ (" "))*) + #,-"."$/
Acabamos de ver que el ob[eLo de log se encarga de escrlblr un mensa[e en la consola
con el slgulenLe cdlgo.
Cdlgo 6.8: (Log2usandoLog.[ava)
log.info("realizando un log sencillo");

Sln embargo, no queda muy claro por que el meLodo se denomlna lnfo y no por
e[emplo message(), ya que slmplemenLe lmprlme un mensa[e . LsLo se debe a que el apl
de log4[ soporLa varlos nlveles de lmpresln de mensa[e, dependlendo de sl es un
mensa[e sln lmporLancla o es un mensa[e crlLlco para la apllcacln. A conLlnuacln se
muesLra los dlsLlnLos nlveles de mensa[e soporLados y su uso.
Logger.faLal() lmprlme lnformacln de errores que hacen fallar
compleLamenLe a la apllcacln.
Logger.error() lmprlme lnformacln sobre errores que ha generado
la apllcacln pero no son faLales.
Logger.warn() lmprlme lnformacln sobre slLuaclones aLlplcas en la
apllcacln.
Logger.lnfo() lmprlme lnformacln sobre el flu[o de la apllcacln.
Logger.debug() Almacena lnformacln lmporLanLe a nlvel de debug
de la apllcacln

!!!"#$%&'()*(&$#+#,#"*-.
105
una vez que Lenemos claros los dlsLlnLos Llpos de mensa[e que una apllcacln puede
lmprlmlr apoyndose en el apl de log4[ ,vamos a crear un nuevo e[emplo con el
slgulenLe bloque de cdlgo.
Cdlgo 6.9: (Log2nlveles.[ava)
public class Log02Niveles {
public static void main(String[] args) {
PatternLayout patron = new PatternLayout("%m %n");
ConsoleAppender consola = new ConsoleAppender(patron);
Logger log = Logger.getLogger("milog");
log.addAppender(consola);
log.fatal("realizando un log sencillo nivel FATAL");
log.error("realizando un log sencillo nivel ERROR");
log.warn("realizando un log sencillo nivel WARN");
log.info("realizando un log sencillo nivel INFO");
log.debug("realizando un log sencillo nivel DEBUG");
}
}

8eallzada esLa operacln, sl e[ecuLamos el programa, podremos ver por consola el
slgulenLe resulLado:

1odos los mensa[es de error se han lmprlmldo de forma correcLa. Ahora blen, algo que
no hemos comenLado al lnLroduclr el apl de log4[ es que esLos mensa[es se encuenLran
relaclonados de forma [errqulca (ver lmagen).

!"#$%&'(&$") +),)
106

ue manera que se puede conflgurar el slsLema de log para que slo se lmprlman por la
consola los mensa[es que perLenezcan a un elemenLo de la [erarqula o superlor. vamos
a anadlr el slgulenLe bloque de cdlgo a nuesLro programa.
Cdlgo6.11: (Log2nlveles.[ava)
logger.setLevel(Level.WARN);

Con esLe cdlgo solo sern lmpresos los de nlvel WA8n o superlores (ver lmagen)

LsLo nos permlLlr deflnlr en nuesLro cdlgo que mensa[es y con que nlveles se aslgnan.
SeguldamenLe se muesLra una funcln de e[emplo y algunos usos de los dlsLlnLos
nlveles de log.

!!!"#$%&'()*(&$#+#,#"*-.
107
Cdlgo6.12: (Log2nlveles.[ava)
public static double calcularImporte(double importe) {
Logger log = crearLog();
log.info("entramos en la funcion");
if (importe < 0) {
log.warn("el importe no puede ser negativo");
throw new RuntimeException("operacion no soportada con el
importe");
} else {
if (importe > 0 && importe < 100) {
log.info("compra con el 10 % de descuento");
return importe * 0.90;
} else {
log.info("compra con el 20% de descuento");
return importe * 0.80;
}
}
log.debug(el importe calculado es :+ importe);
}

Ls basLanLe probable que, cuando esLemos desarrollando el programa, deseemos que
el nlvel de log se encuenLre en modo uL8uC de Lal forma que ayude a los
desarrolladores a solvenLar cualquler Llpo de problema a Lraves de sus Lrazas de
mensa[e. Ahora blen, cuando el slsLema se encuenLre en produccln, preferlremos que
slo se almacenen Lrazas de errores crlLlcos y modlflcaremos el nlvel de Lraza de log a
error.
PasLa esLe momenLo hemos uLlllzado el Al de Log4! a nlvel de nuesLro cdlgo LanLo
para reallzar las Lareas de log como para conflgurar el log en sl .Ln los enLornos reales
esLa conflguracln de log donde uno aslgna el formaLo del mensa[e, los appenders y en
nlvel de log no se reallza a nlvel de cdlgo, slno que se uLlllza un flchero de propledades
senclllo denomlnado Log4[.properLles. Ln la slgulenLe Larea se aborda el mane[o de esLe
flchero.
S. !"#$%& !" $%&'()*+%*"+,-".

una vez que hemos enLendldo como funclona el apl de log4[ es mucho ms senclllo
hablar del flchero log4[.properLles, que es el encargado de aslgnar los nlveles de log
,appenders y layouLs en una apllcacln real de Lal forma que esLa conflguracln pueda
ser modlflcada por un admlnlsLrador sln Lener que Locar el cdlgo de la apllcacln
vamos a examlnar deLalladamenLe el slgulenLe flchero log4[.properLles, que usaremos
en nuesLra apllcacln.
!"#$%&'(&$") +),)
108
Cdlgo 6.13: (log4[.properLles)
log4j.rootLogger = DEBUG, AppenderDeConsola
log4j.appender.AppenderDeConsola=org.apache.log4j.ConsoleAppender
log4j.appender.miAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.miAppender.layout.conversionPattern=%m%n

Ln esLe punLo ya es mucho mas senclllo enLender cada llnea, aun asl las vamos a lr
comenLando una por una.
Cdlgo 6.14: (log4[.properLles)
log4j.rootLogger = DEBUG, AppenderDeConsola

La prlmera llnea deflne el logger prlnclpal a nlvel de uL8uC y le aslgna un appender
denomlnado AppenderueConsola" .vamos a anallzar la slgulenLe llnea.
Cdlgo 6.13: (log4[.properLles)
log4j.appender.AppenderDeConsola=org.apache.log4j.ConsoleAppender

LsLa llnea se encarga de deflnlr que Llpo de appender usa nuesLro log. Ln esLe caso se
LraLa de un senclllo appender de consola que lmprlmlr los mensa[es por la consola de
la apllcacln. Las ulLlmas dos llneas se encargan de deflnlr el Llpo de layouL que se va a
uLlllzar (ver lmagen).
Cdlgo 6.16 (log4[.properLles)
log4j.appender.miAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.miAppender.layout.conversionPattern=%m%n

Ln nuesLro caso el LayouL es de Llpo aLLern" el cul deflne un paLrn a apllcar sobre
la esLrucLura del mensa[e . Ln esLe caso m es un paLrn que lndlca que el LexLo del
mensa[e ha de ser lmpreso y por ulLlmo n deflne que una vez lmpreso el LexLo del
mensa[e, se lmprlma un reLorno de carro .LxlsLen muchas ms opclones de formaLo con
esLe LayouL, pero no las vamos a LraLar aqul.
Lo ulLlmo que nos queda por comenLar es que el nombre log4[ que aparece en cada una
de las llneas hace referencla al nombre de nuesLro logger log4[" .LsLe nombre puede
ser camblado por cualquler oLro, como por e[emplo.
!!!"#$%&'()*(&$#+#,#"*-.
109
Cdlgo 6.17 (log4[.properLles)
com.arquitecturajava

Ll cul hace referencla al nombre de los packages de nuesLro proyecLo y ser el nombre
que se uLlllzar a nlvel de la apllcacln. La slgulenLe Larea se encarga de conflgurar
Log4[ en nuesLra apllcacln.
6. !"# %& '#()* &+ +,&"-./ /0'12/213+4
una vez que hemos vlsLo como funclona el apl de log4[ ,podremos hacer uso del mlsmo
en nuesLra apllcacln. ara ello lnsLalaremos la llbrerla de log4[ en el dlrecLorlo ||b de
nuesLra apllcacln web (ver lmagen).
Anadlda la llbrerla, hay que anadlr el flchero de conflguracln de log4[ con sus
parameLrlzaclones . LsLe flchero se ublcar en la carpeLa src de nuesLro proyecLo de
ecllpse (ver lmagen).
8eallzada esLa operacln, deflnlmos el conLenldo del flchero que en esLe caso, por
slmpllflcar, ser ldenLlco al anLerlormenLe comenLado.

!"#$%&'(&$") +),)
110
Cdlgo 6.18 (log4[.properLles)
log4j.rootLogger = DEBUG, miappender
log4j.logger.milog = com.arquitecturajava.logs
log4j.appender.miappender=org.apache.log4j.ConsoleAppender
log4j.appender.miappender.layout=org.apache.log4j.PatternLayout
log4j.appender.miappender.layout.conversionPattern=%m%n

una vez reallzada esLa operacln, slmplemenLe nos queda modlflcar nuesLra clase
uaLa8asePelper para que se encargue de subsLlLulr las llneas de SysLem.ouL por el uso
del apl de log (ver lmagen).
Cdlgo 6.19 (uaLa8asePelper.[ava)
public class DataBaseHelper<T> {
private static final Logger log = Logger.getLogger(DataBaseHelper.class
.getPackage().getName());
public int modificarRegistro(String consultaSQL) {
!!!!!!!
try {
!!!.
} catch (ClassNotFoundException e) {
log.error("Error de acceso al driver" + e.getMessage());
throw new DataBaseException("Error de SQL", e);
} catch (SQLException e) {
log.error("Error de SQL" + e.getMessage());
throw new DataBaseException("Error de SQL", e);
} finally {
if (sentencia != null) {
try {
sentencia.close();
} catch (SQLException e) {
log.error("Error con la sentencia" +
e.getMessage());}
}if (conexion != null) {
try {
conexion.close();
} catch (SQLException e) {
log.error("Error cerrando la conexion"
+e.getMessage());
}}}return filasAfectadas;}
!!!"#$%&'()*(&$#+#,#"*-.
111

!"#$%"&
Ln esLe caplLulo hemos Lomado conLacLo con el funclonamlenLo del Al de log4[ , el
esLndar de facLo de la plaLaforma !LL a la hora de gesLlonar los mensa[es de log de una
apllcacln . Lo hemos conflgurado para que funclone en nuesLro proyecLo.

!"#$%&'(&$") +),)
112
!!!" $%&'(&$&) *+, - ." /)0.") 123





Pemos avanzando en esLos caplLulos en la consLruccln de nuesLra apllcacln,
reallzando dlversos refacLorlngs que han me[orado su dlseno. Ln esLos momenLos
dlsponemos de los slgulenLes componenLes:
ag|nas IS : Se encargan de crear la capa de presenLacln
C|ases Iava : Se encargan de crear la capa de negoclo y perslsLencla
Ll uso del prlnclplo Dk nos ha servldo de gula en el dlseno de nuesLra apllcacln. Aun
asl, quedan muchas cosas por hacer y el prlnclplo Dk no podr ayudarnos en Lodas
ellas. Ls momenLo de segulr progresando en el dlseno .ara ello, vamos a lnLroduclr un
nuevo prlnclplo: el pr|nc|p|o Sk.
Sk (Slmple 8esponsablllLy rlnclple): Loda clase o componenLe debe Lener una unlca
responsabllldad y Lodas sus funclones deben orlenLarse hacla esLa. CLra forma de
enfocarlo es : una clase, al Lener una unlca responsabllldad, slo debe ser alLerada a
Lraves de un camblo en dlcha responsabllldad. LsLa deflnlcln puede parecer confusa
en un prlmer momenLo pero el concepLo se lr aclarando paulaLlnamenLe con las
expllcaclones del caplLulo.





!!!"#$%&'()*(&$#+#,#"*-.
113
Cb[et|vos
Apllcar el prlnclplo S8 a nuesLra apllcacln
1areas :
1. 8esponsabllldades de la apllcacln y el prlnclplo S8
2. ConsLruccln de un servleL conLrolador
3. Mapeo de ServleL
4. ServleL ConLrolador y funclonalldad
3. lnsercln en modelo MvC
6. 8orrar en el modelo MvC
7. LdlLar en el modelo MvC
8. lllLrar en el modelo MvC

1. kesponsab|||dades de |a ap||cac|n y e| pr|nc|p|o Sk
Sl revlsamos las responsabllldades nuesLro cdlgo fuenLe, podremos enconLrarnos con
lo slgulenLe :
1. ag|nas IS (Capa resentac|n) : 8esponsabllldad de presenLar
lnformacln al usuarlo
2. C|ases Iava (Capa de ers|stenc|a) : 8esponsabllldad de perslsLlr los daLos
en la base de daLos.
arece que nuesLras clases cumplen con los requlslLos del prlnclplo S8 ya que Llenen
asoclada una unlca responsabllldad. Ahora blen, sl repasamos las dlsLlnLas pglnas !S
de nuesLra apllcacln, podremos enconLrarnos con la pglna 8orrarLlbro.[sp y su cdlgo
fuenLe:
Cdlgo 7.1 (8orrarLlbro.[sp)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="com.arquitecturajava.Libro"%>
<%@ page import="com.arquitecturajava.DataBaseException" %>
<%
String isbn= request.getParameter("isbn");
Libro libro= new Libro(isbn);
libro.borrar();
response.sendRedirect("MostrarLibros.jsp");
%>
!"#$%&'(&$") +),)
114
Ln prlnclplo al ser una pglna !S se deberla encargar de presenLar lnformacln al
usuarlo. Sln embargo, es evldenLe que esLa pglna no lncluye nl una sola eLlqueLa hLml
y no presenLa nlnguna lnformacln, por LanLo, su responsabllldad no es presenLar
daLos. uede parecernos que se LraLa de una clase cuya responsabllldad es borrar
daLos, sln embargo, sl revlsamos el proplo cdlgo de la pglna, veremos como la pglna
lnsLancla un ob[eLo de Llpo Llbro y es esLe el encargado de borrar el reglsLro de la base
de daLos (ver cdlgo).
Cdlgo 7.2 (8orrarLlbro.[sp)
Libro libro= new Libro(isbn);
libro.borrar();

Asl pues cul es realmenLe la responsabllldad de esLa pglna? AparenLemenLe no
Llene responsabllldades, pero sl asl fuera, podrlamos ellmlnarla sln per[ulclo para
nuesLra apllcacln. Ls evldenLe que sl ellmlnamos la pglna, no podremos borrar los
reglsLros. LsLo se debe a que la paglna sl Llene una responsabllldad y esLa es la de
contro|. Ls declr ,se encarga de deflnlr que pglna se carga en cada momenLo, asl como
que clase y que meLodo se lnvoca (ver cdlgo).

Asl ,nos enconLramos con una nueva responsabllldad denLro de nuesLra apllcacln: el
conLrol. LsLa responsabllldad no es expresada unlcamenLe por la pglna 8orrarLlbro.[sp.
slno que prcLlcamenLe por Lodas las pglna de nuesLra apllcacln. or e[emplo la
pglna MosLrarLlbros.[sp se encarga de conLrolar a que meLodos de la clase Llbro
debemos lnvocar para presenLar los daLos. Asl pues la responsabllldad de conLrol se
encuenLra dlsLrlbulda enLre dlsLlnLas pglna de dlversas maneras (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
115

Ahora blen, en el caso de la pglna MosLrarLlbros.[sp nos enconLramos anLe un claro
lncumpllmlenLo del prlnclplo S8 ya que la pglna en cuesLln se hace cargo de dos
responsabllldades claramenLe lndependlenLes: la de conLrol y la de presenLacln (ver
lmagen).

ara solvenLar esLe problema, debemos exLraer la responsabllldad de la pglna y
ublcarla en oLro componenLe, pero no podr ser nlnguno de los componenLes que
acLualmenLe Lenemos deflnldos ya que esLos ya Llenen asoclada una responsabllldad:
las pglnas la presenLacln y las clases la de perslsLencla. ara poder exLraer esLa
responsabllldad Lendremos que apoyarnos en un nuevo Llpo de componenLe : un
Serv|et.
!"#$%&'(&$") +),)
116
2. Constru|r un serv|et contro|ador
un servleL es una clase !ava que es capaz de generar cdlgo hLml como lo hace una
pglnas !S pero Lamblen es capaz de gesLlonar la comunlcacln enLre varlas de esLas
pglnas. LsLa capacldad es la que vamos a uLlllzar en nuesLro caso a la hora de reublcar
la responsabllldad de conLrol (ver lmagen).

una vez clarlflcado que el servleL ser el encargado de la responsabllldad de conLrol,
esLaremos cumpllendo con el prlnclplo S8 en el cul cada componenLe slo Llene una
unlca responsabllldad. vamos a pasar ya a consLrulr el servleL e lmplemenLar una
prlmera versln de su meLodo doCeL() que ser el encargado de la comunlcacln enLre
las dlsLlnLas pglnas.
Cdlgo 7.3 (ConLroladorLlbros.[ava)
package com.arquitecturajava.aplicacion;
//omitimos imports
public class ControladorLibros extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws
ServletException,IOException {
RequestDispatcher despachador = null;
List<Libro> listaDeLibros = Libro.buscarTodos();
List<String> listaDeCategorias = Libro.buscarTodasLasCategorias();
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);
despachador = request.getRequestDispatcher("MostrarLibros.jsp");
despachador.forward(request, response);

}
}

!!!"#$%&'()*(&$#+#,#"*-.
117
3. Mapeo de Serv|et
una vez creado el servleL, debemos anadlr un mapeo de esLe a Lraves del flchero
web.xml para de[arlo compleLamenLe conflgurado y poder acceder al mlsmo desde la
slgulenLe url /ConLroladorLlbros.do
Cdlgo 7.4 (web.xml)
<servlet>
<description></description>
<display-name>ControladorLibros</display-name>
<servlet-name>ControladorLibros</servlet-name>
<servlet-class>com.arquitecturajava.aplicacion.ControladorLibros</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ControladorLibros</servlet-name>
<url-pattern>/ControladorLibros</url-pattern>
</servlet-mapping>

4. Serv|et Contro|ador y func|ona||dad
8eallzadas esLas dos operaclones (consLruccln y mapeo), es momenLo de expllcar cada
una de las llneas que esLe servleL conLlene, las cules se encargan de la funclonalldad
de conLrol . vamos a comenzar con las dos prlmeras:
Cdlgo 7.3 (ConLroladorLlbros.[ava)
List<Libro> listaDeLibros = Libro.buscarTodos();
List<String> listaDeCategorias = Libro.buscarTodasLasCategorias();

LsLas llneas delegan en la capa de perslsLencla y cargan la lnformacln que la pglna
MosLrarLlbros.[sp neceslLa en dos varlables: llsLaueLlbros y llsLaueCaLegorlas,
deflnlendo parLe de la responsabllldad de conLrol. vamos a anallzar las slgulenLes
llneas.
Cdlgo 7.6 (ConLroladorLlbros.[ava)
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);

!"#$%&'(&$") +),)
118
LsLas llneas se encargan de almacenar ambas llsLas en el ob[eLo requesL, que es
acceslble LanLo por el servleL conLrolador como por las paglnas !S y hace una funcln
de lnLermedlarlo (ver lmagen).


una vez el ob[eLo requesL lncluye ambas llsLas , usaremos el slgulenLe bloque de cdlgo
para redlrlglr la peLlcln hacla la paglna MosLrarLlbros.[sp.
Cdlgo 7.7 (ConLroladorLlbros.[ava)
despachador = request.getRequestDispatcher("MostrarLibros.jsp");
despachador.forward(request, response);

8eallzado esLe ulLlmo paso , las paglnas [sp no neceslLan ya usar para nada la capa de
perslsLencla y pueden obLener la lnformacln que neceslLan mosLrar del proplo ob[eLo
requesL que slrve de lnLermedlarlo (ver lmagen).


!!!"#$%&'()*(&$#+#,#"*-.
119
Cdlgo 7.8 (MosLrarLlbro.[sp)
<select name="categoria">
<option value="seleccionar">seleccionar</option>
<%
List<String> listaDeCategorias=null;
listaDeCategorias=(List<String>)request.getAttribute("listaDeCategorias")
for(String categoria:listaDeCategorias) {
if (categoria.equals(request.getParameter("categoria"))){
%>
<option value="<%=categoria%>" selected ><%=categoria%></option>
<% } else { %>
<option value="<%=categoria%>"><%=categoria%></option>
<%} }%>
</select>
<input type="submit" value="filtrar">
</form>
<br/>
<%
List<Libro> listaDeLibros
=(List<Libro>)request.getAttribute("listaDeLibros");
for(Libro libro:listaDeLibros){ %>
<%=libro.getIsbn()%>
<%=libro.getTitulo()%>
<%=libro.getCategoria()%>
<a href="BorrarLibro.do?isbn=<%=libro.getIsbn()%>">Borrar</a>
<a href="FormularioEditarLibro.do?isbn=<%=libro.getIsbn()%>">Editar</a>
<br/>
<% }
%>

una vez reallzados esLos refacLorlngs hemos anadldo un nuevo componenLe a nuesLra
apllcacln que se encarga del conLrol de la mlsma. A conLlnuacln se muesLra un
dlagrama con la nueva arqulLecLura de la apllcacln y las dlsLlnLas responsabllldades.




!"#$%&'(&$") +),)
120
Pemos usado el prlnclplo S8 para separar responsabllldades en la apllcacln y de
forma lndlrecLa hemos dlsenado una arqulLecLura que cumple con el paLrn MvC en el
cul cada componenLe Llene un rol cerrado (ver lmagen).
vamos a segulr avanzando en la consLruccln de un Modelo MvC para nuesLra
apllcacln.
!!!"#$%&'()*(&$#+#,#"*-.
121
4. Inserc|n con mode|o MVC
Ln esLa Larea vamos a modlflcar la apllcacln para que LanLo la parLe de mosLrar como
la de lnserLar esLen consLruldas sobre un modelo MvC. ara ello deflnlremos las
slgulenLes Lres u8Ls asocladas al conLrolador.
MosLrarLlbros.do
lormularloLlbrolnserLar.do
lnserLarLlbro.do
uependlendo de la u8L que se sollclLe al ConLrolador por e[emplo
ConLroladorLlbros/MosLrarLlbros.do el conLrolador reallzara una operacln u oLra. ara
clarlflcar el funclonamlenLo del conLrolador vamos a mosLrar un dlagrama con el flu[o
de Lraba[o cuando el usuarlo pulsa el boLn de lnserLar en la paglna MosLrarLlbros.[sp

vamos a comenLar el dlagrama paso a paso para clarlflcar del Lodo cul es la lglca que
deflne la funclonalldad de mosLrar y lnserLar llbros.
1. ulsamos en el boLn de lnserLar llbro y sollclLamos la slgulenLe url al
conLrolador Iormu|ar|oL|broInsertar.do
2. Ll conLrolador lnvoca a la clase Llbro y carga la llsLa de caLegorlas
!"#$%&'(&$") +),)
122
3. Ll conLrolador nos redlrlge a la paglna lormularloLlbro.[sp y muesLra la llsLa
de caLegorlas cargada.
4. 8ellenamos el formularlo e lnvocamos al conLrolador pasando como url
|nsertarL|bro.do
3. Ll conLrolador lnvoca la la clase Llbro e lnserLa los daLos en la base de
daLos. una vez reallzada esLa operacln, lnvoca los meLodos de
buscar1odos y buscarCaLegorlas
6. Ll conLrolador nos redlrlge a MosLrarLlbros.do que carga la paglna
MosLrarLlbros.[sp con los daLos que acabamos de cargar
una vez aclaradas cules son las dlsLlnLas peLlclones que reallzaremos en esLa Larea al
servleL ConLrolador, vamos a ver el cdlgo fuenLe del meLodo doCeL() modlflcado para
lnclulr las dlsLlnLas opclones:
Cdlgo 7. 9 (ConLroladorLlbros.[ava)
RequestDispatcher despachador = null;
if (request.getServletPath().equals("/MostrarLibros.do")) {
List<Libro> listaDeLibros = Libro.buscarTodos();
List<String> listaDeCategorias =
Libro.buscarTodasLasCategorias();
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);
despachador = request.getRequestDispatcher("MostrarLibros.jsp");
} elseif (request.getServletPath().equals("/FormularioInsertarLibro.do")) {
List<String> listaDeCategorias=null;
listaDeCategorias=Libro.buscarTodasLasCategorias();
request.setAttribute("listaDeCategorias", listaDeCategorias);
despachador=request.getRequestDispatcher("FormularioInsertarLibro.jsp");
} else {
String isbn = request.getParameter("isbn");
String titulo = request.getParameter("titulo");
String categoria = request.getParameter("categoria");
Libro libro = new Libro(isbn, titulo, categoria);
libro.insertar();
despachador = request.getRequestDispatcher("MostrarLibros.do");
}

1ras modlflcar el servleL, podremos darnos cuenLa de que Loda la funclonalldad que se
enconLraba ublcada en la pglna lnserLarLlbro.[sp se ha reublcado a nlvel del servleL y la
pglna lnserLarLlbro.[sp, asl podr ser ellmlnada (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
123

S. 8orrar en mode|o MVC
Ls el momenLo de progresar y apllcar el modelo MvC a la funclonalldad de borrar. ara
ello anadlremos una nueva u8L a nuesLro modelo.
8orrarLlbro.do
Ll cdlgo que se encargar de gesLlonar la peLlcln de esLa url es el slgulenLe:
Cdlgo 7.10 (ConLroladorLlbros.[ava)
else {
String isbn = request.getParameter("isbn");
Libro libro = new Libro(isbn);
libro.borrar();
despachador = request.getRequestDispatcher("MostrarLibros.do");
}

ara que el cdlgo funclone correcLamenLe, debemos modlflcar el enlace de la paglna
MosLrarLlbros.[sp (ver lmagen).
!"#$%&'(&$") +),)
124
Cdlgo 7.11 (ConLroladorLlbros.[ava)
<a href="BorrarLibro.do?isbn=<%=libro.getIsbn()%>">Borrar</a>

A conLlnuacln se muesLra el nuevo flu[o de la apllcacln.

LsLa es la expllcacln deLallada de cada una de las peLlclones:
1. ulsamos en el boLn de borrar a nlvel de uno de los reglsLros e lnvocamos al
conLrolador con 8orrarLlbro.do
2. Ll conLrolador lnvoca a la clase acLlve record a su meLodo borrar y borra el
reglsLro. una vez hecho esLo, lnvoca buscar1odos y buscarCaLegorlas para
cargar los daLos necesarlos.
3. Ll conLrolador nos redlrlge a la pglna MosLrasLlbros.[sp
una vez compleLada la Larea de borrar a Lraves del modelo MvC , nos daremos cuenLa
de que la paglna 8orrarLlbro.[sp ya no es necesarla (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
125

6. Ld|tar en mode|o MVC
La Larea de edlLar presenLa grandes slmlllLudes con la Larea de lnserLar y nos permlLlr
de nuevo ellmlnar oLra pglna (LdlLarLlbro.[sp) de la apllcacln. ara consLrulr la
funclonalldad de edlcln neceslLaremos anadlr una nueva u8L a la gesLln del
conLrolador Iormu|ar|oLd|tarL|bro.do que nos redlrlglr a la paglna
lormularloLdlLarLlbro.do. vamos a ver a conLlnuacln el cdlgo:
Cdlgo 7.12 (ConLroladorLlbros.[ava)
} else if (request.getServletPath().equals("/FormularioEditarLibro.do")){
String isbn = request.getParameter("isbn");
List<String> listaDeCategorias = Libro.buscarTodasLasCategorias();
Libro libro = Libro.buscarPorClave(request.getParameter("isbn"));
request.setAttribute("listaDeCategorias", listaDeCategorias);
request.setAttribute("libro", libro);
despachador = request.getRequestDispatcher("FormularioEditarLibro.jsp");

una vez creado esLe bloque de cdlgo la apllcacln ha de ser capaz de modlflcar los
daLos exlsLenLes en el formularlo y salvar los camblos (ver lmagen).
!"#$%&'(&$") +),)
126


A conLlnuacln se muesLra el bloque de cdlgo que se encargarla de acepLar los
camblos y salvarlos.
}else {

String isbn = request.getParameter("isbn");
String titulo = request.getParameter("titulo");
String categoria = request.getParameter("categoria");
Libro libro = new Libro(isbn, titulo, categoria);
libro.salvar();
despachador = request.getRequestDispatcher("MostrarLibros.do");

}

vamos a expllcar mlnuclosamenLe cada una de las peLlclones de la Larea de edlcln.
1. ulsamos en el boLn de edlLar a nlvel de uno de los reglsLros e lnvocamos al
conLrolador con lormularloLdlLarLlbro.do
!!!"#$%&'()*(&$#+#,#"*-.
127
2. Ll conLrolador lnvoca a la clase Llbro a su meLodo buscarorClave
3. Ll conLrolador nos redlrlge a la paglna lormularloLdlLarLlbro.[sp, mosLrando los
daLos a modlflcar.
4. Modlflcamos los daLos del formularlo, pulsamos al boLn de salvar e lnvocamos
a SalvarLlbro.do.
3. Ll conLrolador lnvoca al meLodo salvar para acLuallzar los daLos del Llbro.
uespues de hacer esLo, como slempre lnvoca buscar1odos y buscarCaLegorlas
para cargar los daLos que la pglna MosLrarLlbros.[sp neceslLa.
6. Ll conLrolador nos redlrlge a MosLrarLlbros.[sp
una vez hemos Lermlnado de gesLlonar la Larea de edlcln, nos sovrar la paglna
SalvarLlbro.[sp ya que su funclonalldad la cubre el conLrolador, por lo LanLo podremos
ellmlnarla (ver lmagen).

7. I||trado en Mode|o MVC
ComplemenLando a las modlflcaclones anLerlores nos enconLramos con la Larea de
fllLrado. LsLa permlLe organlzar y selecclonar los llbros por caLegorla para ello
anadlremos una nueva url que acceda al conLrolador y sea la encargada de fllLrar.
lllLrar.do
!"#$%&'(&$") +),)
128
una vez anadlda esLa url y modlflcada la paglna MosLrarLlbros.[sp, podremos anadlr el
slgulenLe bloque de cdlgo al conLrolador de Lal forma que se encargue de reallzar el
fllLrado.
Cdlgo 7.13 (ConLroladorLlbros.[ava)
List<Libro> listaDeLibros = null;
List<String> listaDeCategorias = Libro.buscarTodasLasCategorias();
if (request.getParameter("categoria") == null ||
request.getParameter("categoria").equals("seleccionar")) {
listaDeLibros = Libro.buscarTodos();
} else {
listaDeLibros = Libro.buscarPorCategoria(request
.getParameter("categoria"));
}
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);
despachador = request.getRequestDispatcher("MostrarLibros.jsp");
}

A conLlnuacln se muesLra un dlagrama de flu[o con la lglca que se e[ecuLa duranLe la
operacln de fllLrado.

!!!"#$%&'()*(&$#+#,#"*-.
129
Cada una de las peLlclones de la Larea de edlcln en expllcacln pormenorlzada:
1. ulsamos en el boLn de fllLrar a nlvel del desplegable.
2. Ll conLrolador lnvoca a la clase Llbro a su meLodo buscarorCaLegorla. una vez
hemos esLo, el ConLrolador lnvoca al meLodo buscarCaLegorlas para cargar los
daLos necesarlos para la pra MosLrarLlbros.[sp.
3. Ll conLrolador nos redlrlge a la pgla MosLrarLlbros.[sp, apllcando el fllLro.
Pemos Lermlnado de modlflcar las paglnas y de consLrulr nuesLro conLrolador usando el
prlnclplo S8 y reublcando las responsabllldades de conLrol a nlvel del servleL
conLrolador .A conLlnuacln se muesLra el cdlgo fuenLe del servleL compleLo para
ayudar a clarlflcar Lodas las modlflcaclones reallzadas.
public class ControladorLibros extends HttpServlet {
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
RequestDispatcher despachador = null;

if (request.getServletPath().equals("/MostrarLibros.do")) {

List<Libro> listaDeLibros = Libro.buscarTodos();
List<String> listaDeCategorias = Libro.
buscarTodasLasCategorias();
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);
despachador = request.
getRequestDispatcher("MostrarLibros.jsp");
} else if (request.getServletPath().equals(
"/FormularioInsertarLibro.do")) {

List<String> listaDeCategorias = null;
listaDeCategorias = Libro.buscarTodasLasCategorias();
request.setAttribute("listaDeCategorias", listaDeCategorias);
despachador = request
.getRequestDispatcher("FormularioInsertarLibro.jsp");
} else if (request.getServletPath().equals("/InsertarLibro.do")) {

String isbn = request.getParameter("isbn");
String titulo = request.getParameter("titulo");
String categoria = request.getParameter("categoria");
Libro libro = new Libro(isbn, titulo, categoria);
libro.insertar();
despachador = request.
getRequestDispatcher("MostrarLibros.do");
} else if (request.getServletPath().equals("/BorrarLibro.do")) {
String isbn = request.getParameter("isbn");
Libro libro = new Libro(isbn);
libro.borrar();
!"#$%&'(&$") +),)
130
despachador = request.
getRequestDispatcher("MostrarLibros.do");
} else if (request.getServletPath().equals("/FormularioEditarLibro.do")) {
String isbn = request.getParameter("isbn");
List<String> listaDeCategorias = Libro.
buscarTodasLasCategorias();
Libro libro = Libro
.buscarPorClave(request.getParameter("isbn");
request.setAttribute("listaDeCategorias", listaDeCategorias);
request.setAttribute("libro", libro);

despachador = request
.getRequestDispatcher("FormularioEditarLibro.jsp");

} else if (request.getServletPath().equals("/SalvarLibro.do")) {

String isbn = request.getParameter("isbn");
String titulo = request.getParameter("titulo");
String categoria = request.getParameter("categoria");
Libro libro = new Libro(isbn, titulo, categoria);
libro.salvar();
despachador = request.
getRequestDispatcher("MostrarLibros.do");
} else {
List<Libro> listaDeLibros = null;
List<String> listaDeCategorias =
!!!!!!!!!!!!!!!!.Libro.buscarTodasLasCategorias();
if (request.getParameter("categoria") == null
||
!!!!!!!!!..request.getParameter("categoria").equals("seleccionar")) {
listaDeLibros = Libro.buscarTodos();
} else {
listaDeLibros = Libro.buscarPorCategoria(request
.getParameter("categoria"));
}
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);
despachador = request.
getRequestDispatcher("MostrarLibros.jsp");
}
despachador.forward(request, response);
}
}




!!!"#$%&'()*(&$#+#,#"*-.
131
!"#$%"&
una vez flnallzado el conLrolador, hemos reublcado las responsabllldades de nuesLra
apllcacln, organlzndolas de acuerdo al prlnclplo S8. Como resulLado, hemos podldo
separar me[or cada una de las capas y ellmlnar parLe de los flcheros !S que Lenlamos.
or ulLlmo, queda por ver como ha quedado la esLrucLura flslca de flcheros una vez
compleLada la evolucln a un modelo MvC . La slgulenLe lmagen muesLra el resulLado.







!"#$%&'(&$") +),)
132
!!!"#$






Acabamos de apllcar el paLrn MvC a nuesLra apllcacln, apoyndonos en el prlnclplo
S8 ,aun asl un desarrollador puede decldlr no usar esLe paLrn de dlseno y segulr
usando scrlpLleL de !S en sus pglnas. ara evlLar esLe problema, en esLe nuevo
caplLulo modlflcaremos las pglnas de nuesLra apllcacln para que use !ava SLandard
1ag Llbrary (!S1L) como llbrerla de eLlqueLas, la cul nos ayudar a slmpllflcar el
desarrollo y evlLar el uso de scrlpLleL, obLenlendo unas paglnas ms claras.
Cb[et|vos:
uLlllzar !S1L en la apllcacln
1areas:
1. lnsLalacln de !S1L
2. lnLroduccln a !S1L
3. LLlqueLas 8slcas !S1L
4. Modlflcar MosLrarLlbro.[sp
3. Modlflcar lormularlolnserLarLlbro.[sp
6. Modlflcar lormularloLdlLarLlbro.[sp


!!!"#$%&'()*(&$#+#,#"*-.
133
1. Insta|ac|n de IS1L
AnLes de comenzar a lnLroduclrnos en !S1L, neceslLamos lnsLalar llbrerlas adlclonales a
nuesLro servldor 1omcaL. ara ello accederemos a la slgulenLe url.
http:]][st|.[ava.net]down|oad.htm|
ue la cul podremos obLener las slgulenLes llbrerlas
[sLl.[ar
sLandard.[ar
una vez obLenldas las llbrerlas, las ublcaremos en el dlrecLorlo WL8-lnl/llb de nuesLra
apllcacln (ver lmagen).

8eallzado esLe paso, habremos Lermlnado de lnsLalar !S1L en nuesLra apllcacln y
podremos comenzar a Lraba[ar con ello.
2. Introducc|n a IS1L
Ln esLos momenLos nuesLras paglnas !S mezclan el uso de eLlqueLas con scrlpLleL. !S1L
nos permlLlr homogenelzar esLe comporLamlenLo, permlLlendonos el uso de eLlqueLas
hLml y la subsLlLucln del scrlpLleL por un con[unLo de eLlqueLas de servldor, de Lal
forma que las nuevas paglnas !S unlcamenLe esLarn compuesLas por eLlqueLas (ver
lmagen).


!"#$%&'(&$") +),)
134

A conLlnuacln se muesLra un e[emplo senclllo de las dlferenclas enLre ambas
Lecnologlas a la hora de lmprlmlr lnformacln hLml
IS
Cdlgo 8.1:
<%if (edad>18) {%>
Eres una persona adulta con edad <%=edad%>
<%}%>

IS1L
Cdlgo 8.2:
<c:if test=${edad>18}>
Eres una persona adulta ${edad}
</c:if>

Como podemos ver con !S1L unlcamenLe Lenemos grupos de eLlqueLas y LexLo plano lo
que har ms senclllo a los maqueLadores Lraba[ar con las pglnas.
3. Lt|quetas 8s|cas IS1L
AnLes de modlflcar nuesLra apllcacln para que soporLe !S1L, vamos a expllcar las
eLlqueLas elemenLales de !S1L que nuesLra apllcacln va a neceslLar.


!!!"#$%&'()*(&$#+#,#"*-.
135
La slgulenLe eLlqueLa lmprlme una varlable !S en la pglna:
Cdlgo8. 3:
${variable}

La eLlqueLa <forLach> recorre coleccln de ob[eLos ublcados en una llsLa e lmprlme sus
propledades
Cdlgo 8.4:
<c:forEach var="objeto" items="${lista}">
${objeto.propiedad}
</c:forEach>

Se encarga de lmprlmlr un bloque de lnformacln dependlenLe de una condlcln
predeLermlnada.
Cdlgo 8.3:
<c:if test=${edad>30}>
Eres una persona adulta ${edad}
</c:if>

una vez vlsLas las eLlqueLas esenclales, vamos a modlflcar nuesLras pglnas.
4. Mod|f|car MostrarL|bro.[sp
A conLlnuacln vamos a usar dos eLlqueLas <c:forLach> para modlflcar la paglna y
ellmlnar compleLamenLe el scrlpLleL. A conLlnuacln se muesLra el cdlgo.





!"#$%&'(&$") +),)
136
Cdlgo 8.6: (MosLrarLlbro.[sp)
<form name="filtroCategoria" action="filtrar.do"><select
name="categoria">
<option value="seleccionar">seleccionar</option>
<c:forEach var="categoria" items="${listaDeCategorias}">
<option value="${categoria}">${categoria}</option>
</c:forEach>
</select><input type="submit" value="filtrar"></form>
<br />
<c:forEach var="libro" items="${listaDeLibros}">
${libro.isbn}${libro.titulo}${libro.categoria}
<a href="BorrarLibro.do?isbn=${libro.isbn}">borrar</a>
<a href="FormularioEditarLibro.do?isbn=${libro.isbn}">editar</a>
<br />
</c:forEach>
<a href="FormularioInsertarLibro.do">InsertarLibro</a>

uespues de reallzar esLa Larea, pasaremos a modlflcar la pglna lormularlolnserLar.[sp.
S. Mod|f|car Iormu|ar|o Insertar
Ser suflclenLe con crear oLro bucle <c:forLach> encargado de cargar la llsLa de
caLegorlas.
Cdlgo 8.7: (lormularloLlbro.[sp)
<form id="formularioInsercion" action="InsertarLibro.do">
<fieldset><legend>Formularioaltalibro</legend>
<p><label for="isbn">ISBN:</label>
<input type="text" id="isbn" name="isbn" /></p>
<p><label for="titulo">Titulo:</label>
<input type="text" id="titulo" name="titulo" /></p>
<p><label for="categoria">Categoria :</label>
<select name="categoria">
<c:forEach var="categoria" items="${listaDeCategorias}">
<option value="${categoria}">${categoria}</option>
</c:forEach>
</select><br />
</p><p><input type="submit" value="Insertar" /></p>
</fieldset>
</form>


!!!"#$%&'()*(&$#+#,#"*-.
137
llnallzada esLa operacln, nos queda una ulLlma pglna por modlflcar
6. Mod|f|car Iormu|ar|oLd|tarL|bro.[sp
LsLa pglna es muy slmllar a la pglna anLerlor, aunque Lendr ms bloque de cdlgo
!S1L al Lener que presenLar el formularlo con la lnformacln para edlLar ya cargada.

Cdlgo 8 8: (lormularloLlbroLdlclon.[sp)
<form id="formularioEdicion" action="ModificarLibro.do">
<fieldset><legend>Formularioaltalibro</legend>
<p><label for="isbn">ISBN:</label><input type="text" id="isbn"
name="isbn" value="${libro.isbn}" /></p>
<p><label for="titulo">Titulo:</label><input type="text"
id="titulo" name="titulo" value="${libro.titulo}" /></p>
<p><label for="categoria">Categoria :</label><select
name="categoria">
<c:forEach var="categoria" items="${listaDeCategorias}">
<option value="${categoria}">${categoria}</option>
</c:forEach>
</select><br />
</p>
<p><input type="submit" value="Salvar" /></p>
</fieldset>
</form>

!"#$%"&
una vez flnallzadas las modlflcaclones, nuesLra apllcacln ha de[ado de usar scrlpLleL en
el cdlgo de las pglnas !S y uLlllza eLlqueLas !S1L, reforzando el modelo MvC que
consLrulmos en el caplLulo anLerlor.





!"#$%&'(&$") +),)
138
!!!" $%&'(&$&) *+, - .)/0") 12+ 3












Ln los dos caplLulos anLerlores hemos modlflcado nuesLra apllcacln para que, usando
el prlnclplo S8, la dlvlsln de responsabllldades sea mas naLural y use !S1L como
Lecnologla de capa de presenLacln. Ln esLe caplLulo lnLroduclremos oLro prlnclplo
lmporLanLe: e| pr|nc|p|o CC o prlnclplo de aperLura y clerre cuya deflnlcln es:

CC (Cpen C|osed r|nc|p|e):Ll prlnclplo CC o prlnclplo de aperLura y clerre, se deflne
como: Lodo cdlgo desarrollado para una apllcacln debe esLar cerrado a las
modlflcaclones y ablerLo a la exLenslbllldad. Lxpresado de oLra manera: debemos poder
anadlr nueva funclonalldad a la apllcacln sln Lener que alLerar el cdlgo ya consLruldo.
SeguldamenLe nos encargaremos de apllcar esLe prlnclplo en nuesLra apllcacln.

Cb[et|vos
Apllcar el prlnclplo CC a nuesLra apllcacln



1areas
1. Ll prlnclplo CC y el ConLrolador
2. Ll prlnclplo CC y el paLron Command
3. Creacln de una acclon prlnclpal
4. Crear una [erarqula de acclones
3. Apl de reflecLlon y prlnclplo CC



!!!"#$%&'()*(&$#+#,#"*-.
139
1. L| pr|nc|p|o CC y e| Contro|ador

Ln esLos momenLos Lenemos consLrulda una apllcacln sobre el modelo MvC y su
dlseno es basLanLe slldo. uespues de conocer la deflnlcln del prlnclplo CC nos
percaLamos de que cada vez que anadlmos una mlnlma funclonalldad nueva a nuesLra
apllcacln esLamos obllgados a modlflcar el ServleL conLrolador de esLa y anadlr una o
varlas senLenclas lf -else lf que lmplemenLen la nueva funclonalldad (ver lmagen).



Asl pues parece claro que el conLrolador es un elemenLo que no esL para nada cerrado
a las modlflcaclones, slno ms blen al conLrarlo: cualquler modlflcacln por pequena
que sea de la apllcacln afecLa dlrecLamenLe al conLrolador y clarlflca que no cumple
con el prlnclplo CC (ver lmagen).

!"#$%&'(&$") +),)
140




2. L| pr|nc|p|o CC y e| patrn Command

vamos a apoyarnos en el prlnclplo CC para comenzar a redlsenar el conLrolador de Lal
forma que podamos anadlr nueva funclonalldad a la apllcacln sln que esLe se vea
afecLado. ara redlsenar el conLrolador y que pueda cumpllr con el prlnclplo CC vamos
exLraer el concepLo de Acc|n]1area del mlsmo y ublcarlo en una [erarqula de clases
compleLamenLe nueva . Cada una de esLas clases Lendr las slgulenLes caracLerlsLlcas:

1. Peredarn de una clase comun denomlnada Accln.
2. 1odas dlspondrn del meLodo e[ecuLar en el cual e[ecuLaran la funclonalldad a
ellas aslgnada.
3. 1endrn un nombre que haga referencla a la funclonalldad que se encargan de
e[ecuLar.

A conLlnuacln se muesLra la lmagen con una parLe de la [erarqula de las acclones.


!!!"#$%&'()*(&$#+#,#"*-.
141


Ln prlnclplo nos puede parecer que se LraLa de un senclllo grupo de clases sln embargo
la [erarqula de acclones se consLrulr apoyndonos en un paLrn de dlseno
denomlnado Comando. LsLe paLrn obllga cada clase a deflnlr un meLodo e[ecuLar en el
cul ublcaremos la funclonalldad que deseamos (ver lmagen).


ueflnlda la [erarqula de clases, podremos exLraer la funclonalldad que se encuenLra
ublcada en el conLrolador y reublcarla en el meLodo e[ecuLar de cada una de las clases .
A parLlr de esLe momenLo, el conLrolador delegar en las acclones (ver lmagen).

!"#$%&'(&$") +),)
142



3. Creac|n de una acc|n pr|nc|pa|

ueflnldo el nuevo funclonamlenLo del conLrolador, vamos a ver el cdlgo fuenLe de la
clase Accln.

Cdlgo 9.1: (Acclon.[ava)
package com.arquitecturajava.aplicacion.controlador.acciones;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public abstract class Accion {
public abstract String ejecutar(HttpServletRequest request,
HttpServletResponse response);
}



Creada esLa clase, podemos ver como el meLodo e[ecuLar reclbe dos parmeLros.

PLLpServleL8equesL
PLLpServleL8esponse
!!!"#$%&'()*(&$#+#,#"*-.
143

Son los mlsmos parmeLros que uLlllzamos a nlvel del servleL. ue esLa forma nuesLro
servleL conLrolador podr delegar en el con[unLo de acclones que vemos a
conLlnuacln.



4. Crear [erarqu|a de acc|ones

A parLlr de ahora usaremos acclones para lmplemenLar la funclonalldad de cada una de
los dlsLlnLos bloques de cdlgo. vamos a ver el cdlgo fuenLe de una accln en concreLo
que nos ayude a enLender que parLe de la funclonalldad exlsLenLe cubren las acclones y
que oLra funclonalldad cubre el conLrolador. A conLlnuacln se muesLra el cdlgo
fuenLe de la Acclon lnserLarLlbro.

Cdlgo 9.2: (lnserLarLlbroAcclon.[ava)
public class InsertarLibroAccion extends Accion{
public String ejecutar(HttpServletRequest request,
HttpServletResponse response) {
String isbn = request.getParameter("isbn");
String titulo = request.getParameter("titulo");
String categoria = request.getParameter("categoria");
Libro libro = new Libro(isbn, titulo, categoria);
libro.insertar();
return "MostrarLibros.do";
}
!"#$%&'(&$") +),)
144

Pemos creado cada una de las dlsLlnLas acclones exLrayendo el cdlgo que exlsLla en las
clusulas lf-elself-else del meLodo doCeL() del conLrolador, quedando esLe muy
slmpllflcado ya que unlcamenLe Llene que decldlr que accln crea y luego lnvocar al
meLodo e[ecuLar de esLa (ver cdlgo).

Cdlgo 9.3: (ConLroladorLlbros.[ava)
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
RequestDispatcher despachador = null;
Accion accion = null;
if (request.getServletPath().equals("/MostrarLibros.do")) {
accion = new MostrarLibrosAccion();
} elseif (request.getServletPath().equals(
"/FormularioInsertarLibro.do")) {
accion = new FormularioInsertarLibroAccion();
} elseif (request.getServletPath().equals("/InsertarLibro.do")) {
accion = new InsertarLibroAccion();
} elseif (request.getServletPath().equals("/BorrarLibro.do")) {
accion = new BorrarLibroAccion();
} elseif (request.getServletPath().equals("/FormularioEditarLibro.do")) {
accion = new FormularioEditarLibroAccion();
} elseif (request.getServletPath().equals("/ModificarLibro.do")) {
accion = new ModificarLibroAccion();
} else {
accion = new FiltrarLibrosPorCategoriaAccion();
}
despachador = request.getRequestDispatcher(
!.accion.ejecutar(request,response));
despachador.forward(request, response);
}

Con esLe refacLorlng hemos me[orado basLanLe nuesLra apllcacln y aunque cada vez
que anadlmos una nueva funclonalldad, debemos modlflcar el conLrolador, la mayor
parLe del nuevo cdlgo se encuenLra en cada una de las acclones.

Ll slgulenLe paso a reallzar ser exLraer el proplo bloque lf else del conLrolador y
ublcarlo en la clase Accln de Lal forma que el conLrolador ya no Lenga nlnguna
responsabllldad en cuanLo a que accln ha de crear y esLa responsabllldad quede
compleLamenLe delegada a la clase Accln.

ara esLe paso consLrulremos un nuevo meLodo en la clase Accln denomlnado
geLAcclon() que se encargue de crear las dlsLlnLas acclones. LsLos meLodos
hablLualmenLe se les denomlnan meLodos facLorla ya que cumplen con el paLrn
facLory. A conLlnuacln se muesLra un dlagrama aclaraLorlo asl como el cdlgo fuenLe
de esLe meLodo.
!!!"#$%&'()*(&$#+#,#"*-.
145



Cdlgo 9. 4: (Acclon.[ava)
publicstatic Accion getAccion(String tipo) {
Accion accion=null;
if (tipo.equals("/MostrarLibros.do")) {
accion = new MostrarLibrosAccion();
} elseif (tipo.equals(
"/FormularioInsertarLibro.do")) {
accion = new FormularioInsertarLibroAccion();
} elseif (tipo.equals("/InsertarLibro.do")) {
accion = new InsertarLibroAccion();
}
!..............................
return accion;
}

!"#$%&'(&$") +),)
146
Como podemos ver, es esLe meLodo ahora el encargado de crear cada una de las
acclones, slmpllflcando sobremanera el conLrolador que Lenemos desarrollado, ya que
a parLlr de esLe momenLo el conLrolador queda con el slgulenLe cdlgo:

Cdlgo 9.3: (ConLroladorLlbros.[ava)
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
RequestDispatcher despachador = null;
Accion accion = null;
String url= request.getServletPath();
accion= Accion.getAccion(url.substring(1,url.length()-3));
despachador = request.getRequestDispatcher(accion.ejecutar(request,
response));
despachador.forward(request, response);
}


una vez reallzados esLos camblos, no Lenemos que modlflcar el servleL nunca ms
para poder anadlr nuevas acclones a nuesLra apllcacln: por lo LanLo el servleL
conLrolador cumple con el prlnclplo CC, aunque no ocurre lo mlsmo con la clase
acLlon, como se muesLra en el slgulenLe dlagrama.
!!!"#$%&'()*(&$#+#,#"*-.
147


Ln esLos momenLos debemos modlflcar la clase Accln y su meLodo esLLlco
geLAcclon() cada vez que deseemos anadlr nuevas acclones . Ls por esLo que Lodavla
nos queda Lraba[o que reallzar para que Lamblen esLa clase cumpla con el prlnclplo
CC.

S. Ap| de ref|ect|on y e| pr|nc|p|o CC

ara solvenLar esLe problema es necesarlo fl[arse en el nombre de las dlsLlnLas u8L que
pasamos al conLrolador, como es por e[emplo la slgulenLe:

Cdlgo 9.7
FormularioInsertarLibro.do

!"#$%&'(&$") +),)
148
uespues de obLener esLa u8L, podemos Lransformarla en el slgulenLe LexLo e[ecuLando
un par de funclones de formaLo, con lo cual nos queda un LexLo ldenLlco al nombre de
una clase Accln concreLa.

Cdlgo 9.8:
FormularioInsertarLibroAcccion

CbLenldo el nombre de la accln, usaremos el apl de reflecLlon que ya conocemos de
caplLulos anLerlores y crearemos un ob[eLo basado en el nombre de la clase. ara ello
usaremos el slgulenLe meLodo del apl:

Cdlgo 9.9:
Class.forName.newInstance(String nombreClase)

A conLlnuacln se muesLra un dlagrama aclaraLorlo:


!!!"#$%&'()*(&$#+#,#"*-.
149
una vez creado el ob[eLo, lnvocaremos a su meLodo e[ecuLar. A conLlnuacln se
muesLra el cdlgo de cmo el Al de reflecLlon permlLe lr lnserLando nuevas acclones
sln modlflcar el cdlgo prevlamenLe consLruldo.

Cdlgo 9.10:
public static Accion getAccion(String tipo) {
Accion accion = null;
try {
accion = (Accion) Class.forName(getPackage()
+"."+tipo+"Accion").newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return accion;
}

1ermlnado esLe camblo, podemos lr anadlendo nuevas acclones a nuesLra apllcacln sln
lmpacLar en las anLerlormenLe consLruldas, cumpllendo con el prlnclplo CC (ver
lmagen).


!"#$%&'(&$") +),)
150

!"#$%"&

Pemos Lermlnado de modlflcar nuesLra apllcacln que ahora se apoya en el prlnclplo
CC para lr anadlendo nueva funclonalldad sln afecLar a la anLerlormenLe consLrulda.
LsLe dlseno es muy hablLual a dla de hoy en frameworks web como ha sldo el caso de
sLruLs o es el caso de !Sl y Sprlng MvC. Al LraLarse de una modlflcacln lmporLanLe del
Modelo MvC a esLe modelo se le suele denomlnar Modelo MvC 2 o de ConLrolador
lronLal.


!!!"#$%&'()*(&$#+#,#"*-.
151


















!"#$%&'(&$") +),)
152
!"!!"#$%&'($






Acabamos de apllcar el prlnclplo CC y hemos mlgrado nuesLra apllcacln a un modelo
MvC2. LsLa ha sldo la ulLlma versln de la apllcacln que no hace uso en alguna de sus
parLes de un framework !LL.
A parLlr de esLe caplLulo comlenza la segunda parLe del llbro orlenLada a la uLlllzacln
de dlsLlnLos frameworks que nos sern uLlles para acelerar el desarrollo. Ln esLe
caplLulo lnLroduclremos PlbernaLe como framework de perslsLencla y subsLlLulremos la
capa de perslsLencla acLual (uaLa8asePelper.[ava) por PlbernaLe.
Cb[et|vos :
lnLroduccln a PlbernaLe
uLlllzar PlbernaLe en nuesLra apllcacln
1areas :
1. ConcepLo de lramework de perslsLencla.
2. lnsLalacln de PlbernaLe.
3. lnLroduccln a PlbernaLe
4. Conflguracln de PlbernaLe
3. lnserLar ob[eLos en la base de daLos con PlbernaLe.
6. Seleccln de ob[eLos de la base de daLos con PlbernaLe.
7. Selecclonar un unlco ob[eLo con PlbernaLe
8. 8orrar ob[eLos de la base de daLos con PlbernaLe.
9. lllLrar ob[eLos de la base de daLos con PlbernaLe
10. ConsLruccln de la clase PlbernaLe Pelper.
11. Mapeo del flchero de conflguracln.
12. Ll prlnclplo de Convencln sobre conflguracln
!!!"#$%&'()*(&$#+#,#"*-.
153
1. Introduc|on a| concepto de framework de pers|stenc|a
PasLa esLe momenLo hemos usado la clase uaLa8asePelper para que se encargara de
las operaclones llgadas con la base de daLos (ver lmagen).

Sln embargo la clase aunque funclonal, Llene muchas llmlLaclones Lales como:
no soporLa Lransacclones que agrupen varlos meLodos ya que la conexln no es
comparLlda y cada meLodo es LoLalmenLe lndependlenLe.
no soporLa uso de pool de conexlones y cada vez se consLruye una conexln
nueva
no soporLa consulLas preparadas y usa consulLas SCL esLndar con los
problemas de lnyeccln de SCL que esLo genera
no soporLa varlos Llpos de moLores de bases de daLos y se cenLra en MySCL
odrlamos conLlnuar con la llsLa de llmlLaclones, pero parece claro que sl queremos
consLrulr una solucln LnLerprlse, la clase que hemos consLruldo no es el me[or camlno.
nos ha sldo uLll hasLa el momenLo y ha ayudado a lr asenLando concepLos. Asl pues, sl
queremos evoluclonar nuesLra solucln a algo mas serlo, deberemos apoyarnos en un
framework de perslsLencla que ellmlne las llmlLaclones que nuesLra clase acLual Llene y
aporLe caracLerlsLlcas adlclonales (ver lmagen).



!"#$%&'(&$") +),)
154


Ln nuesLro caso uLlllzaremos PlbernaLe ya que es el framework de perslsLencla ms
conocldo por la comunldad, la slgulenLe Larea abordara su lnsLalacln.
2. Insta|ac|n de n|bernate
ara poder lnsLalar PlbernaLe lo prlmero que Lendremos que hacer es ba[arnos las
llbrerlas de las cuales se compone, que esLn dlsponlbles en la slgulenLe url:
hLLp://sourceforge.neL/pro[ecLs/hlbernaLe/flles/hlbernaLe3/

!!!"#$%&'()*(&$#+#,#"*-.
155
CbLenldas las llbrerlas, pasaremos a lnsLalarlas en un proyecLo !ava LsLndar de Lcllpse
en el cul consLrulremos unos senclllos e[emplos para aprender a mane[ar el
framework. A conLlnuacln se muesLran las llbrerlas que debemos anadlr a nuesLro
proyecLo para que los slgulenLes e[emplos se puedan e[ecuLar correcLamenLe.

1ras lnsLalar el framework, es momenLo de comenzar a Lraba[ar con el.

3. Introducc|n a n|bernate
PlbernaLe es un framework C8M (Cb[ecL 8elaLlonal Mapplng) cuya Larea es la de
permlLlr a un desarrollador mapear ob[eLos conLra reglsLros de una base de daLos (ver
lmagen).
!"#$%&'(&$") +),)
156


1odos los frameworks de perslsLencla Lraba[an de forma slmllar, pero cada uno Llene
sus proplos flcheros de conflguracln. Ln el caso del framework PlbernaLe exlsLen una
serle de flcheros y concepLos claves a la hora de comenzar a Lraba[ar con el. Los
enumeramos a conLlnuacln basndonos en la clase Llbro.
n|bernate.cfg.xm|: Ls el flchero prlnclpal de conflguracln del framework, es
donde se conflgura el drlver !u8C de acceso a daLos la lp del servldor de base
de daLos, el usuarlo y la password ,asl como los flcheros de mapeo que van a
uLlllzar las dlsLlnLas clases.
L|bro.xm|: Ls el flchero de mapeo que almacena la lnformacln relevanLe
referlda a cmo un ob[eLo que perLenece a una clase deLermlnada, en esLe
caso un Llbro, es mapeado a una flla de la Labla Llbros
L|bro.[ava : Clase [ava que es mapeada
A conLlnuacln se muesLra un dlagrama de alLo nlvel sobre cuales son los flcheros y
pasos generales que reallza el framework PlbernaLe a la hora de Lraba[ar con los
ob[eLos [ava que se encarga de perslsLlr.



!!!"#$%&'()*(&$#+#,#"*-.
157

A conLlnuacln vamos a expllcar cada uno de los pasos del dlagrama:
1. Leer n|bernate.cfg.xm|: Como prlmera Larea, el framework busca y lee el
flchero de conflguracln donde se encuenLra la lnformacln de usuarlo, clave,
drlver y url de conexln. ue esLa forma se conecLa a la base de daLos. !unLo a
esLa lnformacln se encuenLra Lamblen la llsLa de flcheros de mapeo que leer
posLerlormenLe.

2. Leer I|chero de mapeo: Se encarga de leer Lodos los flcheros de mapeo de la
apllcacln para saber como mapear un ob[eLo deLermlnado conLra alguna de
las Lablas exlsLenLes en la base de daLos.

3. Carga |a c|ase : Ll programa que esLemos consLruyendo carga las clases en
memorla
!"#$%&'(&$") +),)
158
4. Crear Cb[eto : Ll programa que esLemos consLruyendo crea varlos ob[eLos de la
clase
3. Sa|var: PlbernaLe se encarga de guardar los daLos en la base de daLos

una vez reallzada una lnLroduccln a cmo PlbernaLe Lraba[a en llneas generales, es
momenLo de consLrulr nuesLro prlmer e[emplo.
4. Conf|gurac|n n|bernate
una vez creado un proyecLo !ava esLndar y anadldas las llbrerlas necesarlas para
Lraba[ar con PlbernaLe, lo prlmero que neceslLaremos ser conflgurar el flchero
hlbernaLe.cfg.xml. LsLe flchero esLar ublcado denLro de nuesLro classpaLh, como la
lmagen muesLra:
Clarlflcada la necesldad de esLe flchero, vamos a ver un e[emplo con su conLenldo:
Cdlgo 10.1(hlbernaLe.cfg.xml)
<?xml version='1.0' encoding='utf-8'?>
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/arquitecturajava</property>
<property name="connection.username">root</property>
<property name="connection.password">java</property>
<property name="connection.pool_size">5</property>
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="show_sql">true</property>
<mapping resource="com/arquitecturajava/aplicacion/bo/Libro.xml"/>
</session-factory>
</hibernate-configuration>

!!!"#$%&'()*(&$#+#,#"*-.
159
Como anLes hemos comenLado, el flchero conLlene la lnformacln de conexln y los
flcheros de mapeo a uLlllzar (mapplng-resources). vamos a comenLar deLalladamenLe
cada una de las propledades que esLe flchero conLlene.
Cdlgo 10.2(hlbernaLe.cfg.xml):
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>

LsLa llnea se encarga de selecclonar el drlver naLlvo de conexln a la base de daLos
.ara ello neceslLaremos anadlr el drlver Llpo 4 de MySCL a nuesLra apllcacln.
Cdlgo 10.3(hlbernaLe.cfg.xml):
<property name="connection.url">jdbc:mysql://localhost/arquitecturajava</property>

LsLa llnea deflne la u8L de acceso al servldor de base de daLos y a una de sus bases de
daLos en concreLo.
Cdlgo 10.4(hlbernaLe.cfg.xml):
<property name="connection.username">root</property>
<property name="connection.password">java</property>

LsLas dos llneas conflguran el usuarlo y password de acceso a la base de daLos.
Cdlgo 10.3(hlbernaLe.cfg.xml):
<property name="connection.pool_size">5</property>

LsLa llnea conflgura el Lamano del pool de conexlones del framework a 3.
Cdlgo 10.6(hlbernaLe.cfg.xml):
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>

LsLa llnea selecclona el dlalecLo que usara PlbernaLe a la hora de reallzar las dlsLlnLas
operaclones conLra la base de daLos .Ln esLe caso el dlalecLo elegldo es el de MySCL
aunque PlbernaLe soporLa muchos ms como SCLServer, Cracle eLc y permlLe que una
!"#$%&'(&$") +),)
160
mlsma apllcacln basada en PlbernaLe pueda camblar de forma LransparenLe el moLor
de base de daLos uLlllzado .LsLa es una de las venLa[as fundamenLales de hacer uso de
un framework de perslsLencla.
Cdlgo 10.7(hlbernaLe.cfg.xml):
<property name="show_sql">true</property>

Conflgura PlbernaLe para que muesLre Lodas las consulLas SCL que genera. LsLe
parmeLro suele ser una ayuda lmporLanLe a la hora de valorar sl PlbernaLe esL
funclonando de forma correcLa o no.
Cdlgo 10.8(hlbernaLe.cfg.xml):
<mapping resource="com/arquitecturajava/aplicacion/bo/Libro.xml"/>

LsLa ulLlma llnea es la que se encarga de dar de alLa los dlsLlnLos flcheros que mapean
las clases a las Lablas de la base de daLos .Ln nuesLro e[emplo lnLroducLorlo unlcamenLe
Lenemos un flchero el flchero Llbro.xml (ver lmagen).
vamos a mosLrar a conLlnuacln el conLenldo de esLe flchero y anallzar su conLenldo.
Cdlgo 10.11(Llbro.xml):
<?xml version="1.0"?>
<hibernate-mapping package="com.arquitecturajava.aplicacion.bo">
<class name="Libro" table="Libros">
<id name="isbn" type="string" />
<property name="titulo" type="string" column="titulo" />
<property name="categoria" type="string" column="categoria" />
</class>
</hibernate-mapping>

!!!"#$%&'()*(&$#+#,#"*-.
161
Como podemos ver el flchero xml no es dlflcll de enLender , ya que slmplemenLe mapea
cada una de las propledades que Llene nuesLra clase con una columna de la Labla de la
base de daLos. Ln esLe caso unlcamenLe dlsponemos de las slgulenLes propledades.
Cdlgo 10.12(Llbro.xml):
<property name="titulo" type="string" column="titulo" />
<property name="categoria" type="string" column="categoria" />

ara complemenLar el mapeo PlbernaLe neceslLa saber cul de las propledades de la
clase es deflnlda como clave prlmarla. ara ello el framework usa la eLlqueLa <ld> que
ldenLlflca una propledad como clave prlmarla.
Cdlgo 10.13(Llbro.xml):
<id name="isbn" type="string" />

una vez reallzados esLos pasos, podemos pasar a consLrulr un programa senclllo que
use PlbernaLe como framework de perslsLencla.
S. Insertar L|bro con n|bernate
Como punLo de parLlda vamos a crear un programa que se encarga de crear un ob[eLo
Llbro y salvarlo en la base de daLos PlbernaLe, a conLlnuacln se muesLra el cdlgo:
Cdlgo 10.14(rlnclpal.[ava):
public static void main(String[] args) {
Session session=null;
Transaction transaccion =null;
try {
SessionFactory factoria = new Configuration().configure()
.buildSessionFactory();
session = factoria.openSession();
transaccion = session.beginTransaction();
Libro l= new Libro("1","java","programacion");
session.saveOrUpdate(l);
transaccion.commit();
} catch (HibernateException e) {
System.out.println(e.getMessage());
transaccion.rollback();
} finally {
session.close();}
!"#$%&'(&$") +),)
162
vamos a expllcar llnea a llnea el bloque de cdlgo consLruldo para que paulaLlnamenLe
nos vayamos famlllarlzando con los dlsLlnLos concepLos.
Cdlgo 10.13(rlnclpal.[ava):
SessionFactory factoria =new Configuration().configure().buildSessionFactory();

LsLa prlmera llnea de cdlgo se encarga de leer el flchero hlbernaLe.cfg.xml y conflgurar
el acceso a daLos para el framework. una vez conflgurado el acceso, nos devuelve un
ob[eLo SesslonlacLory que es un ob[eLo unlco a nlvel del framework y ser el
encargado de darnos acceso al resLo del Al de PlbernaLe. una vez dlsponemos del
ob[eLo SesslonlacLory, lnvocamos el meLodo openSesslon(), como se muesLra a
conLlnuacln.
Cdlgo 10.16(rlnclpal.[ava):
Session session = factoriaSession.openSession();

LsLe meLodo nos devuelve una sesln que se puede enLender como una conexln
clslca a la base de daLos. una vez consLrulda una sesln, ya dlsponemos de una
conexln que nos permlLlr salvar ob[eLos en la base de daLos. ara ello nos
consLrulremos un prlmer ob[eLo.
Cdlgo 10.17(rlnclpal.[ava):
Libro libro= new Libro (1,java,programacion);

Creado esLe nuevo ob[eLo, usaremos el ob[eLo sesln para comenzar una nueva
Lransaccln.
Cdlgo 10.18(rlnclpal.[ava):
transaccion= session.beginTransaction();

una vez que nos enconLramos denLro de una Lransaccln, sollclLamos al ob[eLo sesslon
que salve el ob[eLo usando el meLodo saveCrupdaLe.

!!!"#$%&'()*(&$#+#,#"*-.
163
Cdlgo 10.19(rlnclpal.[ava):
session.saveOrUpdate(libro);

ara ello el framework PlbernaLe se apoyar en los flcheros de mapeo consLruldos
(Llbro.xml) y que esLn dlsponlbles a Lraves del ob[eLo Sesslon, encargndose de apllcar
el mapeo deflnldo. una vez reallzada la operacln, flnallzamos la Lransaccln.
Cdlgo 10.20(rlnclpal.[ava):
session.getTransaction().commit();

Pemos salvado el ob[eLo en la base de daLos y hemos vlsLo las clases fundamenLales del
framework. A conLlnuacln el dlagrama nos lo resume.


una vez reallza esLa operacln de lnsercln de llbros en la base de daLos, vamos a ver
cmo podemos usar PlbernaLe para reallzar oLras operaclones complemenLarlas.
!"#$%&'(&$") +),)
164
6. Se|ecc|onar Cb[etos con n|bernate
vamos a consLrulr un nuevo e[emplo con el framework PlbernaLe que se encargue de
selecclonar Lodos los llbros de la base de daLos, para ello consLrulremos el slgulenLe
programa maln.
Cdlgo 10.21(rlnclpal.[ava):
public static void main(String[] args) {
Session session=null;
try {
SessionFactory factoria = new Configuration().configure()
.buildSessionFactory();
session= factoria.openSession();
Query consulta= session.createQuery("from Libro libro");
List<Libro> lista= consulta.list();
for(Libro l: lista) {
System.out.println(l.getIsbn());
System.out.println(l.getTitulo());
System.out.println(l.getCategoria());
}
}catch(HibernateException e) {
System.out.println(e.getMessage());
}finally {
session.close();
}
}

LsLe e[emplo Llene fuerLe slmlllLudes con el e[emplo anLerlor la unlca dlferencla
lmporLanLe es que aparece un nuevo concepLo el de uery.
uery : Ll ob[eLo Cuery hace referencla en PlbernaLe a una consulLa que lanzamos
conLra la base de daLos .Lso sl en vez de ser una consulLa SCL se LraLa de una consulLa
PCL (n|bernate uery Language) lengua[e propleLarlo de PlbernaLe que nos permlLe
Lraba[ar con el mlsmo Llpo de senLenclas sln lmporLarnos el moLor de base de daLos que
uLlllcemos .Ms adelanLe, esLa consulLa ser Lransformada en consulLa SCL para el
moLor de base de daLos que se haya selecclonado como dlalecLo en el flchero
hlbernaLe.cfg.xml. una vez Lenemos claro cul es el concepLo de Cuery, vamos a
anallzar nuesLra consulLa
Cdlgo 10.22(rlnclpal.[ava):
Query consulta= session.createQuery("from Libro libro");

!!!"#$%&'()*(&$#+#,#"*-.
165
Ln esLe caso se LraLa de una consulLa sencllla que usa PCL para selecclonar Lodos los
llbros de la Labla usando un allas. una vez hemos creado la consulLa, lnvocamos al
meLodo llsL() del ob[eLo Cuery que nos devuelve una llsLa de ob[eLos a recorrer.
Cdlgo 10.23(rlnclpal.[ava):
List<Libro> lista= consulta.list();

ulcha llsLa la recorreremos con un senclllo buble for
Cdlgo 10.24(rlnclpal.[ava):
for(Libro l: lista) {
System.out.println(l.getIsbn());
System.out.println(l.getTitulo());
System.out.println(l.getCategoria());
}

LsLe bucle for nos presenLar la lnformacln por la consola.
PasLa esLe momenLo hemos vlsLo cmo lnserLar llbros o cmo selecclonar una llsLa de
esLos , ahora vamos a segulr Lraba[ando con el framework.
7. Se|ecc|onar un n|co Cb[eto
Ll slgulenLe e[emplo nos mosLrar cmo selecclonar un unlco reglsLro de la Labla
usando PlbernaLe.

!"#$%&'(&$") +),)
166
Cdlgo 10.23(rlnclpal.[ava):
public static void main(String[] args) {
Session session=null;
try {
SessionFactory factoria = new Configuration().configure()
.buildSessionFactory();
session= factoria.openSession();
Libro libro=(Libro) session.get(Libro.class,"1");
System.out.println(libro.getTitulo());
}catch(HibernateException e) {
System.out.println(e.getMessage());
}finally {
session.close();
}
}

Ln esLe e[emplo que acabamos de consLrulr lo unlco desLacable es cmo PlbernaLe se
encarga de selecclonar un unlco ob[eLo a Lraves de la slgulenLe llnea.
Cdlgo 10.26(rlnclpal.[ava):
Libro libro=(Libro) session.get(Libro.class,"1");

una vez selecclonado, slmplemenLe lmprlmlmos sus daLos por panLalla.
Cdlgo 10.27(rlnclpal.[ava):
System.out.println(libro.getTitulo());

Cuedan por consLrulr unlcamenLe dos operaclones ms que nos vayan a ser uLlles a la
hora de hacer evoluclonar nuesLra apllcacln: las operaclones de borrar y fllLrar.
8. 8orrar un ob[eto
Ln el caso de borrar no vamos a profundlzar mucho porque es Lan senclllo como
lnvocar el meLodo deleLe del ob[eLo sesln una vez obLenldo el ob[eLo a Lraves de
PlbernaLe, a conLlnuacln se muesLra el cdlgo:


!!!"#$%&'()*(&$#+#,#"*-.
167
Cdlgo 10.28(rlnclpal.[ava):
Session session=null;
try {
SessionFactory factoria = new Configuration().configure()
.buildSessionFactory();
session= factoria.openSession();
Libro libro=(Libro) session.get(Libro.class,"1");
session.delete(libro);
}catch(HibernateException e) {
System.out.println(e.getMessage());
}finally {
session.close();
}

9. I||trar ob[etos con n|bernate
or ulLlmo, como lnLroduccln al framework, vamos a ver cmo se puede lanzar una
consulLa con PCL que reclba parmeLros y fllLre la seleccln de daLos.
Cdlgo 10.29(rlnclpal.[ava):

public static void main(String[] args) {
Session session = null;
try {
SessionFactory factoria = new Configuration().configure()
.buildSessionFactory();
session = factoria.openSession();
Query consulta = session
.createQuery(" from Libro libro where
libro.categoria=:categoria");
consulta.setString("categoria", "programacion");
List<Libro> lista = consulta.list();
for (Libro l : lista) {
System.out.println(l.getIsbn());
System.out.println(l.getTitulo());
System.out.println(l.getCategoria());
}
} catch (HibernateException e) {
System.out.println(e.getMessage());
} finally {
session.close();
}
}

!"#$%&'(&$") +),)
168
Como podemos ver, esLa consulLa se encarga de locallzar Lodos los llbros que esLn
denLro de una caLegorla deLermlnada. ara ello se consLruye una consulLa en PCL y se
le aslgna un parmeLro: caLegorla a la cual se le aslgna un valor.
Cdlgo 10.30(rlnclpal.[ava):
Query consulta = session.createQuery(" from Libro libro where
libro.categoria=:categoria");
consulta.setString("categoria", programacion);

una vez hecho esLo, lnvocamos como en casos anLerlores al meLodo llsL() del ob[eLo
Cuery y recorremos la llsLa.
Cdlgo 10.31(rlnclpal.[ava):
List<Libro> lista = consulta.list();
for (Libro l : lista) {
System.out.println(l.getIsbn());
System.out.println(l.getTitulo());
System.out.println(l.getCategoria());
}

Con esLa breve lnLroduccln al framework PlbernaLe Lendremos suflclenLe para hacer
frenLe a los camblos de nuesLra apllcacln, que se abordarn a conLlnuacln.
10. M|grar nuestra ap||cac|n a n|bernate
Ls momenLo de ver cmo podemos enca[ar el framework denLro de nuesLra apllcacln.
Ln prlmer lugar vamos a consLrulr una nueva clase que subsLlLuya a la clase
uaLa8asePelper y se encargue de lnlclallzar el framework PlbernaLe. LsLa clase se
denomlnar PlbernaLePelper y lnlclallzar el framework. A conLlnuacln se muesLra su
cdlgo.





!!!"#$%&'()*(&$#+#,#"*-.
169
Cdlgo 10.32 (rlnclpal.[ava):

package com.arquitecturajava.aplicacion;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateHelper {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
return new Configuration().configure().buildSessionFactory();
}
catch (Throwable ex) {
System.err.println("Error creando una factoria de session." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}

LsLa sencllla clase nos permlLlr obLener de forma dlrecLa el ob[eLo SesslonlacLory, que
lnlclallza el framework , como se muesLra a conLlnuacln.
Cdlgo 10.33 (rlnclpal.[ava):
SessionFactory factoriaSession=HibernateHelper.getSessionFactory();
Session session = factoriaSession.openSession();
Libro libro=(Libro) session.get(Libro.class,isbn);
session.close();

una vez consLrulda la clase PlbernaLePelper, es momenLo de camblar nuesLra clase
Llbro para que se apoye compleLamenLe en el Al de PlbernaLe. uespues de esLo,
podremos ellmlnar la clase uaLa8asePelper de nuesLra apllcacln. A conLlnuacln se
muesLra el cdlgo fuenLe de la clase Llbro acLuallzado para que se apoye en PlbernaLe.




!"#$%&'(&$") +),)
170
Cdlgo 10.34 (Llbro.[ava):
package com.arquitecturajava.aplicacion;
//omitimos imports
public class Libro {

private String isbn;
private String titulo;
private String categoria;

@Override
public int hashCode() {
return isbn.hashCode();
}
@Override
public boolean equals (Object o) {
String isbnLibro= ((Libro)o).getIsbn();
return isbnLibro.equals(isbn);

}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitulo() {
return titulo;
}
public void setTitulo(String titulo) {
this.titulo = titulo;
}
public String getCategoria() {
return categoria;
}
public void setCategoria(String categoria) {
this.categoria = categoria;
}
public Libro(String isbn) {
super();
this.isbn = isbn;
}
public Libro() {
super();
}
public Libro(String isbn, String titulo, String categoria) {
super();
this.isbn = isbn;
this.titulo = titulo;
this.categoria = categoria;
!!!"#$%&'()*(&$#+#,#"*-.
171
}
@SuppressWarnings("unchecked")
public static List<Libro> buscarTodasLasCategorias() {

SessionFactory factoriaSession=HibernateHelper.getSessionFactory();
Session session = factoriaSession.openSession();
String consulta="select distinct libro.categoria from Libro libro";
List<Libro> listaDeCategorias = session.createQuery(consulta).list();
session.close();
return listaDeCategorias;
}
public void insertar() {

SessionFactory factoriaSession=HibernateHelper.getSessionFactory();
Session session = factoriaSession.openSession();
session.beginTransaction();
session.save(this);
session.getTransaction().commit();
}
public void borrar(){

SessionFactory factoriaSession=HibernateHelper.getSessionFactory();
Session session = factoriaSession.openSession();
session.beginTransaction();
session.delete(this);
session.getTransaction().commit();
}
public void salvar() {

SessionFactory factoriaSession=HibernateHelper.getSessionFactory();
Session session = factoriaSession.openSession();
session.beginTransaction();
session.saveOrUpdate(this);
session.getTransaction().commit();
}
@SuppressWarnings("unchecked")
public static List<Libro> buscarTodos() {
SessionFactory factoriaSession=HibernateHelper.getSessionFactory();
Session session = factoriaSession.openSession();
List<Libro> listaDeLibros = session.createQuery(" from Libro libro").list();
session.close();
return listaDeLibros;
}
public static Libro buscarPorClave(String isbn) {
SessionFactory factoriaSession=HibernateHelper.getSessionFactory();
Session session = factoriaSession.openSession();
Libro libro=(Libro) session.get(Libro.class,isbn);
session.close();
return libro;
}
!"#$%&'(&$") +),)
172
@SuppressWarnings("unchecked")
public static List<Libro> buscarPorCategoria(String categoria) {

SessionFactory factoriaSession=HibernateHelper.getSessionFactory();
Session session = factoriaSession.openSession();
Query consulta=session.createQuery(" from Libro libro where
libro.categoria=:categoria");
consulta.setString("categoria", categoria);
List<Libro> listaDeLibros = consulta.list();
session.close();
return listaDeLibros;
}

}

una vez reallzadas esLas modlflcaclones, nuesLra clase Llbro se apoya compleLamenLe
en el framework de perslsLencla para reallzar cualquler operaclon. La esLrucLura flslca
del proyecLo ha anadldo los slgulenLes elemenLos en un nuevo paqueLe denomlnado bo
(buslness ob[ecLs).

11. n|bernate y Convenc|n sobre Conf|gurac|n.
Pemos mlgrado nuesLra apllcacln de un slsLema de perslsLencla elemenLal que usaba
una clase [ava (uaLa8asePelper) al uso de PlbernaLe. ara ello hemos Lenldo que
modlflcar la lmplemenLacln de parLe de nuesLras clases, asl como anadlr una serle de
flcheros de conflguracln del framework adlclonales, como se muesLra en la slgulenLe
flgura.
!!!"#$%&'()*(&$#+#,#"*-.
173

Aunque nos pueda parecer que esLamos usando PlbernaLe de la forma adecuada y que
prcLlcamenLe no Lenemos cdlgo repeLldo en nuesLra apllcacln, vemos que lo que sl
Lenemos repeLldo es la lnformac|n respecLo a los concepLos que esLamos mane[ando
a nlvel de capa de perslsLencla .Ln esLe caso esLamos replLlendo la lnformacln sobre el
concepLo de llbro en las slgulenLes ublcaclones.
Clase !ava
llchero de conflguracln (Llbro.xml)
1abla Llbro (Mysql)
LsLe problema esL llgado con el prlnclplo u8? ya que, aunque no se LraLa de repeLlcln
de cdlgo, sl se LraLa de repeLlcln de |nformac|n a nlvel de nuesLra apllcacln (ver
lmagen).
!"#$%&'(&$") +),)
174


Ll ob[eLlvo prlnclpal de la slgulenLe Larea ser ellmlnar las repeLlclones de lnformacln
de nuesLra apllcacln en cuanLo a la capa de perslsLencla se reflere.
12. Dk e n|bernate
Ln prlnclplo no podemos apllcar una solucln sencllla a la repeLlcln de lnformacln
que Lenemos enLre la apllcacln !LL y la base de daLos, ya que al LraLarse de slsLemas
lndependlenLes ambos deben almacenar la lnformacln relaLlva a nuesLro negoclo (ver
lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
175

Sln embargo sl que podemos avanzar en solvenLar la repeLlcln de lnformacln que
exlsLe a nlvel de nuesLra apllcacln !LL en la cul Lenemos la mlsma lnformacln
almacenada a nlvel de las clases !ava y de los flcheros xml de conflguracln del
framework (ver lmagen).

La repeLlcln de cdlgo, ya sabemos por caplLulos anLerlores, conlleva graves
problemas de manLenlmlenLo .Lo mlsmo sucede con la repeLlcln de lnformacln. nos
basLa por e[emplo con referlrnos a las clslcas reglas de normallzacln de una base de
daLos para saber los problemas que se generan. Sln embargo aqul no podemos apllcar
esLas reglas de normallzacln, ya que nos enconLramos no con una base de daLos slno
con cdlgo !ava. Asl pues es momenLo de lnLroduclr oLro prlnclplo de lngenlerla de
sofLware que apoya al prlnclplo u8?. Ll prlnclplo de Convencln sobre Conflguracln o
CCC (ConvenLlon Cver ConflguraLlon).
!"#$%&'(&$") +),)
176
CCC :Ll prlnclplo CCC deflne que, anLes de abordar el desarrollo, un programador
puede declarar una serle de convenclones que le permlLen asumlr una conflguracln
por defecLo del slsLema.
Culz esLa deflnlcln sea algo absLracLa y dlflcll de enLender en un prlnclplo . un
e[emplo es la forma de perclblrlo ms claramenLe. vamos a usar el prlnclplo CCC en
nuesLra apllcacln deflnlendo la slgulenLe convencln.
Los campos de nuesLras clases [ava de negoclo (Llbro) slempre sern ldenLlcos a los
campos de la Labla de la base de daLos donde se guarden los ob[eLos de esLa.
Ll hecho de apllcar esLe concepLo a nuesLra apllcacln lmpllcar que el flchero xML que
consLrulmos por cada clase de perslsLencla no ser a parLlr de ahora necesarlo, ya que
al apllcar esLa convencln se sobreenLlende que los campos y propledades colnclden.
ConsecuenLemenLe, como la lmagen muesLra, esLe flchero ya no es necesarlo.

Sln embargo recordemos que esLe flchero no se encargaba unlcamenLe de mapear los
campos, slno que adems se encargaba de deflnlr cul de Lodas las propledades de la
clase se ldenLlflcada como clave prlmarla . A conLlnuacln se muesLra el flchero en
forma de recordaLorlo.

!!!"#$%&'()*(&$#+#,#"*-.
177
Cdlgo 10.33 (Llbro.xml):
<class name="Libro" table="Libros">
<id name="isbn" type="string" />
<property name="titulo" type="string" column="titulo" />
<property name="categoria" type="string" column="categoria" />
</class>

Asl pues no podemos ellmlnar esLe flchero hasLa que reublquemos la lnformacln sobre
las claves prlmarlas en algun oLro lugar. ara ello haremos uso del slsLema de
anoLaclones que soporLa [ava y que permlLe anadlr lnformacln adlclonal a nuesLras
clases.
un e[emplo claro de esLe Llpo de lnformacln es la anoLacln [Cverrlde, que nos
permlLe deflnlr cmo un meLodo ha de ser sobrecargado . A conLlnuacln se muesLra
un e[emplo de cdlgo.
Cdlgo 10.36:
@Override
public void metodo() {
}

Apoyndonos en esLa ldea, podemos volver a PlbernaLe. PlbernaLe soporLa oLro
con[unLo de anoLaclones orlenLadas a faclllLar la perslsLencla de nuesLros ob[eLos.
vamos a hacer uso de esLas anoLaclones.
QLnt|ty : ldenLlflca a una clase como clase a perslsLlr
QId: ldenLlflca la propledad de la clase como clave prlmarla de la Labla
Q1ab|e: ldenLlflca cul es el nombre de la Labla conLra la que se mapea la
clase.
Ll uso de esLe con[unLo de anoLaclones nos permlLlr ellmlnar los flcheros xml de
mapeo que hemos usado hasLa ahora .
!"#$%&'(&$") +),)
178


A conLlnuacln se muesLra el cdlgo fuenLe de nuesLra clase.
Cdlgo 10.37 (Llbro.xml):
@Entity
@Table(name="Libros")
public class Libro {
@Id
private String isbn;
private String titulo;
private String categoria;
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitulo() {
return titulo;
}
publicvoid setTitulo(String titulo) {
this.titulo = titulo;
}
public String getCategoria() {
return categoria;
} //resto de metodos

Como podemos ver, ya no neceslLamos el flchero de mapeo, es suflclenLe con el uso de
anoLaclones. Ll modelo de anoLaclones nos obllga Lamblen a reallzar algunas
modlflcaclones a nlvel del flchero PlbernaLe.cfg.xml , vamos a verlo.
!!!"#$%&'()*(&$#+#,#"*-.
179
Cdlgo 10.38 (PlbernaLe.cfg.xml):
<hibernate-configuration><session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">
jdbc:mysql://localhost/arquitecturaJavaORM
</property>
<property name="connection.username">root</property>
<property name="connection.password">java</property>
<property name="connection.pool_size">5</property>
<property name="dialect">
org.hibernate.dialect.MySQL5Dialect
</property>
<mapping class="com.arquitecturajava.aplicacion.bo.Libro" />
</session-factory>
</hibernate-configuration>

kesumen
LsLe caplLulo ha servldo de lnLroduccln al framework PlbernaLe . Pemos apllcado el
prlnclplo CCC para conflgurar de una forma mas cmoda el framework a la hora de
usarlo en nuesLra apllcacln.









!"#$%&'(&$") +),)
180
!!!!"#$%&'($ * +$,'-".&$/





Pemos modlflcado nuesLra apllcacln para que se apoye en el framework PlbernaLe a
la hora de gesLlonar la capa de perslsLencla. Sln embargo aun nos quedan basLanLes
punLos a la hora de Lraba[ar con un framework de perslsLencla .Culzs lo mas
desLacable del uso de un framework de perslsLencla es que nos permlLe consLrulr
modelos ms comple[os y flexlbles donde exlsLan varlas clases y se consLruyan
relaclones enLre las mlsmas. Ln esLos momenLos, nuesLro caso parLe de un modelo
elemenLal donde unlcamenLe Lenemos una Labla en la base de daLos , Lal como se
muesLra en la slgulenLe lmagen.

Ls momenLo de consLrulr un modelo ms slldo enLldad-relacln en el cul el
framework PlbernaLe se pueda apoyar. Asl pues modlflcaremos la esLrucLura de la base
de daLos para que aparezca una nueva Labla, la Labla CaLegorlas (ver lmagen).

!!!"#$%&'()*(&$#+#,#"*-.
181

ue esLa forma, ambos concepLos esLn relaclonados a Lraves del ld de la Labla caLegorla
y del campo caLegorla de la Labla Llbros. una vez consLruldas ambas Lablas, esLas
quedarn relaclonadas a Lraves de una clave exLerna (ver lmagen).



una vez modlflcado el modelo de Lablas, debemos encargarnos de reallzar las
modlflcaclones oporLunas en nuesLra apllcacln para que soporLe un modelo ms
comple[o donde las enLldades se relaclonan, esLe ser el ob[eLlvo prlnclpal del caplLulo.
A conLlnuacln se llsLan los ob[eLlvos y Lareas del mlsmo.





!"#$%&'(&$") +),)
182
Cb[et|vos:
Lvoluclonar la apllcacln !LL para que soporLe un modelo de ob[eLos comple[o a nlvel
de capa de perslsLencla.
1areas:
1. ConsLrulr la clase CaLegorla y mapearla
2. Modlflcar la capa de presenLacln para soporLar la clase CaLegorla
3. Creacln de relaclones enLre clases
4. 8elaclones y perslsLencla con PlbernaLe
3. 8elaclones y capa de presenLacln
1. Constru|r |a c|ase categor|a y mapear|a
nos enconLraremos que, lgual que exlsLen dos Lablas en la base de daLos, deberemos
Lener Lamblen en prlnclplo dos clases en nuesLro modelo de ob[eLos de negoclo (ver
lmagen)


Asl pues debemos crear una nueva clase en nuesLra apllcacln que se encargar de
gesLlonar el concepLo de CaLegorla. vamos a ver su cdlgo.



!!!"#$%&'()*(&$#+#,#"*-.
183
Cdlgo 11.1: (CaLegorla.[ava)
package com.arquitecturajava.aplicacion.bo;
//omitimos imports
@Entity
@Table(name = "Categorias")
public class Categoria {
@Id
private String id;
private String descripcion;
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals (Object o) {
String categoriaId= ((Categoria)o).getId();
return id.equals(categoriaId);
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDescripcion() {
return descripcion;
}
public void setDescripcion(String descripcion) {
this.descripcion = descripcion;
}
public static List<Categoria> buscarTodos() {
SessionFactory factoriaSession =
HibernateHelper.getSessionFactory();
Session session = factoriaSession.openSession();
List<Categoria> listaDeCategorias = session.createQuery(
" from Categoria categoria").list();
session.close();
return listaDeCategorias;
}
}

una vez creada esLa clase, observaremos que comparLe el mlsmo slsLema de
anoLaclones que Llene la clase llbro y deberemos anadlrla a la zona de clases mapeadas
que Llene el flchero hlbernaLe.cfg.xml para que sea lnclulda como clase de perslsLencla.
Pemos adems sobrecargado el meLodo equals y hashcode, lo cul evlLar problemas a
la hora de comparar ob[eLos de la mlsma clase. A conLlnuacln se muesLra el cdlgo
que debemos anadlr a nuesLro flchero de conflguracln para dar de alLa esLa nueva
clase.
!"#$%&'(&$") +),)
184
Cdlgo 11.2: (hlbernaLe.cfg.xml)
<hibernate-configuration>
<session-factory>
<!--resto de propiedades-->
<mapping class="com.arquitecturajava.aplicacion.bo.Libro" />
<mapping class="com.arquitecturajava.aplicacion.bo.Categoria" />
</session-factory>
</hibernate-configuration>

2. Mod|f|car |a Capa de presentac|n y soportar |a c|ase Categor|a
una vez hecho esLo, es necesarlo modlflcar algunas de nuesLras acclones para que se
hagan eco de los camblos reclen lnLroducldos, ya que ahora el meLodo de buscar Lodas
las caLegorlas se encuenLra ublcado en la clase CaLegorla. vamos a ver como esLe
camblo afecLa a la clase lormularlolnserLarLlbroAcclon.

Cdlgo 11.3: (formularlolnserLarLlbroAcclon.xml)

public class FormularioInsertarLibroAccion extends Accion {
@Override
public String ejecutar(HttpServletRequest request,
HttpServletResponse response) {
List<Categoria> listaDeCategorias = null;
listaDeCategorias = Categoria.buscarTodos();
request.setAttribute("listaDeCategorias", listaDeCategorias);
return "FormularioInsertarLibro.jsp";
}
}

Como podemos ver, la clase de accln hace uso de la nueva clase CaLegorla a la hora
de buscar Lodas las caLegorlas de la apllcacln. LsLe camblo afecLar de lgual modo a
oLras acclones .una vez modlflquemos Lodas las acclones afecLadas, deberemos
Lamblen modlflcar las dlsLlnLas paglnas !S que hacen uso de la llsLa de caLegorlas. A
conLlnuacln se muesLra cmo varla el cdlgo de la pglna lormularlolnserLarLlbro.[sp.


!!!"#$%&'()*(&$#+#,#"*-.
185

Cdlgo 11.4: (MosLrarLlbros.[sp)
<form id="formularioInsercion" action="InsertarLibro.do">
<fieldset><legend>Formularioaltalibro</legend>
<p><label for="isbn">ISBN:</label><input type="text" id="isbn"
name="isbn" /></p>
<p><label for="titulo">Titulo:</label><input type="text"
id="titulo" name="titulo" /></p>
<p><label for="categoria">Categoria :</label>
<select name="categoria">
<c:forEach var="categoria" items="${listaDeCategorias}">
<option value="${categoria.id}">
${categoria.descripcion}
</option>
</c:forEach>
</select><br />
</p>
<p><input type="submit" value="Insertar" /></p>
</fieldset>
</form>

LsLe camblo afecLar LanLo a los formularlos de edlcln como a la paglna
MosLrarLlbros.[sp .Ahora blen, en esLa pglna Lendremos algunos problemas anadldos
con el slgulenLe bloque de cdlgo.
Cdlgo 11.3: (MosLrarLlbros.[sp)
<c:forEach var="libro" items="${listaDeLibros}">
${libro.isbn}
${libro.titulo}
${libro.categoria}
<a href="BorrarLibro.do?isbn=${libro.isbn}">borrar</a>
<a href="FormularioEditarLibro.do?isbn=${libro.isbn}">editar</a>
<br />
</c:forEach>

Aunque en un prlnclplo nos parezca que no exlsLe nlngun camblo a esLe nlvel, sl
e[ecuLamos la pglna, podremos percaLarnos de que el resulLado es dlsLlnLo a los
e[emplos del caplLulo anLerlor, ya que no aparece el nombre de la caLegorla slno su ld
Lal como se ve en la slgulenLe lmagen.

!"#$%&'(&$") +),)
186
Ls aqul donde podemos observar que, aunque hemos consLruldo un modelo ms
slldo, quedan pasos por reallzar. Ll modelo Llene sus llmlLaclones y Lendremos que
avanzar un paso ms para superarlas. ara ello, la slgulenLe Larea se encargar de
deflnlr relaclones enLre las dlsLlnLas clases.
3. Creac|n de re|ac|ones entre c|ases
Ln esLos momenLos nuesLras dos clases CaLegorla y Llbro no esLn relaclonadas enLre
sl. Ls momenLo de modlflcar nuesLro cdlgo fuenLe y crear las slgulenLes relaclones
enLre ambas clases:
- Una Categor|a cont|ene var|os L|bros: 8elacln de 1 a n en la que una caLegorla
conLlene un con[unLo de llbros

- Un L|bro pertenece a una categor|a: ke|ac|n de n a 1 en la que cada Llbro
perLenece a una caLegorla concreLa
Ll slgulenLe dlagrama muesLra cmo se relaclonan ambas clases.

!!!"#$%&'()*(&$#+#,#"*-.
187
ara que esLa relacln exlsLa a nlvel de cdlgo !ava, la clase CaLegorla debe lnclulr un
LlsL<> de Llbros y la clase Llbro debe lnclulr una varlable de Llpo CaLegorla, como el
slgulenLe dlagrama muesLra.

una vez Lenemos claras esLas ldeas, es momenLo de pasar a mosLrar el cdlgo fuenLe
de ambas clases para ver como esLas dos relaclones se lmplemenLan.
Cdlgo 11.6: (CaLegorla.[ava)
@Entity
@Table(name = "Categorias")
public class Categoria {
@Id
private int id;
private String descripcion;
private List<Libro> listaDeLibros;
public List<Libro> getListaDeLibros() {
return listaDeLibros;
}
public void setListaDeLibros(List<Libro> listaDeLibros) {
this.listaDeLibros = listaDeLibros;
}
// resto de codigo





!"#$%&'(&$") +),)
188
Cdlgo 11.7: (Llbro.[ava)
@Entity
@Table(name="Libros")
public class Libro {
@Id
private String isbn;
private String titulo;
private Categoria categoria;

public Categoria getCategoria() {
return categoria;
}
public void setCategoria(Categoria categoria) {
this.categoria = categoria;
}
//resto de codigo

LsLe es un prlmer paso a la hora de crear relaclones enLre nuesLras clases. Sln embargo
esLa prlmera parLe no crea relaclones a nlvel de perslsLencla, slno unlcamenLe a nlvel
de memorla. La slgulenLe Larea se apoyar en el uso de anoLaclones para que las
relaclones que hayamos consLruldo Lengan senLldo Lamblen a esLe oLro nlvel.
4. ke|ac|ones y pers|stenc|a con n|bernate
PlbernaLe nos provee de un con[unLo nuevo de anoLaclones orlenLadas a crear
relaclones enLre las dlsLlnLas clases [ava y asegurar su perslsLencla. vamos a enumerar
a conLlnuacln algunas de las anoLaclones ms lmporLanLes:
- QCne1oMany : AnoLacln que se encarga de crear una relacln de 1 a n enLre dos
clases predeLermlnadas (CaLegorla y Llbro en nuesLro e[emplo).
- QMany1oCne :Anotac|n que se encarga de crear una relacln de muchos a uno
enLre dos clases predeLermlnadas (Llbro y CaLegorla en nuesLro e[emplo).
- QIo|nCo|umn: AnoLacln que slrve a para dlscernlr que columna de la Labla de la base
de daLos se usa como clave exLerna o fornea a la hora de apllcar la relacln.
Aclarado esLe punLo , vamos a ver como se apllcan las anoLaclones a nlvel de cdlgo.


!!!"#$%&'()*(&$#+#,#"*-.
189
Cdlgo 11.8: (Llbro.[ava)
@Entity
@Table(name="Libros")
public class Libro {
@Id
private String isbn;
private String titulo;
@ManyToOne
@JoinColumn (name="categoria")
private Categoria categoria;
}

Cdlgo 11.9: (CaLegorla.[ava)
@Entity
@Table(name="Categorias")
public class Categoria {
@Id
private int id;
private String descripcion;
@OneToMany
@JoinColumn(name = "categoria")
private List<Libro> listaDeLibros;

1ras consLrulr las relaclones a nlvel de perslsLencla usando las anoLaclones de
PlbernaLe, vamos a consLrulr un e[emplo senclllo que muesLra cmo uLlllzarlas.
Cdlgo 11.10: (rlnclpal.[ava)
SessionFactory factoriaSession=HibernateHelper.getSessionFactory();
Session session = factoriaSession.openSession();
List<Libro> listaDeLibros = session.createQuery("from Libro libro).list();
for(Libro l :listaDeLibros) {
System.out.println(l.getTitulo());
//accedemos a la categoria a traves de la relacion.
System.out.println(l.getCategoria().getDescripcion());
}
session.close();

Como podemos ver, en un prlmer momenLo usamos el framework PlbernaLe y el
lengua[e PCL para selecclonar Lodos los llbros de los dlsponemos.

!"#$%&'(&$") +),)
190
Cdlgo 11.11: (rlnclpal.[ava)
List<Libro> listaDeLibros = session.createQuery("from Libro libro).list();

una vez obLenldos los llbros, recorremos la llsLa con un buble y vamos mosLrando los
dlsLlnLos conLenldos.
Cdlgo 11.12: (rlnclpal.[ava)
for(Libro l :listaDeLibros) {
System.out.println(l.getIsbn());
}

Ahora blen sl revlsamos la slgulenLe llnea.
Cdlgo 11.13: (rlnclpal.[ava)
System.out.println(l.getCategoria().getDescripcion());

nos podemos dar cuenLa de que nos obllga a acceder a la lnformacln de descrlpcln
de nuesLra caLegorla, lnformacln que prevlamenLe no hemos selecclonado con la
consulLa PCL .8ecordemos que la consulLa unlcamenLe selecclona el concepLo de Llbro.
Cdlgo 11.14: (rlnclpal.[ava)
from Libro libro

ara cumpllr con nuesLra peLlcln PlbernaLe usar la lnformacln relaLlva a las
relaclones que acabamos de consLrulr y obLendr los daLos necesarlos de la base de
daLos, como se muesLra en la lmagen al e[ecuLar el cdlgo.



!!!"#$%&'()*(&$#+#,#"*-.
191

Aunque la apllcacln funclona correcLamenLe, no es senclllo enLender cmo PlbernaLe
conslgue reallzar esLa operacln .vamos a comenLar a grosso modo como funclona esLe
framework de perslsLencla a la hora de reallzar esLa operacln: PlbernaLe es capaz de
reallzar esLa operacln a Lraves del concepLo de roxy que crean las anoLaclones
relaLlvas a las relaclones .un proxy es un ob[eLo falseo que slmula ser un ob[eLo real. Ln
nuesLro caso, PlbernaLe lee los daLos de la clase CaLegorla y crea un ob[eLo CaLegorla
roxy que slmula ser el ob[eLo orlglnal, como se muesLra en el slgulenLe dlagrama.


!"#$%&'(&$") +),)
192
vamos a comenLar a conLlnuacln el dlagrama
1. PlbernaLe accede al ob[eLo CaLegorla, la cul es un proxy
2. PlbernaLe crea un ob[eLo CaLegorla real accedlendo a la base de daLos
3. PlbernaLe accede a los daLos el ob[eLo real y se los devuelve al Llbro
una vez Lenemos claro como funclona el concepLo de CaLegorlaroxy y que no se LraLa
de un ob[eLo real ,vamos a mosLrar cul es la esLrucLura bslca de memorla que se
consLruye cuando e[ecuLamos la consulLa selecL llbro from llbro" .A conLlnuacln se
muesLra una lmagen.


Ls vlslble que se carga en memorla una llsLa de Llbros ,sln embargo esLa llsLa no
conLlene nlngun ob[eLo CaLegorla 8eal slno slmplemenLe un con[unLo de
roxlesCaLegorla que dan la sensacln de ser los ob[eLos reales. Ahora blen, cuando
e[ecuLemos la slgulenLe llnea de cdlgo


!!!"#$%&'()*(&$#+#,#"*-.
193
Cdlgo 11.13: (rlnclpal.[ava)
System.out.println(l.getCategoria().getDescripcion());

PlbernaLe responder a la llamada al meLodo geLCaLegorla().geLuescrlpclon(), como se
muesLra en la flgura.


vamos a expllcar deLalladamenLe cada uno de los pasos
1. Ln el prlmer paso, el ob[eLo Llbro lnvoca al meLodo geLCaLegorla(), el cul en
prlnclplo nos devuelve un roxyCaLegorla
2. nuesLro ob[eLo llbro lnvoca al meLodo geLuescrlpclon() del roxyCaLegorla.
!"#$%&'(&$") +),)
194
3. Al no esLar llgado a un ob[eLo CaLegorla real slno a un roxyCaLegorla, esLe
reclbe la peLlcln y delega en PlbernaLe.
4. Ll framework PlbernaLe revlsa las relaclones consLruldas y lanza una consulLa de
seleccln que selecclona la caLegorla a la que el llbro perLenece
3. una vez hecho esLo, consLruye un ob[eLo real CaLegorla con los daLos obLenldos
de la base de daLos y lo vlncula al roxyCaLegorla
6. or ulLlmo, el roxyCaLegorla delega la lnvocacln orlglnal del ob[eLo Llbro en la
CaLegorla que se acaba de consLrulr en memorla, devolvlendo la descrlpcln al
Llbro que la sollclL.
LsLa forma de Lraba[ar de PlbernaLe se conoce comunmenLe como carga vaga" o
lazyload, ya que unlcamenLe accede a la base de daLos para obLener lnformacln sobre
las relaclones enLre los ob[eLos cuando la apllcacln cllenLe lo sollclLa y nunca anLes.
S. ke|ac|ones y capa de presentac|n
una vez hecho esLo modlflcaremos el cdlgo de la capa de presenLacln para que se
apoye en el uso de relaclones como se muesLra a conLlnuacln.
Cdlgo 11.16: (rlnclpal.[ava)
<c:forEach var="libro" items="${listaDeLibros}">
${libro.isbn}${libro.titulo}${libro.categoria.descripcion}
<a href="BorrarLibro.do?isbn=${libro.isbn}">borrar</a>
<a href="FormularioEditarLibro.do?isbn=${libro.isbn}">editar</a>
<br />
</c:forEach>

Como podemos ver, ahora usamos !S1L para acceder a la relacln
5{||bro.categor|a.descr|pc|on} una vez reallzada esLa operacln, los daLos de llbros y
caLegorlas se mosLrarn correcLamenLe.
!!!"#$%&'()*(&$#+#,#"*-.
195
Ahora blen, sl revlsamos las consulLas SCL que PlbernaLe ha Lenldo que e[ecuLar,
veremos que pueden ser me[orables .A conLlnuacln se muesLra una lmagen con las
consulLas e[ecuLadas.



Como podemos ver, se reallza una consulLa adlclonal por cada caLegorla que debe
obLener de la base de daLos. Asl pues sl Luvleramos clen caLegorlas se e[ecuLarlan clen
consulLas. Ln esLe caso hublera sldo me[or e[ecuLar una unlca consulLa de Llpo [oln que
obLenga los daLos de las dos Lablas slmulLneamenLe. ara ello vamos a usar la slnLaxls
de PCL para modlflcar la consulLa y de[arla con el slgulenLe cdlgo.
Cdlgo 11.17: (rlnclpal.[ava)
List<Libro> listaDeLibros = session.createQuery("from Libro libro right join fetch
libro.categoria").list();

LsLa clausula rlgLh [oln feLch obllga a PlbernaLe a e[ecuLar una consulLa de [olns enLre
las dos Lablas, cargando Lodos los daLos en una unlca consulLa (ver lmagen).


!"#$%&'(&$") +),)
196
una vez opLlmlzada esLa consulLa, es momenLo de volver a mlrar hacla el cdlgo de
nuesLra apllcacln y modlflcar el meLodo que busca Lodos los llbros para que cargue a
Lraves de un [oln Lodos los daLos en una unlca consulLa. vamos a verlo.
Cdlgo 11.18: (Llbro.[ava)
publicstatic List<Libro> buscarTodos() {
SessionFactory factoriaSession=HibernateHelper.getSessionFactory();
Session session = factoriaSession.openSession();
List<Libro> listaDeLibros = session.createQuery("from Libro libro right join fetch
libro.categoria").list();
session.close();
return listaDeLibros;
}

una vez creada esLa consulLa PCL, modlflcaremos la pglna MosLrarLlbros.[sp para que
se encargue de mosLrar las descrlpclones de las caLegorlas apoyndose en las
relaclones creadas con PlbernaLe y en la consulLa opLlmlzada que acabamos de deflnlr.
A conLlnuacln se muesLra como queda el nuevo bloque de cdlgo.
Cdlgo 11.19: (MosLrarLlbros.[sp)
<c:forEach var="libro" items="${listaDeLibros}">
${libro.isbn}
${libro.titulo}
${libro.categoria.descripcion}
<a href="BorrarLibro.do?isbn=${libro.isbn}">borrar</a>
<a href="FormularioEditarLibro.do?isbn=${libro.isbn}">editar</a>
<br />
</c:forEach>

A conLlnuacln se muesLra el resulLado.
!!!"#$%&'()*(&$#+#,#"*-.
197
!"#$%"&
Ln esLe caplLulo hemos mosLrado como consLrulr un modelo de perslsLencla ms
flexlble consLruyendo relaclones enLre los dlsLlnLos ob[eLos. Aunque hemos aumenLado
la flexlbllldad, Lamblen hemos lncremenLado la comple[ldad a la hora de abordar un
desarrollo, lnLroduclendo caracLerlsLlcas avanzadas de los frameworks de perslsLencla.


!"#$%&'(&$") +),)
198
!"!!"#" %&'()(*&+,& -%.






uuranLe muchos anos en la plaLaforma !2LL han exlsLldo dlsLlnLos frameworks de
perslsLencla como lbaLls, PlbernaLe , 1opLlnk eLc (ver lmagen).

Cada uno de esLos frameworks de perslsLencla ha uLlllzado una fllosofla propla a la hora
de decldlr de que forma se almacena la lnformacln en la base de daLos. ue esLe ampllo
con[unLo de frameworks hay un subcon[unLo que son frameworks C8M (Cb[ecL
8elaLlonal Mapplng) como 1opLlnk y PlbernaLe. Algunos oLros frameworks no pueden
ser lncluldos denLro de esLa caLegorla, caso de l8aLls o Sprlng !u8C, que no reallzan un
mapeo proplamenLe dlcho (ver lmagen).

!!!"#$%&'()*(&$#+#,#"*-.
199

A dla de hoy la plaLaforma !LL se ha encargado de esLandarlzar la capa de perslsLencla a
Lraves de la creacln del esLndar !A (Iava ers|stence AI). LsLe esLndar se ha
basado fundamenLalmenLe en las experlenclas que los dlsLlnLos fabrlcanLes han Lenldo
con los frameworks de C8M, de[ando fuera a aquellos que no lo son. or esa razn
prcLlcamenLe la LoLalldad de los frameworks de C8M soporLan el uso del apl de !A
(ver lmagen).

Asl pues el slgulenLe paso que abordaremos en nuesLra apllcacln ser la mlgracln de
la capa de perslsLencla del uso del Al de PlbernaLe al uso del Al de !A sobre
PlbernaLe. Asl ser prcLlcamenLe LransparenLe mlgrar una apllcacln de un framework
de perslsLencla a oLro como por e[emplo de PlbernaLe a 1opLlnk. LsLo nos aporLar
flexlbllldad a la hora de eleglr fabrlcanLe para nuesLro servldor de apllcaclones.
odemos empezar con una apllcacln lnsLalada en !8oss con PlbernaLe y mlgrarla de
una forma relaLlvamenLe sencllla a WebLoglc con 1opLlnk (ver lmagen).

!"#$%&'(&$") +),)
200

SeguldamenLe se deLallan los ob[eLlvos y Lareas de esLe caplLulo.
Cb[et|vos :
Mlgrar la capa de perslsLencla de nuesLra apllcacln a !A
1areas:
1. lnLroduccln al Al de !A
2. Mlgracln de la apllcacln a !A.
3. Mane[o de Lxcepclones y !A
1. Introducc|n a| AI de IA
LsLa Larea se cenLrra en hacer evoluclonar nuesLra capa de perslsLencla creada con
PlbernaLe a una nueva capa de perslsLencla que delega en PlbernaLe pero se apoya en
el Al de !A para Lraba[ar. Ll Al de !A es muy slmllar al Al de PlbernaLe, ya que el
esLndar de !A se apoy en el exlLo de PlbernaLe como framework para grandes
parLes de su dlseno. A conLlnuacln se expllcan cules son las clases fundamenLales que
usa el Al de !A.
ers|stence: Pace referencla a la conflguracln de !A y es slmllar a la clase
ConflguraLor de PlbernaLe.
Lnt|tyManagerIactory: lacLorla que se encarga de lnlclallzar el framework, su
rol es slmllar al SesslonlacLory de PlbernaLe que hemos uLlllzado en caplLulos
anLerlores.
Lnt|tyManager: Clase que se encarga de gesLlonar la perslsLencla de un
con[unLo de enLldades slmllar al ob[eLo Sesslon del Al de PlbernaLe.
Lnt|ty1ransact|on: Clase que se encarga de deflnlr el concepLo de Lransaccln,
slmllar a 1ransacLlon en PlbernaLe.
!!!"#$%&'()*(&$#+#,#"*-.
201
1ypeduery: ldenLlflca una consulLa deflnlda con !CL (!ava erslsLence Cuery
Language) slmllar a la clase Cuery de PlbernaLe con la unlca salvedad que
soporLa el uso de generlcos.
ers|stence.xm|: llchero que reemplaza al flchero clslco de PlbernaLe
PlbernaLe.cfg.xml" y que conLlene Lodos los parmeLros necesarlos para
conecLarnos conLra un servldor de base de daLos.
una vez expllcadas las clases prlnclpales, vamos a ver un e[emplo senclllo de cmo el
apl de !A se encarga de buscar Lodos los llbros de nuesLra apllcacln a Lraves de un
programa de consola.
Cdlgo 12.1: (rlnclpal.[ava)
public static void main (String args[]) {
EntityManagerFactory emf=
Persistence.createEntityManagerFactory("arquitecturaJava");
EntityManager em=emf.createEntityManager();
TypedQuery<Libro> consulta= em.
createQuery("Select l from Libro l",Libro.class);
List<Libro> lista= consulta.getResultList();
for(Libro l: lista) {
System.out.println(l.getTitulo());
}
}

Como podemos ver, el cdlgo es muy slmllar al usado en PlbernaLe. vamos a
comenLarlo llnea a llnea.
Cdlgo 12.2: (rlnclpal.[ava)
EntityManagerFactory
emf=Persistence.createEntityManagerFactory("arquitecturaJava");

LsLa parLe del cdlgo se encarga de crear un LnLlLyManagerlacLory, que es el ob[eLo
que lnlclallza Lodo lo necesarlo para que el esLndar de !A pueda Lraba[ar. ara ello se
apoyar en el flchero perslsLence.xml, que se muesLra a conLlnuacln. LsLe flchero se
encuenLra ublcado en el dlrecLorlo ML1A-lnl de nuesLra apllcacln (ver lmagen).
!"#$%&'(&$") +),)
202

A conLlnuacln se muesLra el conLenldo de esLe flchero.
Cdlgo 12.3: (perslsLence.xml)
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
<persistence-unit name="arquitecturaJava">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.arquitecturajava.aplicacion.bo.Libro</class>
<class>com.arquitecturajava.aplicacion.bo.Categoria</class>
<properties>
<property name="hibernate.show_sql" value="true"/>
<property name="javax.persistence.transactionType"
value="RESOURCE_LOCAL" />
<property name="javax.persistence.jdbc.driver"
value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url"
value="jdbc:mysql://localhost/arquitecturaJavaORM" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="java" />
<property name="hibernate.dialect"
value="org.hibernate.dialect.MySQL5Dialect" />
</properties>
</persistence-unit>
</persistence>


!!!"#$%&'()*(&$#+#,#"*-.
203
Como podemos ver el flchero es muy slmllar al flchero clslco de conflguracln del
framework PlbernaLe .una vez conflgurado, ya podemos comenzar a usar !A. Ls
momenLo hablar del el ob[eLo LnLlLyManager (ver cdlgo).
Cdlgo 12.4: (rlnclpal.[ava)
EntityManager em=emf.createEntityManager();

LsLe ob[eLo es el encargado de gesLlonar el clclo de vlda de las enLldades y es capaz
LanLo de guardar ob[eLos en la base de daLos como de selecclonarlos a Lraves de la
creacln de consulLas !CL (!ava erslsLence Cuery Language), como se muesLra en la
slgulenLe llnea.
Cdlgo 12.3: (rlnclpal.[ava)
TypedQuery<Libro> consulta= em.
createQuery("Select l from Libro l",Libro.class);
List<Libro> lista= consulta.getResultList();

una vez creada la consulLa lnvocados al meLodo geL8esulLLlsL() que nos devuelve una
llsLa de Llbros generlca. or ulLlmo slmplemenLe recorremos la llsLa y presenLamos por
consola el LlLulo de cada llbro.
Cdlgo 12.6: (rlnclpal.[ava)
for(Libro l: lista) {
System.out.println(l.getTitulo());
}

Como complemenLo al e[emplo anLerlor, vamos a ver un e[emplo en el cual usamos !A
para perslsLlr un ob[eLo en la base de daLos.





!"#$%&'(&$") +),)
204
Cdlgo 12.7: (rlnclpal.[ava)
public static void main(String[] args) {
EntityManagerFactory emf=
Persistence.createEntityManagerFactory("arquitecturaJava");
EntityManager manager = emf.createEntityManager();
Libro libro= new Libro ("2","java","programacion");
EntityTransaction tx = null;
tx=manager.getTransaction();
tx.begin();
manager.merge(libro);
tx.commit();
manager.close();
}
}

Como podemos ver, aparece un nuevo Llpo de Cb[eLo LnLlLy1ransacLlon que se encarga
de e[ecuLar Lransacclones sobre !A .La unlca dlferencla con el e[emplo anLerlor es que
usamos el meLodo merge () de la clase LnLlLyManager para guardar el ob[eLo en la base
de daLos , meLodo que es slmllar al saveCrupdaLe que en caplLulos anLerlores usamos
para PlbernaLe.
2. M|grac|n de Ap||cac|n a IA
vlsLa una lnLroduccln al apl de !A, vamos a mlgrar nuesLra apllcacln al uso de !A.
ara ello consLrulremos, como hlclmos en el caso de PlbernaLe, una clase Pelper que
nos ayude a Lraba[ar con el Al de !A , a conLlnuacln se muesLra su cdlgo fuenLe.
Cdlgo 12.8: (!APelper.[ava)
package com.arquitecturajava.aplicacion;
//omitimos imports
public class JPAHelper {
private static final EntityManagerFactory emf = buildEntityManagerFactory();
private static EntityManagerFactory buildEntityManagerFactory() {
try {
return Persistence.createEntityManagerFactory("arquitecturaJava");
}catch (Throwable ex) {
throw new RuntimeException("Error al crear la factoria de JPA");
}}
public static EntityManagerFactory getJPAFactory() {
return emf;}
}

!!!"#$%&'()*(&$#+#,#"*-.
205
una vez consLrulda la clase helper y deflnldo el flchero perslsLence.xml, podemos
modlflcar nuesLra apllcacln y que nuesLras clases de negoclo uLlllcen el Al de !A de
forma sencllla. A conLlnuacln se muesLra el cdlgo fuenLe de la clase Llbro una vez
mlgrada a !A ,el cdlgo de la clase CaLegorla es muy slmllar.
Cdlgo 12.9: (CaLegorla.[ava)
package com.arquitecturajava.aplicacion;
import java.util.List;
// imports omitidos
@Entity
@Table(name = "Libros")
public class Libro {
// omlLlmos propledades
publlc vold lnserLar() [
EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
EntityTransaction tx = null;
tx = manager.getTransaction();
tx.begin();
manager.persist(this);
tx.commit();

}
public void borrar() {

EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
EntityTransaction tx = null;
tx = manager.getTransaction();
tx.begin();
manager.remove(manager.merge(this));
tx.commit();
manager.close();
}
public void salvar() {

EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
EntityTransaction tx = null;
tx = manager.getTransaction();
tx.begin();
manager.merge(this);
tx.commit();
manager.close();
}

!"#$%&'(&$") +),)
206
public static List<Libro> buscarTodos() {

EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
TypedQuery<Libro> consulta = manager.createQuery(
"SELECT l FROM Libro l JOIN FETCH l.categoria",
Libro.class);
List<Libro> listaDeLibros = null;
listaDeLibros = consulta.getResultList();
manager.close();
return listaDeLibros;
}

public static Libro buscarPorClave(String isbn) {

EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
TypedQuery<Libro> consulta = manager.createQuery(
"Select l from Libro l JOIN FETCH l.categoria where l.isbn=?1",
Libro.class);
consulta.setParameter(1, isbn);
Libro libro = null;
libro = consulta.getSingleResult();
manager.close();
return libro;
}

public static List<Libro> buscarPorCategoria(Categoria categoria) {
EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
TypedQuery<Libro> consulta = manager.createQuery(
"Select l from Libro l where l.categoria=?1",
Libro.class);
consulta.setParameter(1, categoria);
List<Libro> listaDeLibros = null;
listaDeLibros = consulta.getResultList();
manager.close();
return listaDeLibros;
}
}

Acabamos de mlgrar los meLodos de perslsLencla de la clase Llbro al sLandard !A. La
slgulenLe Larea se LraLar de abordar oLro Lema que Lenlamos pendlenLe: la gesLln de
excepclones a nlvel de capa de perslsLencla.
!!!"#$%&'()*(&$#+#,#"*-.
207
3. Mane[o de Lxcepc|ones
Ln esLos momenLos sl en alguna ocasln una consulLa produce una excepcln, no se
garanLlza que las conexlones, senLenclas eLc. se clerren correcLamenLe y por lo LanLo
podemos acabar Lenlendo problemas. Ln esLa Larea vamos a encargarnos de modlflcar
los meLodos de la capa de perslsLencla para que se encarguen de una correcLa gesLln
de excepclones. ara ello comenzaremos modlflcando el meLodo borrar de la clase llbro
anadlendole las clusulas Lry/caLch/flnally necesarlas. SeguldamenLe se muesLra su
cdlgo.
Cdlgo 12.10: (Llbro.[ava)
public void borrar() {
EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
EntityTransaction tx = null;
try {
tx=manager.getTransaction();
tx.begin();
manager.remove(manager.merge(this));
tx.commit();
} catch (PersistenceException e) {
manager.getTransaction().rollback();
throw e;
} finally {
manager.close();
}

Como podemos ver, el mane[o de excepclones es muy slmllar al cdlgo que
anLerlormenLe se albergaba a nlvel de !u8C y no vamos a comenLarlo con ms deLalle.
A conLlnuacln se muesLra como complemenLarlo el meLodo busca1odos() como
meLodo de seleccln .






!"#$%&'(&$") +),)
208
Cdlgo 12.11: (Llbro.[ava)
public static List<Libro> buscarTodos() {
EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
TypedQuery<Libro> consulta = manager.createQuery(
"SELECT l FROM Libro l JOIN FETCH l.categoria",
Libro.class);
List<Libro> listaDeLibros = null;
try {
listaDeLibros = consulta.getResultList();
} finally {
manager.close();
}
return listaDeLibros;
}

Asl, el cdlgo es slmllar, con la unlca dlferencla que no uLlllzamos clusula caLch ya que
no es necesarlo reallzar un rollback de nlnguna excepcln. Ll mlsmo cdlgo hublera sldo
necesarlo en PlbernaLe, pero hemos preferldo obvlarlo y cenLrarnos en !A.
!"#$%"&
Ln esLe caplLulo no hemos reallzado grandes camblos a nlvel de la arqulLecLura de la
apllcacln pero sl en cuanLo a cmo se lmplemenLa la capa de perslsLencla uLlllzando
!A como sLandard.










!!!"#$%&'()*(&$#+#,#"*-.
209

!"#$%&'(&$") +),)
210
!"!"# %&'()'%'* +,- . /# %01&2( 345





Ln el caplLulo anLerlor hemos hecho evoluclonar nuesLra apllcacln para que soporLe el
esLndar de !A. Ls momenLo de segulr progresando en su dlseno. ara esLo, es
necesarlo sallr momenLneamenLe del enLorno web a fln de poder expllcar algunos
nuevos concepLos. vamos a suponer que nuesLra apllcacln neceslLa de un nuevo
mdulo que se encargue de leer una llsLa de llbros almacenada en un flchero de LexLo.
La esLrucLura del flchero es la slgulenLe:
1,Java,1,Programacin
2,JSP ,2, Web

Ln prlnclplo consLrulr un programa para leer esLos daLos e lmprlmlr la llsLa de llbros
por consola es senclllo, Lenemos adems consLruldas las clases de negoclo que se
adapLan a esLos daLos.
Llbro
CaLegorla
Asl pues vamos a consLrulr un nuevo proyecLo !ava que denomlnaremos LeerLlbros
usando ecllpse (proyecLo [ava sLandard) que use nuesLras clases de negoclo .A
conLlnuacln se muesLra una lmagen de los elemenLos requerldos.

!!!"#$%&'()*(&$#+#,#"*-.
211

una vez lmporLadas esLas clases, nos percaLamos de que no es poslble Lraba[ar con
ellas de forma dlrecLa sln lnclulr la clase !APelper, asl pues anadlmos esLa clase a
nuesLro proyecLo. uespues esLaremos Lamblen obllgados a anadlr la llbrerla de
PlbernaLe y !A, ya que nuesLras clases hacen uso de anoLaclones de esLe Llpo. Asl
pues nuesLras clases Llbro y caLegorla Llenen las slgulenLes dependenclas.
!APelper (Clase)
PlbernaLe-[pa.2.0 (Llbrerla)
vamos a ver el cdlgo fuenLe del programa que se encarga de leer la llsLa de llbros:
Cdlgo 13.1: (rlnclpal.[ava)
public class Principal {
public static void main(String[] args) throws IOException {

String texto="";
Reader l= new FileReader("libros.txt");
BufferedReader lector= new BufferedReader(l);
List<Libro> lista= new ArrayList<Libro>();
Libro libro=null;
Categoria categoria=null;
while ((texto=lector.readLine())!=null ){
String[] datos= texto.split(",");
categoria= new Categoria(Integer.parseInt(datos[2]),datos[3]);
libro = new Libro(datos[0],datos[1],categoria);
lista.add(libro);
}
for(Libro l1 :lista) {
System.out.println(l1.getTitulo());
}
}
}

!"#$%&'(&$") +),)
212
Ll programa es muy senclllo: lee el flchero, lo recorre llnea a llnea, crea una nueva llsLa
de llbros la cul flnalmenLe recorre e lmprlme por panLalla. Ahora blen: van a aparecer
algunos problemas. Ln prlmer lugar nuesLro programa no neceslLa para nada nlnguno
de los meLodos de perslsLencla de la clase Llbro o de la clase CaLegorla, nl mucho
menos hace uso de la clase !APelper y de las llbrerlas de !A. Sln embargo, no
Lenemos ms remedlo que lmporLarlas a nuesLro proyecLo. LsLo claramenLe no Llene
nlngun senLldo .vamos a cenLrar el ob[eLlvo de esLe caplLulo en solvenLar esLe Llpo de
problemas .ara ello vamos a lnLroduclr oLro prlnclplo denomlnado prlnclplo lS o
lnLerface SegregaLlon rlnclple cuya deflnlcln se muesLra seguldamenLe:
IS : una clase cllenLe A que Llene una dependencla con la clase 8 no debe
verse forzada a depender de meLodos de la clase 8 que no vaya a usar [ams.
Ln nuesLro caso parece claro que Lenemos un problema relaLlvo a esLe prlnclplo, ya que
nuesLra clase cllenLe (clase rlnclpal) depende de meLodos que nunca va a uLlllzar.
MeLodos que esLn en la clase llbro, concreLamenLe los relaLlvos al uso de perslsLencla,
como se muesLra en la flgura.

Asl, nos enconLramos con un problema de dlseno en el cul no hemos apllcado el
prlnclplo lS, como se muesLra en la slgulenLe flgura.

!!!"#$%&'()*(&$#+#,#"*-.
213

Pe aqul los ob[eLlvos del presenLe caplLulo:
!"#$%&'() !
Apllcar el prlnclplo lS a la capa de erslsLencla.
1areas:
1. Crear las clases LlbrouAC y ersonauAC que cumplan con el prlnclplo lS
2. uso de lnLerfaces a nlvel uAC para permlLlr varlas lmplemenLaclones
3. Creacln de uACs Cenerlcos
4. 8endlmlenLo

1. Crear |as c|ases L|broDAC y Categor|aDAC.
vamos a usar a conLlnuacln el prlnclplo lS para ellmlnar dependenclas enLre la clase
Maln (cllenLe) y los meLodos de la clase Llbro. ara ello la clase Llbro exLernallzar
Lodos los meLodos de perslsLencla a una nueva clase denomlnada LlbrouAC. uAC( uaLa
Access Cb[ecL) hace referencla a un paLrn de dlseno de la capa de perslsLencla que se
encarga de cumpllr con el prlnclplo lS y separar las responsabllldades de negoclo y
perslsLencla. Asl pues, la clase Llbro se encargar de los meLodos seL/geL (negoclo) y la
clase LlbrouAC de Lodos los meLodos de perslsLencla (lnserLar/borrar eLc.). A
conLlnuacln se muesLra una flgura aclaraLorla:
!"#$%&'(&$") +),)
214

una vez creadas las nuevas clases, se ublcaran en un nuevo paqueLe de la apllcacln
denomlnado uAC (ver lmagen).

Acabamos de separar los meLodos de nuesLra clase Llbro en dos clases lndependlenLes
cada una de las cules se encarga de una deLermlnada funclonalldad. Pemos apllcado el
prlnclplo lS, ya que era el que de forma ms dlrecLa enca[aba .lgualmenLe podrlamos
haber apllcado el prlnclplo S8 (Slmple 8esponsablllLy rlnclple) ya que Lamblen
esLamos separando las dlsLlnLas responsabllldades de muesLra clase. Ll hecho de que
dos prlnclplos enca[en con el refacLorlng que deseamos apllcar a nuesLro cdlgo nos
ayuda a forLalecer la ldea de que podemos obLener una solucln me[or.
lrecuenLemenLe el ver que dos prlnclplos de lngenlerla nos orlenLan hacla la mlsma
!!!"#$%&'()*(&$#+#,#"*-.
215
solucln refuerza el concepLo de que los refacLorlngs van en la dlreccln adecuada.
Ahora nuesLro programa rlnclpal unlcamenLe depender de la clase Llbro, como se
muesLra en la flgura y no Lendr necesldad de usar nada de la capa de perslsLencla.

uespues de Lener claro cmo dlvldlr las clases, vamos a ver deLalladamenLe cmo
queda el cdlgo fuenLe de la clase Llbro asl como el de la clase LlbrouAC.
Cdlgo 13.2: (Llbro.[ava)
@Entity
@Table(name = "Libros")
public class Libro {
@Id
private String isbn;
private String titulo;
@ManyToOne
@JoinColumn(name = "categoria")
private Categoria categoria;
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitulo() {
return titulo;
}
public void setTitulo(String titulo) {
this.titulo = titulo;
}
public Categoria getCategoria() {
return categoria;
}
publicvoid setCategoria(Categoria categoria) {
this.categoria = categoria;
} //omitimos constructores
}
!"#$%&'(&$") +),)
216

A continuacin se muestra el codigo de la clase LibroDAO:
Cdlgo 13.3: (LlbrouAC.[ava)
public class LibroDAO {
public void insertar(Libro libro) {
EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
EntityTransaction tx = null;
try {
tx=manager.getTransaction();
tx.begin();
manager.merge(libro);
tx.commit();
} catch (PersistenceException e) {
manager.getTransaction().rollback();
throw e;
} finally {
manager.close();
}
}
public void borrar(Libro libro) {
EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
EntityTransaction tx = null;
try {
tx=manager.getTransaction();
tx.begin();
manager.remove(manager.merge(libro));
tx.commit();
} catch (PersistenceException e) {
manager.getTransaction().rollback();
throw e;
} finally {
manager.close();
}}
public void salvar(Libro libro) {
EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
EntityTransaction tx = null;
try {
tx=manager.getTransaction();
tx.begin();
manager.merge(libro);
tx.commit();
} catch (PersistenceException e) {
manager.getTransaction().rollback();
throw e;
!!!"#$%&'()*(&$#+#,#"*-.
217
} finally {
manager.close();
}
}
public List<Libro> buscarTodos() {
EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
TypedQuery<Libro> consulta = manager.createQuery(
"Select l from Libro l", Libro.class);
List<Libro> listaDeLibros = null;
try {
listaDeLibros = consulta.getResultList();
} finally {
manager.close();
}
return listaDeLibros;
}
public Libro buscarPorClave(String isbn) {

EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
TypedQuery<Libro> consulta = manager.createQuery(
"Select l from Libro l where l.isbn=?1", Libro.class);
consulta.setParameter(1, isbn);
Libro libro = null;
try {
libro = consulta.getSingleResult();
} finally {
manager.close();
}
return libro;
}
public List<Libro> buscarPorCategoria(Categoria categoria) {
EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
TypedQuery<Libro> consulta = manager.createQuery(
"Select l from Libro l where l.categoria=?1", Libro.class);
consulta.setParameter(1, categoria);
List<Libro> listaDeLibros = null;
try {
listaDeLibros = consulta.getResultList();
} finally {
manager.close();
}
return listaDeLibros;
}
}

!"#$%&'(&$") +),)
218
Ll cdlgo fuenLe de ambas clases es prcLlcamenLe ldenLlco a lo que Lenlamos anLes de
separarlas, excepLuando que los meLodos de la clase LlbrouAC reclben ahora como
parmeLros Llbros y han de[ado de ser esLLlcos. una vez vlsLo esLe refacLorlng, vamos
a ver como quedarla el cdlgo en nuesLras acclones, a conLlnuacln mosLramos una de
ellas.
Cdlgo 13.4: MosLrarLlbroAcclon.[ava)
@Override
public String ejecutar(HttpServletRequest request,
HttpServletResponse response) {
LibroDAO libroDAO = new LibroDAO();
CategoriaDAO categoriaDAO = new CategoriaDAO();
List<Libro> listaDeLibros = libroDAO.buscarTodos();
List<Categoria> listaDeCategorias =
!!!!!!!categoriaDAO.buscarTodos();
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);
return "MostrarLibros.jsp";
}

Pemos Lermlnado de apllcar el prlnclplo lS a nuesLra apllcacln. SeguldamenLe
avanzaremos en el dlseno de la capa uAC para aporLar flexlbllldad.
2. Uso de |nterfaces en componentes DAC
Acabamos de separar de forma clara la capa de perslsLencla de la capa de negoclo en
nuesLra apllcacln. Ln esLos momenLos la capa de perslsLencla esLa consLrulda con !A
pero en e[emplos anLerlores ha esLado consLrulda con PlbernaLe o con !u8C .Asl pues
hemos Lenldo una evolucln en cuanLo a cmo consLrulmos esLa capa de perslsLencla
(ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
219
Muchas apllcaclones enLerprlse Llenen un Llempo de vlda ampllo. Ls hablLual que la
capa de perslsLencla evoluclone con el paso del Llempo y de las verslones de la
apllcacln. Asl pues, es lnLeresanLe dlsenar esLa capa de forma que, en caso de mlgrar
de !u8C a PlbernaLe o de PlbernaLe a !A, los camblos a reallzar en el cdlgo sean los
mlnlmos poslbles. Asl pues vamos a consLrulr un lnLerface LlbrouAC y un lnLerface
CaLegorlauAC de los cules se puedan generar varlas lmplemenLaclones (ver
lmagen).

ara poder generar esLos lnLerfaces hay que redlsenar el con[unLo de paqueLes que
esLamos uLlllzando .A parLlr de ahora usaremos los slgulenLes en cuanLo a capa de
perslsLencla:
com.arqu|tectura[ava.dao : aqueLe que conLlene unlcamenLe los lnLerfaces
uAC
com.arqu|tectura[ava.dao.[pa: aqueLe que conLlene la lmplemenLacln para
!A.

!"#$%&'(&$") +),)
220
vamos a ver a conLlnuacln una lmagen que clarlflca la esLrucLura.
una vez clara la esLrucLura de la capa de perslsLencla, vamos a ver el cdlgo fuenLe de
uno de esLos lnLerfaces, concreLamenLe el lnLerface LlbrouAC, el caso del lnLerface
CaLegorlauAC es muy slmllar.
Cdlgo 13.3: (LlbrouAC.[ava)
package com.arquitecturajava.aplicacion.dao;
import java.util.List;
import com.arquitecturajava.aplicacion.bo.Categoria;
import com.arquitecturajava.aplicacion.bo.Libro;

public interface LibroDAO {

public abstract void borrar(Libro libro);
public abstract void salvar(Libro libro);
public abstract List<Libro> buscarTodos();
public abstract Libro buscarPorClave(String isbn);
public abstract List<Libro> buscarPorCategoria(Categoria categoria);
}

una vez creado el lnLerface podemos hacer que nuesLra clase LlbrouAC!Almpl
lmplemenLe el lnLerface.
Cdlgo 13.6: (LlbrouAC!Almpl.[ava)
public class LibroDAOJPAImpl implements LibroDAO {
// el resto del codigo no varia
}

!!!"#$%&'()*(&$#+#,#"*-.
221
Con esLa Larea hemos ganado en flexlbllldad a la hora de poder evoluclonar nuesLra
apllcacln de una forma sencllla enLre un slsLema de perslsLencla y oLro. Ls momenLo
de revlsar la esLrucLura de nuesLras clases uAC referenLes a !A
(LlbrouAC!Almpl,CaLegorlauAC!Almpl) para que nos demos cuenLa de que Lodas
ellas comparLen la mlsma esLrucLura lncluso sl anadlmos nuevas clases (ver lmagen).

LsLe es un claro slnLoma de que qulzs nuesLras clases de perslsLencla no cumplen del
Lodo con el prlnclplo u8? y mucha funclonalldad esL repeLlda. La slgulenLe Larea se
encargar de abordar esLe problema.
3. L| pr|nc|p|o Dk y e| patrn Gener|cDAC
Ln prlmer lugar vamos a dlsenar un nuevo lnLerface que lncluya las funclones que sern
comparLldas por Lodas las clases de forma ldenLlca (borrar, salvar, buscarorClave,
buscar1odos). ara ello vamos a consLrulr un lnLerface dlsLlnLo a los anLerlores, ya que
se LraLar de un lnLerface de Llpo Cenerlco de Lal forma que sean luego ms adelanLe
cada una de las clases las que deflnan a que Llpo hace referencla .vamos a ver un
dlagrama aclaraLorlo:
!"#$%&'(&$") +),)
222

una vez Lenemos claro cul es el lnLerface deflnldo como generlco, vamos a ver su
cdlgo.
Cdlgo 13.7: (CenerlcuAC.[ava)
package com.arquitecturajava.aplicacion.dao;

import java.io.Serializable;
import java.util.List;
public interface GenericDAO<T,Id extends Serializable> {
T buscarPorClave (Id id);
List<T>buscarTodos();
void salvar(T objeto);
void borrar(T objeto);
}

Creada esLe lnLerface, consLrulremos una clase Cenerlca que lmplemenLe el lnLerface
lmplemenLando los meLodos de forma generlca (ver lmagen).

!!!"#$%&'()*(&$#+#,#"*-.
223


Al hacer uso de generlcos podremos ellmlnar una gran parLe de la repeLlcln de cdlgo
que Lenemos en nuesLras clases uAC de !A .A conLlnuacln se muesLra la clase
compleLa con Lodos sus meLodos.







!"#$%&'(&$") +),)
224
Cdlgo 13.8: (CenerlcuAC!Almpl)
//omitimos imports etc
public abstract class GenericDAOJPAImpl<T, Id extends Serializable> implements
GenericDAO<T, Id> {
private Class<T> claseDePersistencia;
@SuppressWarnings("unchecked")
public GenericDAOJPAImpl() {
this.claseDePersistencia = (Class<T>) ( (ParameterizedType)
getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
@Override
public T buscarPorClave(Id id) {
EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
T objeto = null;
try {
objeto = (T) manager.find(claseDePersistencia, id);
return objeto;
} finally {
manager.close();
}
}
@Override
public List<T> buscarTodos() {

EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
List<T> listaDeObjetos = null;
try {

TypedQuery<T> consulta = manager.createQuery("select o from "
+ claseDePersistencia.getSimpleName()+ " o",
claseDePersistencia);

listaDeObjetos = consulta.getResultList();
return listaDeObjetos;
} finally {
manager.close();
}
}
public void borrar(T objeto) {

EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
EntityTransaction tx = null;
try {
tx = manager.getTransaction();
tx.begin();
manager.remove(manager.merge(objeto));
!!!"#$%&'()*(&$#+#,#"*-.
225
tx.commit();
} catch (PersistenceException e) {
tx.rollback();
throw e;
} finally {
manager.close();
}
}
public void salvar(T objeto) {
EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
EntityTransaction tx = null;
try {
tx = manager.getTransaction();
tx.begin();
manager.merge(objeto);
tx.commit();
} catch (PersistenceException e) {
tx.rollback();
throw e;
} finally {
manager.close();
}
}
public void insertar(T objeto) {
EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
EntityTransaction tx = null;
try {
tx = manager.getTransaction();
tx.begin();
manager.persist(objeto);
tx.commit();
} catch (PersistenceException e) {
tx.rollback();
throw e;
} finally {
manager.close();
}
}
}

Ll cdlgo de esLa clase genera las operaclones de perslsLencla elemenLales para Lodas
las clases uAC. or lo LanLo no es necesarlo lmplemenLar esLos meLodos en las clases
hl[as.,ya que sl esLas clases exLlenden de la clase CenerlcuAC!Almpl es suflclenLe. A
conLlnuacln se muesLra una lmagen aclaraLorla.

!"#$%&'(&$") +),)
226



una vez que Lenemos claro como la clase CenerlcuAC!Almpl nos ayuda en el
desarrollo de nuesLra apllcacln, es momenLo de ver el cdlgo fuenLe de la clase
Llbro!Almpl y de la Clase CaLegorla!Almpl para ver como quedan slmpllflcadas.


!!!"#$%&'()*(&$#+#,#"*-.
227
Cdlgo 13.9: (LlbrouAC!Almpl.[ava)
package com.arquitecturajava.aplicacion.dao.jpa;

public class LibroDAOJPAImpl extends GenericDAOJPAImpl<Libro, String>
implements LibroDAO {

public List<Libro> buscarPorCategoria(Categoria categoria) {
EntityManagerFactory factoriaSession = JPAHelper.getJPAFactory();
EntityManager manager = factoriaSession.createEntityManager();
CategoriaDAO cdao= new CategoriaDAOJPAImpl();

TypedQuery<Libro> consulta = manager.createQuery(
"Select l from Libro l where l.categoria=?1",
Libro.class);
consulta.setParameter(1, categoria);
List<Libro> listaDeLibros = null;
try {
listaDeLibros = consulta.getResultList();
} finally {
manager.close();
}
return listaDeLibros;
}



Cdlgo 13.10: (CaLegorlauAC!lmpl.[ava)
package com.arquitecturajava.aplicacion.dao.jpa;

import com.arquitecturajava.aplicacion.bo.Categoria;
import com.arquitecturajava.aplicacion.dao.CategoriaDAO;

public class CategoriaDAOJPAImpl extends GenericDAOJPAImpl<Categoria,
Integer> implements CategoriaDAO {
//no hay nada que aadir todo lo aporta la clase GenericDAO de la cual extendemos
}

Como podemos ver, el caso de la clase CaLegorlauAClmpl es el ms exagerado de Lodos
ya que la clase generlca conslgue ellmlnar Lodos los meLodos que Lenla e lncluso anadlr
algunos que nos podrn ser uLlles. 1ras consLrulr esLas clases, podemos ver como
queda la esLrucLura de clases de perslsLencla en nuesLro proyecLo.

!"#$%&'(&$") +),)
228

4. kend|m|ento
Ln muchos casos el uso bslco de PlbernaLe acaba en soluclones cuya escalabllldad es
reduclda, no por el uso del framework slno por la falLa de conoclmlenLo por parLe del
desarrollador . lrecuenLemenLe nuesLro modelo de clases deber sobreescrlblr
meLodos para me[orar el rendlmlenLo del framework C8M. A conLlnuacln se muesLra
un e[emplo senclllo donde se sobrecarga el meLodo buscar1odos para obLener un
me[or rendlmlenLo.
Cdlgo 13.10: (LlbrouAC!Almpl.[ava)
public List<Libro> buscarTodos() {

TypedQuery<Libro> consulta = getManager().createQuery("SELECT l FROM Libro l
JOIN FETCH l.categoria",Libro.class);
return consulta.getResultList();

}
!"#$%"&
Ln esLe caplLulo hemos vlsLo cmo el prlnclplo lS y el prlnclplo S8 nos orlenLan hacla
el dlseno de una capa de perslsLencla ms flexlble mlenLras que el prlnclplo u8? y el uso
de Cenerlcos nos permlLe ellmlnar mucha funclonalldad repeLlda enLre las dlsLlnLas
clases que deflnen la capa uAC. or ulLlmo, hemos revlsado brevemenLe Lemas de
rendlmlenLo.




!!!"#$%&'()*(&$#+#,#"*-.
229






















!"#$%&'(&$") +),)
230
!"!"# !"#$%#!#& () #$*)"+#,$ () %&$-"&. /
!"#$%& (")#*$+








Ln el caplLulo anLerlor hemos apllcado el prlnclplo lS y con el hemos consLruldo una
capa de perslsLencla basada en el paLrn uAC. LsLo nos ha permlLldo separar las
responsabllldades de negoclo y perslsLencla .Ln esLe caplLulo vamos a modlflcar la capa
de perslsLencla para que no solo admlLa varlos slsLemas de perslsLencla
([dbc,hlbernaLe,[pa) a Lraves del uso de lnLerfaces, slno para que adems sea senclllo o
LransparenLe camblar unas lmplemenLaclones por oLras. Ln esLos momenLos
dlsponemos de dos poslbles lmplemenLaclones de capa de perslsLencla: una basada en
PlbernaLe y oLra basada en PlbernaLe sobre !A. A conLlnuacln se muesLra cmo
hemos hecho evoluclonar el cdlgo en el caplLulo anLerlor.


!!!"#$%&'()*(&$#+#,#"*-.
231
Ahora blen, para reallzar esLos camblos no nos ha quedado ms remedlo que modlflcar
el cdlgo fuenLe de nuesLras Acclones. Sl en algun momenLo qulsleramos reallzar el
proceso lnverso, Lendrlamos que volver a camblar esLas. LsLo se debe a que la
responsabllldad sobre el Llpo de ob[eLo de perslsLencla para consLrulr recae en el
programador y en el cdlgo que el consLruye en las dlferenLes acclones (ver lmagen).

Sl en algun momenLo queremos camblar de Llpo de perslsLencla, ser el programador
qulen deber reallzar los camblos. LsLe dlseno no cumple con el prlnclplo CC ya que sl
queremos camblar la capa de perslsLencla, nos veremos obllgados a modlflcar el cdlgo
que prevlamenLe hemos consLruldo. Ln esLe caplLulo vamos a lnLroduclr un nuevo
prlnclplo de lngenlerla: e| pr|nc|p|o de Invers|n de Contro| que nos ayudar a
solvenLar esLe problema y permlLlr que nuesLra capa de perslsLencla pueda
evoluclonar cumpllendo con CC. vamos a expllcar esLe prlnclplo.
Invers|n de Contro| (Invers|on of Contro| o ICC): Ll prlnclplo de lnversln de
conLrol conslsLe en que el conLrol de la consLruccln de los ob[eLos no recae
dlrecLamenLe en el desarrollador a Lraves del uso del operador new, slno que
es oLra clase o con[unLo de clases las que se encargan de consLrulr los ob[eLos
que neceslLamos. Aunque la deflnlcln es de enLrada algo confusa, duranLe el
resLo del caplLulo la lremos clarlflcando a Lraves de la creacln de e[emplos.
Objetivos :
Apllcar el prlnclplo de lnversln de conLrol lCC a la capa de perslsLencla de
nuesLra apllcacln.

!"#$%&'(&$") +),)
232
Tareas :
1. Crear facLorlas e lmplemenLar el prlnclplo de lCC.
2. Ll prlnclplo u8? y el paLrn AbsLracL lacLory.
3. Ll paLrn AbsLracL lacLory y el uso de lnLerfaces.
1. Crear Iactor|as e |mp|ementar e| pr|nc|p|o de ICC,
ara lmplemenLar el prlnclplo de lCC en nuesLra apllcacln debemos anadlrle nuevas
clases que se encarguen de consLrulr los dlsLlnLos ob[eLos de la capa de perslsLencla .
Como punLo de parLlda vamos a revlsar el cdlgo fuenLe de una de nuesLras acclones
para ver cmo consLruye los dlsLlnLos ob[eLos de la capa uAC.
LlbrouAC!Almpl
CaLegorlauAC!Almpl.
A conLlnuacln se muesLra el cdlgo fuenLe de la clase MosLrarLlbrosAcclon.
Cdlgo 14.1: (MosLrarLlbrosAcclon.[ava)
public String ejecutar(HttpServletRequest request,
HttpServletResponse response) {

LibroDAO libroDAO = new LibroDAOJPAImpl();
CategoriaDAO categoriaDAO = new CategoriaDAOJPAImpl();
List<Libro> listaDeLibros = libroDAO.buscarTodos();
List<Categoria> listaDeCategorias = categoriaDAO.buscarTodos();
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);
return "MostrarLibros.jsp";

}

Como podemos ver, es responsabllldad del programador que desarrolla la apllcacln el
crear cada uno de los dlsLlnLos ob[eLos de la capa uAC. Segun la deflnlcln del prlnclplo
de lnversln de conLrol, no ser a parLlr de ahora el programador el que consLruya los
dlsLlnLos de ob[eLos de la capa de perslsLencla, slno que se encargar oLra clase. vamos
a ver el cdlgo fuenLe de la clase LlbrouAClacLory que serla la encargada de crear los
ob[eLos de Llpo LlbrouAC.


!!!"#$%&'()*(&$#+#,#"*-.
233
Cdlgo 14.2: (LlbrouAC.[ava)
public class LibroDAOFactory {
public static LibroDAO getInstance() {
String tipo = "JPA";
if (tipo.equals("Hibernate")) {
return LibroDAOHibernateImpl();
} else {
returnnew LibroDAOJPAImpl();
}
}
}

Como el cdlgo muesLra, esLa clase Llene la responsabllldad de consLrulr las dlsLlnLas
lmplemenLaclones que exlsLan del lnLerface LlbrouAC (ver lmagen).


ue esLa manera y dependlendo del Llpo de perslsLencla deflnamos, la facLorla nos
devuelve una lmplemenLacln u oLra. PablLualmenLe las facLorlas se apoyan en un
flchero de properLles para leer el Llpo de perslsLencla que esLamos uLlllzando. Ln esLe
caso nosoLros devolveremos slempre la lmplemenLacln de !A por slmpllcldad .una
vez que hemos consLruldo esLa clase facLorla, vamos a ver cmo queda el cdlgo fuenLe
de cada una de nuesLras acclones .ara ello vamos a mosLrar el cdlgo de la accln
MosLrarLlbros, ya que usa LanLo la clase de perslsLencla CaLegorlauAC como la clase
LlbrouAC.

!"#$%&'(&$") +),)
234
Cdlgo 14.3: (MosLrarLlbrosAcclon.[ava)
public String ejecutar(HttpServletRequest request,
HttpServletResponse response)
CategoriaDAO categoriaDAO= CategoriaDAOFactory.getInstance();
LibroDAO libroDAO= LibroDAOFactory.getInstance();
List<Libro> listaDeLibros = libroDAO.buscarTodos();
List<Categoria> listaDeCategorias = categoriaDAO.buscarTodos();
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);
return "MostrarLibros.jsp";
}

Ll cdlgo no es compllcado de enLender y podemos ver como ya el programador no
neceslLa hacer uso del operador new slno que se apoyar en dos facLorlas que hemos
consLruldo, una para los Llbros y oLra para las CaLegorlas. ue esLa forma slmplemenLe
camblando la lmplemenLacln que devuelve cada una las facLorlas podremos
lnLercamblar una capa de perslsLencla por oLra (obllgando por e[emplo a las facLorlas a
leer la lmplemenLacln de un flchero de propledades). Sln embargo, para consegulr
esLe nlvel de Lransparencla a la hora de poder lnLercamblar las capas de perslsLencla y
ganar en flexlbllldad, debemos pagar un preclo basLanLe alLo: por cada clase de negoclo
que Lengamos aparecer una nueva facLorla (ver lmagen).



!!!"#$%&'()*(&$#+#,#"*-.
235


LsLo es un problema lmporLanLe ya que nos enconLraremos con una vlolacln clara del
prlnclplo u8? pues prcLlcamenLe Lodas las facLorlas que consLrulmos son ldenLlcas, ya
que Lodas cubren la mlsma funclonalldad al eleglr una lmplemenLacln u oLra de la
capa de perslsLencla. A conLlnuacln se muesLra el cdlgo fuenLe de la facLorla
CaLegorlauAClacLory , podemos adverLlr que es prcLlcamenLe ldenLlco al cdlgo de la
facLorla LlbrouAClacLory.



!"#$%&'(&$") +),)
236

Cdlgo 14.4: (CaLegorlauAClacLory.[ava)
public class CategoriaDAOFactory {
public static CategoriaDAO getInstance() {
String tipo = "JPA";
if (tipo.equals("Hibernate")) {
return new CategoriaDAOHibernateImpl();
} else {
return new CategoriaDAOJPAImpl();
}
}
}

Asl pues Lenemos un problema de repeLlcln de funclonalldad (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
237

or lo LanLo debemos refacLorlzar nuesLro cdlgo para evlLar LanLas repeLlclones de
funclonalldad y a la vez manLener la capacldad que Llene nuesLra apllcacln de camblar
de lmplemenLacln de capa de perslsLencla de forma LransparenLe (PlbernaLe, !A eLc)
. ara ello la slgulenLe Larea se encargara de solvenLar esLe problema.
2. L| pr|nc|p|o Dk y e| patrn Abstract Iactory
La esLrucLura de clases de capa de perslsLencla que Lenemos Llene una pecullarldad :
pueden ser agrupadas por famlllas. una famllla serla la lmplemenLacln de !A y oLra
famllla serla la lmplemenLacln de PlbernaLe (ver lmagen).
Cuando Lenemos esLa casulsLlca Lan especlal exlsLe un paLrn de dlseno que nos puede
ayudar a cumpllr con el prlnclplo lCC y manLener nuesLro compromlso con el prlnclplo
u8?, permlLlendonos por lo LanLo camblar de forma LransparenLe enLre una
lmplemenLacln y oLra sln Lener que pagar un alLo preclo de repeLlcln de cdlgo en
nuesLra apllcacln. LsLe paLrn de dlseno se denomlna AbsLracL lacLory , vamos a
lnLroduclrlo a conLlnuacln.
!"#$%&'(&$") +),)
238
Ll paLrn absLracL facLory es un paLrn de dlseno que se apoya en la consLruccln de un
grupo reducldo de facLorlas. ConcreLamenLe una facLorla por cada famllla de clases que
Lengamos y oLra facLorla que agrupa a las facLorlas encargadas de crear las famlllas
.Asl, en nuesLro e[emplo Lendremos la necesldad de consLrulr Lres facLorlas.
1. Crear una facLorla para la famllla de PlbernaLe
2. Crear una facLorla para la famllla de !A
3. Crear una facLorla para las dos facLorlas que hemos creado
Asl pues vamos a empezar con la prlmera Larea consLrulr una facLorla que sea capaz de
crear Lodos los ob[eLos de una de las famlllas, para ello eleglremos la famllla de !A.
nuesLra facLorla Lendr la pecullarldad de Lener un meLodo por cada una de las clases
!A que consLruyamos. A conLlnuacln se muesLra un dlagrama aclaraLorlo de cmo
esL consLrulda esLa facLorla.

una vez creada la facLorla de !A, vamos a ver su cdlgo fuenLe para que nos ayude a
asenLar ldeas.

!!!"#$%&'()*(&$#+#,#"*-.
239
Cdlgo 14.3: (uAC!AlacLory.[ava)
public class DAOJPAFactory {
public CategoriaDAO getCategoriaDAO() {
return new CategoriaDAOJPAImpl();
}
public LibroDAO getLibroDAO() {
return new LibroDAOJPAImpl();
}
}

La facLorla nos devuelve los ob[eLos que perLenecen a la famllla de !A
LlbrouAC!Almpl y CaLegorlauAC!Almpl. vamos a ver a conLlnuacln el cdlgo de la
facLorla que se encarga de la oLra famllla la famllla de PlbernaLe.
Cdlgo 14.6: (uACPlbernaLelacLory.[ava)
public class DAOHibernateFactory {
public CategoriaDAO getCategoriaDAO() {
return new CategoriaDAOHibernateImpl();
}
public LibroDAO getLibroDAO() {
return new LibroDAOHibernateImpl();
}
}

una vez creadas ambas clases , es fcll ldenLlflcar que comparLen el mlsmo con[unLo de
meLodos y por lo LanLo se puede deflnlr un lnLerface comun para ambas, como el que
se muesLra en el slgulenLe dlagrama.
!"#$%&'(&$") +),)
240


A conLlnuacln se muesLra el cdlgo fuenLe del lnLerface para el caso senclllo de
nuesLra apllcacln.
Cdlgo 14.7: (uAClacLory.[ava)
package com.arquitecturajava.aplicacion.dao;

public interface DAOFactory {
public CategoriaDAO getCategoriaDAO();
public LibroDAO getLibroDAO();
}

una vez deflnldo el lnLerface, obllgaremos a cada una de nuesLras facLorlas a
lmplemenLarlo
Cdlgo 14.8: (uAC!AlacLory.[ava)
public class DAOJPAFactory implements DAOFactory {
// resto del cdigo
}


!!!"#$%&'()*(&$#+#,#"*-.
241
Cdlgo 14.9: (uAC!AlacLory.[ava)
public class DAOHibernateFactory implements DAOFactory {
// resto del cdigo
}

ueflnldo el lnLerface comun para ambas facLorlas, nos enconLramos con que podemos
deflnlr una facLorla que nos devuelva una lmplemenLacln de esLe lnLerface para !A
(uAC!AlacLory) o una lmplemenLacln para PlbernaLe (uACPlbernaLelacLory), algo
muy slmllar a lo que haclamos anLes. A esLa facLorla, dado que crea ob[eLos que son de
Llpo facLorla, se la denomlna AbsLracLlacLory. La slgulenLe flgura muesLra la relacln
enLre las dlsLlnLas clases.















!"#$%&'(&$") +),)
242

A conLlnuacln se muesLra su cdlgo fuenLe.
Cdlgo 14.10: (uACAbsLracLlacLory.[ava)
package com.arquitecturajava.aplicacion.dao;

public abstract class DAOAbstractFactory {
public static DAOFactory getInstance() {
String tipo="JPA";
if (tipo.equals("Hibernate")) {
new DAOHibernateFactory();
} else {
returnnew DAOJPAFactory();}}
}

LsLa clase crea ob[eLos blen de un Llpo de facLorla blen de oLro . Ms Larde cada una de
las facLorlas creadas sern las encargadas de devolvernos los dlsLlnLos ob[eLos uAC
para una lmplemenLacln concreLa. A conLlnuacln se muesLra cmo se usa a nlvel de
las acclones el concepLo de AbsLracLlacLory y de lacLory, ponlendo como e[emplo el
meLodo e[ecuLar de MosLrarLlbrosAcclon.

Cdlgo 14.11: (MosLrarLlbrosAcclon.[ava)
public String ejecutar(HttpServletRequest request,
HttpServletResponse response) {
DAOFactory factoria= DAOAbstractFactory.getInstance().
CategoriaDAO categoriaDAO= factoria.getCategoriaDAO();
LibroDAO libroDAO=factoria.getLibroDAO();
List<Libro> listaDeLibros = libroDAO.buscarTodos();
List<Categoria> listaDeCategorias = categoriaDAO.buscarTodos();
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);
return "MostrarLibros.jsp";
}

A parLlr de esLe momenLo el programador crear una lnsLancla de la clase
AbsLracLlacLory la cul se apoyara hablLualmenLe en un flchero de propledades para
eleglr que famllla de ob[eLos de perslsLencla consLrulr. una vez hecho esLo, nos
enconLramos con que el nuevo dlseno de la apllcacln cumple con el prlnclplo lCC y con
!!!"#$%&'()*(&$#+#,#"*-.
243
el prlnclplo u8? a nlvel de capa de perslsLencla, permlLlendonos varlar enLre una
lmplemenLacln y oLra de forma LransparenLe (ver lmagen).










!"#$%"&
una vez redlsenada la capa de perslsLencla podremos de una manera sencllla camblar
una capa por oLra sln Lener necesldad de Locar el cdlgo fuenLe, cumpllendo con el
prlnclplo CC. ara ello habremos anadldo las slgulenLes clases a la capa uAC:

!"#$%&'(&$") +),)
244
!"!!" $%&'(&)&! #$% & '( )*+,-. /',0121!





Ln el caplLulo anLerlor hemos anadldo versaLllldad a la capa de perslsLencla uLlllzando
los slgulenLes paLrones de dlseno.
lacLory
AbsLracL lacLory
permlLlendonos lnLercamblar las dlsLlnLas capas de perslsLencla de forma
prcLlcamenLe LransparenLe como muesLra la flgura.

Sln embargo, para poder dlsponer de esLa funclonalldad, hemos Lenldo que sacrlflcar
algo :hemos lncremenLado la comple[ldad del mane[o de la capa de perslsLencla por
parLe de los desarrolladores y se neceslLa un con[unLo de clases mayor que anLes para
reallzar las mlsmas operaclones (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
245

Ls momenLo de abordar esLe problema .Ll ob[eLlvo prlnclpal de esLe caplLulo ser
slmpllflcar el Lraba[o de los desarrolladores con la capa de perslsLencla al consLrulr la
capa de presenLacln e lnLeracLuar con la mlsma. Lnumeremos los ob[eLlvos y Lareas
planLeados:
Cb[et|vos:
Slmpllflcar el acceso a la capa de perslsLencla
1areas:
1. uso del prlnclplo u8? en el acceso a la capa de perslsLencla
2. Creacln de una clase de servlclo que slmpllflque el acceso.

1. L| pr|nc|p|o Dk y e| acceso a |a capa de pers|stenc|a
vamos a revlsar el cdlgo fuenLe de la clase MosLrarLlbrosAcclon del caplLulo anLerlor
una vez hemos hecho uso de facLorlas para anadlr flexlbllldad a esLa capa.


!"#$%&'(&$") +),)
246

Cdlgo 13.1: (MosLrarLlbrosAcclon.[ava)
public String ejecutar(HttpServletRequest request,
HttpServletResponse response) {

DAOFactory factoria= DAOAbstractFactory.getInstance().
CategoriaDAO categoriaDAO= factoria.getCategoriaDAO();
LibroDAO libroDAO=factoria.getLibroDAO();
List<Libro> listaDeLibros = libroDAO.buscarTodos();
List<Categoria> listaDeCategorias = categoriaDAO.buscarTodos();
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);
return "MostrarLibros.jsp";
}

Como podemos ver se ha hecho uso de las facLorlas y del absLracL facLory para generar
los ob[eLos que perLenecen a la capa de perslsLencla. Ahora blen sl revlsamos alguna de
nuesLras oLras acclones (como por e[emplo la accln de lormularloLdlLarLlbro cuyo
cdlgo se muesLra a conLlnuacln),
Cdlgo 13.2: (lormularloLdlLarLlbro.[ava)
public String ejecutar(HttpServletRequest request,
HttpServletResponse response) {

DAOFactory factoria= DAOAbstractFactory.getInstance().
CategoriaDAO categoriaDAO= factoria.getCategoriaDAO();
LibroDAO libroDAO=factoria.getLibroDAO();

String isbn = request.getParameter("isbn");
List<Categoria> listaDeCategorias = categoriaDAO.buscarTodos();
Libro libro = libroDAO
.buscarPorClave(request.getParameter("isbn"));
request.setAttribute("listaDeCategorias", listaDeCategorias);
request.setAttribute("libro", libro);
return "FormularioEditarLibro.jsp";
}

nos podremos dar cuenLa de que comparLen el mlsmo cdlgo fuenLe de lnlclallzacln
de las facLorlas a la hora de uLlllzar la capa de perslsLencla .LsLe es un problema claro de
repeLlcln de cdlgo en el cul no se esL uLlllzando el prlnclplo u8? (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
247

2. Creac|n de una c|ase de Serv|c|o
Sl queremos ellmlnar las repeLlclones de cdlgo que Lenemos en cada una de nuesLras
acclones, debemos crear una nueva clase que se encargue de cenLrallzar la creacln de
los ob[eLos de la capa uAC para un subcon[unLo de clases relaclonadas a nlvel de
negoclo. A esLas clases se las denomlna hablLualmenLe clases de servlclo y como
podemos ver en la slgulenLe flgura, un grupo de acclones delega en ellas.
!"#$%&'(&$") +),)
248

ara que esLa nueva capa que aparece en la apllcacln pueda dlsponer posLerlormenLe
de una flexlbllldad slmllar a la que dlspone la capa de perslsLencla, la consLrulremos
apoyndonos en el uso de lnLerfaces. Ln nuesLro caso consLrulremos un servlclo
denomlnado servlcloLlbros que agrupa la funclonalldad asoclada a la gesLln de los
llbros y sus caLegorlas. A conLlnuacln se muesLra un dlagrama aclaraLorlo de la
esLrucLura.

1enemos claro ya el lnLerfaces y el servlclo. vamos a pasar a mosLrar el cdlgo fuenLe
del lnLerface de servlclo.
Cdlgo 13.3: (ServlcloLlbros.[ava)
package com.arquitecturajava.aplicacion.servicios;
import java.util.List;
import com.arquitecturajava.aplicacion.bo.Categoria;
import com.arquitecturajava.aplicacion.bo.Libro;
public interface ServicioLibros {
public void salvarLibro(Libro libro);
public void borrarLibro(Libro libro);
public List<Libro> buscarTodosLosLibros();
public List<Categoria> buscarCategoriasLibros();
public Libro buscarLibroPorClave(String isbn);
public Categoria buscarCategoriaPorClave(int id);
public List<Libro> buscarLibrosPorCategoria(int categoria);
}

ueflnldo el lnLerface ,vamos a ver su lmplemenLacln y cmo esLa delega en las
facLorlas que hemos creado anLerlormenLe para reallzar su funclonalldad.

!!!"#$%&'()*(&$#+#,#"*-.
249
Cdlgo 13.4: (ServlcloLlbros.[ava)
package com.arquitecturajava.aplicacion.servicios.impl;

// omitidos imports
public class ServicioLibrosImpl implements ServicioLibros {

private LibroDAO libroDAO=null;
private CategoriaDAO categoriaDAO=null;
public ServicioLibrosImpl() {
DAOFactory factoria= DAOAbstractFactory.getInstance();
libroDAO= factoria.getLibroDAO();
categoriaDAO=factoria.getCategoriaDAO();
}

public void salvarLibro(Libro libro) {
libroDAO.salvar(libro);
}
public void borrarLibro(Libro libro) {
libroDAO.borrar(libro);
}
public List<Libro> buscarTodosLosLibros() {
return libroDAO.buscarTodos();
}
public List<Categoria> buscarCategoriasLibros() {
return categoriaDAO.buscarTodos();
}

public Libro buscarLibroPorClave(String isbn) {
return libroDAO.buscarPorClave(isbn);
}
public Categoria buscarCategoriaPorClave(int id) {
return categoriaDAO.buscarPorClave(id);
}
public List<Libro> buscarLibrosPorCategoria(int id) {
Categoria categoria= categoriaDAO.buscarPorClave(id);
return libroDAO.buscarPorCategoria(categoria);
}
}

!"#$%&'(&$") +),)
250
una vez consLrulda esLa clase, podemos ver como su consLrucLor se encarga de poner a
nuesLra dlsposlcln las dlsLlnLas facLorlas necesarlas. La siguiente imagen muesLra la
relacln enLre la capa de servlclos, la capa de perslsLencla y la capa de presenLacln y
cmo el consLrulr esLa capa reduce la repeLlcln de cdlgo.

ConsLrulda la clase de servlclo, vamos a ver por ulLlmo cmo el cdlgo fuenLe de la
clases de accln queda slmpllflcado. SeguldamenLe se muesLra el nuevo cdlgo de la
clase MosLrarLlbrosAcclon.
Cdlgo 13.3: (MosLrarLlbrosAcclon.[ava)

public String ejecutar(HttpServletRequest request,
HttpServletResponse response) {
ServicioLibros servicioLibros= new ServicioLibrosImpl();
List<Libro> listaDeLibros = servicioLibros.buscarTodosLosLibros();
List<Categoria> listaDeCategorias =
servicioLibros.buscarCategoriasLibros();
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);
return "MostrarLibros.jsp";
}

!!!"#$%&'()*(&$#+#,#"*-.
251
una vez reallzados esLos camblos podemos mosLrar los nuevos flcheros y paqueLes que
aparecen en nuesLra apllcacln.

!"#$%"&
Ln esLe caplLulo nos hemos cenLrado en slmpllflcar el acceso a la capa de perslsLencla
apoyndonos para ello en la consLruccln de una nueva capa: la capa de servlclos
clslca.










!"#$%&'(&$") +),)
252
!"!!" $%&'(&$&) *+,- ." /%01.2)%3
!"#$%&





Ln el caplLulo anLerlor hemos consLruldo una capa de servlclos que nos ha permlLldo
ellmlnar repeLlclones lnnecesarlas de cdlgo asl como alslar compleLamenLe la capa de
presenLacln de la capa de perslsLencla. Ln esLe caplLulo vamos a anadlr flexlbllldad a la
capa de perslsLencla consLrulda. Ahora nuesLra capa de perslsLencla soporLa nuevas
lmplemenLaclones a Lraves del uso del paLrn AbsLracLlacLory que deflne un con[unLo
de famlllas, pudlendo anadlr nuevas famlllas mas adelanLe . or e[emplo puede ser que
en algun momenLo neceslLemos una famllla de xML o una famllla !u8C como muesLra
en la slgulenLe flgura.

!!!"#$%&'()*(&$#+#,#"*-.
253

Como acabamos de comenLar, es la clase AbsLracLlacLory la que se encarga de la
gesLln de las famlllas y la responsable de crear los dlsLlnLos ob[eLos (ver lmagen).

Ahora blen el paLrn AbsLracL lacLory aunque aporLa venLa[as, Lamblen Llene
llmlLaclones. Sl nos apoyamos en el, no nos ser poslble dlsponer de una capa de
perslsLencla hlbrlda en la que una parLe de las clases uAC sean por e[emplo !u8C y oLra
!A (ver lmagen).
!"#$%&'(&$") +),)
254


uede parecer exLrano el que una apllcacln neceslLe un modelo hlbrldo pero pueden
exlsLlr muchas slLuaclones en las cuales esLo sea uLll, a conLlnuacln se enumeran
varlas.
Ap||cac|n de |egado: uede ser que nuesLra apllcacln Lenga alguna parLe de
legado y neceslLemos por e[emplo acceder a esa parLe vla !u8C.

Modu|o no re|ac|ona|: SlLuacln en la que la capa de perslsLencla neceslLa
punLualmenLe acceder a una lnformacln que no esL almacenado en una base
de daLos relaclonal, por e[emplo flcheros xML y neceslLamos que parLe de la
lmplemenLacln de la capa de perslsLencla acceda a flcheros xml.

Cb[eto Mock : neceslLamos consLrulr una clase que slmule una funclonalldad
concreLa de la capa de perslsLencla ya que en esLos momenLos no ha sldo
Lodavla consLrulda o en nuesLro enLorno de desarrollo no Lenemos acceso a ella
pero queremos poder slmularla.

!!!"#$%&'()*(&$#+#,#"*-.
255
rob|emas de rend|m|ento: arLes de la apllcacln Llenen problemas con la
capa de perslsLencla hablLual que uLlllzamos y neceslLan usar oLro Llpo de
lmplemenLacln que de me[or rendlmlenLo.
LsLas son algunas de las slLuaclones por las cules soporLar un modelo hlbrldo es
lnLeresanLe pero exlsLen muchas ms. Ll ob[eLlvo prlnclpal de esLe caplLulo ser el
permlLlr varlar la lmplemenLacln de parLe de nuesLra capa de perslsLencla sln Lener
que esLar llgados al uso concreLo de una famllla A o famllla 8 de Lal forma que nuesLra
apllcacln sea ms flexlble. ara ello lnLroduclremos el framework Sprlng y sus
capacldades de lnversln de conLrol.
Objetivos:
lnLroduccln al framework Sprlng.
ermlLlr a la apllcacln camblar las lmplemenLaclones de clases concreLas de
forma LoLalmenLe LransparenLe al desarrollador, aporLando flexlbllldad a la
apllcacln usando Sprlng framework
Tareas:
1. Creacln de e[emplo elemenLal de facLorlas
2. lnsLalacln de Sprlng lramework
3. Conflguracln de Sprlng en nuesLra apllcacln


1. Creac|n de e[emp|o de factor|as
Ll framework Sprlng es un framework de lnversln de ConLrol que nos permlLe
gesLlonar nuesLras necesldades de lnversln de conLrol agrupada y senclllamenLe sln
Lener que recurrlr al uso de paLrones de dlseno clslcos (como lacLory y AbsLracL
lacLory). ara comprender cmo funclona esLe framework, vamos a reallzar un e[emplo
senclllo anLes de reLomar nuesLra apllcacln y apllcar las venLa[as aporLadas. ara ello
consLrulremos un senclllo lnLerface Mensa[e que dlspone de dos lmplemenLaclones. A
conLlnuacln se desglosan los concepLos a consLrulr:
Interface Mensa[e: lnLerface con un unlco meLodo denomlnado hola().
C|ase Mensa[en1ML :Clase que lmplemenLa el lnLerface e lmprlme por panLalla
un mensa[e en formaLo P1ML.
C|ase Mensa[e|ano: Clase que lmplemenLa el lnLerface e lmprlme por panLalla
un mensa[e.
C|ase Iactor|aMensa[es: Clase que se encarga de apllcar el prlnclplo de
lnversln de conLrol.
!"#$%&'(&$") +),)
256
A conLlnuacln se muesLra un dlagrama con la esLrucLura bslca.

Clarlflcado el dlagrama, vemos el cdlgo fuenLe de cada una de las clases e lnLerfaces:
Cdlgo 16.1: (Mensa[e.[ava)
public interface Mensaje {
public void hola();
}

Cdlgo 16.2: (Mensa[eP1ML.[ava)
public class MensajeHTML implements Mensaje {
@Override
public void hola() {
System.out.println("<html>hola</html>");
}
}

Cdlgo 16.3: (Mensa[elano.[ava)
public class MensajePlano implements Mensaje {
@Override
public void hola() {
System.out.println("hola");
}
}
!!!"#$%&'()*(&$#+#,#"*-.
257
?a Lenemos el cdlgo de cada una de nuesLras clases. Ahora vamos a consLrulr un
senclllo programa que haga uso de la lmplemenLacln de P1ML .Ll cdlgo se muesLra a
conLlnuacln.
Cdlgo 16.4: (rlnclpal. [ava)
package com.arquitecturajava;
public class Principal {
public static void main(String[] args) {

Mensaje mensaje= newMensajeHTML();
mensaje.hola();
}
}

ConsLruldo el cdlgo, podemos e[ecuLar el programa y ver que resulLados genera.
vease una lmagen una vez e[ecuLado el programa:

una vez que hemos consLruldo las clases, vamos a usar el prlnclplo de lnversln de
conLrol y consLrulr una sencllla facLorla apoyada en un flchero de propledades para
crear un Llpo de mensa[e u oLro dependlendo del conLenldo del flchero (ver lmagen).
!"#$%&'(&$") +),)
258


una vez que Lenemos claro el dlagrama, vamos a ver el conLenldo del flchero de
propledades que vamos a uLlllzar asl como el cdlgo fuenLe de nuesLra facLorla.
Cdlgo 16.3: (mensa[e.properLles)
tipo=html







!!!"#$%&'()*(&$#+#,#"*-.
259
Cdlgo 16.3: (Mensa[elacLory.[ava)
packagecom.arquitecturajava;

importjava.io.FileInputStream;
import java.util.Properties;

public class MensajeFactory {

public static Mensaje getMensaje(){
Properties propiedades= new Properties();
Mensaje mensaje=null;
try {
propiedades.load(new FileInputStream("mensaje.properties"));
String tipo=propiedades.getProperty("tipo");
if (tipo.equals("html")) {
mensaje=new MensajeHTML();
}else {
mensaje= new MensajePlano();
}

} catch (Exception e) {
e.printStackTrace();
}
return mensaje;
}
}


Acabamos de apllcar el prlnclplo de lnversln de conLrol a Lraves del uso de una
facLorla. Ahora podremos consLrulr el programa prlnclpal de la slgulenLe forma y el
resulLado ser ldenLlco al anLerlor:
Cdlgo 16.6: (rlnclpal.[ava)
public static void main(String[] args) {

Mensaje mensaje= MensajeFactory.getMensaje();
mensaje.hola();
}

ue lgual manera podremos modlflcar el flchero de propledades que acabamos de
consLrulr para que la lmplemenLacln y el funclonamlenLo de nuesLro programa
camble. Ln esLe caso camblamos en el flchero el Llpo (ver cdlgo).

!"#$%&'(&$") +),)
260
Cdlgo 16.7: (flchero)
tipo=plano

El resultado ser el siguiente:

una vez hemos vlsLo cmo uLlllzar de forma sencllla el prlnclplo de lnversln, podremos
darnos cuenLa de cmo al apoyarnos en un flchero de propledades, consegulmos
camblar de una lmplemenLacln de Mensa[e a oLra sln Locar el cdlgo fuenLe de
nuesLro programa .ue esLa forma cumpllmos adems con el prlnclplo CC (ver lmagen).

!!!"#$%&'()*(&$#+#,#"*-.
261
Ls momenLo de dar por flnallzada esLa revlsln del prlnclplo lCC y de cmo puede
llgarse al prlnclplo CC para lnLroduclr en la slgulenLe Larea el framework Sprlng y ver
que venLa[as adlclonales aporLa a nuesLra solucln acLual.
2. Insta|ac|n de Spr|ng
una vez Lenemos el e[emplo ms elemenLal de lnversln de conLrol consLruldo, lo
haremos evoluclonar para que haga uso de Sprlng framework para lo cul el prlmer
paso ser obLener el framework de la slgulenLe url.
http://www.springsource.com/download/community
una vez obLenldo el framework, pasaremos a lnsLalar en nuesLros e[emplos los flcheros
[ar necesarlos para reallzar las operaclones bslcas. A conLlnuacln se muesLra una
lmagen con los [ars.

una vez anadlda la carpeLa llb y los [ars necesarlos, podemos comenzar a usar el
framework Sprlng. LsLe framework Lraba[a como lnversor de conLrol y hace las Lareas
de una facLorla. Ln esLe caso se LraLa de una facLorla capaz de crear ob[eLos
apoyndose en un flchero de conflguracln xML (conLexLoApllcaclon.xml) (ver lmagen).
!"#$%&'(&$") +),)
262

una vez que Lenemos claro que Sprlng funclona como sl de una facLorla se LraLase y usa
un flchero de conflguracln, vamos a ver una lmagen que muesLra el proyecLo de
Sprlng, sus llbrerlas y la ublcacln del flchero de conflguracln.

vamos a ver cual es el conLenldo que esLe flchero Lendr para poder reallzar una
funclonalldad slmllar a la que nosoLros reallzbamos con nuesLra facLorla.


!!!"#$%&'()*(&$#+#,#"*-.
263
Cdlgo 16.8: (conLexLoApllcaclon.xml)
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="mensajeHTML"class="com.arquitecturajava.MensajeHTML">
</bean>
</beans>

Se puede ldenLlflcar claramenLe que el flchero se compone de una eLlqueLa <beans>
prlnclpal la cual conLlene un grupo de eLlqueLas <bean> anldadas. LsLas eLlqueLas
<bean> sern las encargadas de deflnlr los dlsLlnLos ob[eLos a lnsLanclar por parLe del
framework. ara ello cada ob[eLo usar dos aLrlbuLos
ld : ldenLlflca el nombre del ob[eLo
class: ldenLlflca a parLlr de que clase se debe consLrulr el ob[eLo
A conLlnuacln se muesLra el bloque de cdlgo que deflne un ob[eLo de Llpo
Mensa[eP1ML.
Cdlgo 16.9: (conLexLoApllcaclon.xml)
<bean id="mensajeHTML" class="com.arquitecturajava.MensajeHTML">
</bean>

una vez Lenemos claro esLo, vamos a ver cmo modlflcar nuesLro programa orlglnal
para hacer uso de Sprlng framework a la hora de lnsLanclar nuesLros ob[eLos y no Lener
que consLrulrnos nosoLros nuesLras proplas facLorlas.
Cdlgo 16.10: (rlnclpal.[ava)
public static void main(String[] args) {
ApplicationContextfactoria = new
FileSystemXmlApplicationContext("contextoAplicacion.xml");
Mensaje mimensaje= (Mensaje)factoria.getBean("mensajeHTML");
mimensaje.hola();
}

vlslblemenLe el cdlgo varla un poco ya que hacemos uso no ya de nuesLra facLorla slno
de una facLorla propla del framework Sprlng.
!"#$%&'(&$") +),)
264
FileSystemXmlApplicationContext

la cul reclbe como parmeLro el flchero de conflguracln de Sprlng
contextoAplicacion.xml

Sl e[ecuLamos nuesLro programa, el resulLado es ldenLlco al programa lnlclal (ver
lmagen)
La venLa[a de hacer uso de Sprlng es que permlLe anadlr Lodas las clases que deseemos
a nlvel del flchero xml (ver cdlgo).
Cdlgo 16.11: (apllcaclonConLexLo.xml)
<bean id="mensajeHTML" class="com.arquitecturajava.MensajeHTML" />
<bean id="mensajeBasico" class="com.arquitecturajava.MensajePlano" />

Asl se anade una mayor flexlbllldad a la hora de crear ob[eLos y se ellmlna las
llmlLaclones hablLuales que Llene una facLorla que unlcamenLe consLruya ob[eLos de
una [erarqula de clases concreLa.
!!!"#$%&'()*(&$#+#,#"*-.
265


or ulLlmo, vamos a ver el cdlgo fuenLe de la clase prlnclpal al Lraba[ar con dos
lmplemenLaclones dlsLlnLas a Lraves del uso de Sprlng.
Cdlgo 16.12: (rlnclpal.[ava)

public static void main(String[] args) {

ApplicationContextfactoria = new
FileSystemXmlApplicationContext("contextoAplicacion.xml");
Mensaje hola= (Mensaje)factoria.getBean("mensajeHTML");
hola.hola();
Mensaje hola= (Mensaje)factoria.getBean("mensajePlano");
hola.hola();
}

Ahora Lenemos claro que podemos anadlr varlas clases al flchero de conflguracln
conLexLoApllcaclon.xml .odemos usar el framework Sprlng como facLorla prlnclpal y
se encargar de crear Lodos los ob[eLos que le sollclLemos. Adems podremos anadlr
nuevas clases a lnsLanclar o camblar una lmplemenLacln por oLra sln necesldad de
camblar nuesLro cdlgo fuenLe, cumpllendo con el prlnclplo CC (ver lmagen).
!"#$%&'(&$") +),)
266

3. Insta|ac|n de Spr|ng en nuestra ap||cac|n.
vlsLo como funclonan de una manera elemenLal las capacldades de lnversln de conLrol
del framework Sprlng, vamos a ver cmo podemos apllcarlas a la apllcacln consLrulda.
Lo prlmero que vamos a hacer es lnsLalar las llbrerlas necesarlas del framework Sprlng
en nuesLra apllcacln web (ver lmagen).

una vez reallzada esLa operacln y anadldas las llbrerlas, hay que conflgurar el
framework Sprlng para que funclone correcLamenLe en una apllcacln web. ara ello
modlflcaremos el flchero web.xml y anadlremos las slgulenLes eLlqueLas.


!!!"#$%&'()*(&$#+#,#"*-.
267
Cdlgo 16.13: (web.xml)
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:contextoAplicacion.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

Ll parmeLro de conLexLo deflne cul va a ser el nombre del flchero de conflguracln
que Sprlng debe cargar. or oLro lado el llsLener de la apllcacln permlLe que el
framework Sprlng se cargue y lea el flchero de conflguracln anLes de que la apllcaclon
web enLre en funclonamlenLo.
una vez conflgurado el framework, podemos deflnlr el flchero xML con las clases que
queremos sean lnsLancladas por la facLorla de sprlng. ara comenzar poco a poco
unlcamenLe sollclLaremos al framework que lnsLancle las clases uAC. A conLlnuacln se
muesLra el codlgo del flchero conLexLoApllcaclon.xml.
Cdlgo 16.14: (conLexLoApllcaclon.[ava)
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<bean id="libroDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.LibroDAOJPAImpl">
</bean>

<bean id="categoriaDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.CategoriaDAOJPAImpl">
</bean>
</beans>

Conflgurado el flchero conLexLoApllcaclon.xml , es necesarlo usar la capa de servlclo
para crear los dlsLlnLos elemenLos de la capa de perslsLencla. Ahora blen, en lugar de
usar facLorlas y absLracL facLorles, en esLe caso usaremos el framework Sprlng ,como se
muesLra a conLlnuacln en el slgulenLe bloque de cdlgo.

!"#$%&'(&$") +),)
268
Cdlgo 16.13: (ServlcloLlbroslmpl.[ava)
public class ServicioLibrosImpl implementsServicioLibros {

private LibroDAOlibroDAO=null;
private CategoriaDAOcategoriaDAO=null;

publicServicioLibrosImpl() {
ClassPathXmlApplicationContextfactoria =
new ClassPathXmlApplicationContext("contextoAplicacion.xml");
libroDAO= (LibroDAO)factoria.getBean("libroDAO");
categoriaDAO=(CategoriaDAO)factoria.getBean("categoriaDAO");
}

LsLa claro que se uLlllza oLra facLorla :ClassaLhxmlAppllcaLlonConLexL, facLorla de
Sprlng que busca un flchero denLro del classpaLh .Asl hemos usado un framework de
lnversln de conLrol para poder camblar la lmplemenLacln de la capa de perslsLencla
de una forma flexlble, permlLlendo LanLo usar !A, PlbernaLe, !u8C como oLras . Anadlr
nuevas lmplemenLaclones unlcamenLe lmpllca anadlr o modlflcar el flchero xml de
conflguracln. no hay que Locar para nada la apllcacln (ver lmagen).



!!!"#$%&'()*(&$#+#,#"*-.
269
una vez que hemos reallzado los prlmeros camblos a nlvel de Sprlng framework,
podremos ellmlnar Lodas las clases de facLorla que hablamos creado para la capa de
perslsLencla y slmpllflcar el modelo de nuesLra apllcacln en el que ya no neceslLaremos
el grupo de facLorlas (ver lmagen).



!"#$%"&
Ln esLe caplLulo hemos vlsLo una lnLroduccln al framework Sprlng y cmo esLe
framework permlLe ellmlnar el slsLema de facLorlas prevlamenLe consLruldo, anadlendo
mayor flexlbllldad a la apllcacln en proceso de consLruccln, uLlllzando el prlnclplo de
lnversln de conLrol.


!"#$%&'(&$") +),)
270
!"#$%&'(()*% ,' -'.'%,'%()/ & !"#$%&
!"#$%&'"(





Ln el caplLulo anLerlor hemos comenzado a usar el prlnclplo de lnversln de conLrol
para que la clase ServlcloLlbroslmpl se encargue de crear los dlsLlnLos ob[eLos de la
capa de perslsLencla a Lraves del framework Sprlng (ver lmagen).



!!!"#$%&'()*(&$#+#,#"*-.
271
Ln esLe caplLulo vamos a avanzar en el uso del prlnclplo de lnversln de conLrol y vamos
a uLlllzar el framework Sprlng para que se encargue de lnlclallzar no slo las clases que
perLenecen a la capa de perslsLencla slno Lamblen las clases de servlclo, en nuesLro
caso ServlcloLlbroslmpl. ue esLa forma nuesLras acclones delegarn ahora en el
framework Sprlng para cargar las clases de servlclo (ver lmagen).


ara ello nuesLro prlmer paso ser modlflcar el flchero conLexLoApllcaclon.xml y anadlr
nuesLra clase de servlclos (ver cdlgo).
Cdlgo 17.1: (conLexLoApllcaclon.xml)
<bean id="servicioLibros
class="com.arquitecturajava.aplicacion.servicios.impl.ServicioLibrosImpl">
</bean>

una vez reallzada esLa operacln, neceslLamos modlflcar la clase absLracLa Accln de
Lal forma que el resLo de las acclones se puedan apoyar en Sprlng al sollclLar el servlclo
de llbros. ara ello crearemos un nuevo meLodo en esLa clase denomlnado
get8ean(Str|ng nombre8ean) ,asl Lodas las dems acclones al heredarlo pueden
delegar en el para consLrulr la clase de servlclos necesarlos (ver lmagen).
!"#$%&'(&$") +),)
272


una vez enLendldo esLe concepLo, vemos cmo lmplemenLar esLa funclonalldad a nlvel
de la clase Accln. Ahora se muesLra el cdlgo de nuesLro nuevo meLodo.
Cdlgo 17.2: (Acclon.[ava)
public Object getBean(String nombre) {
ClassPathXmlApplicationContextfactoria = new
ClassPathXmlApplicationContext("contextoAplicacion.xml");
return factoria.getBean(nombre);
}

1ermlnada esLa operacln, las acclones crearn los servlclos de una forma muy sencllla
como se muesLra en el slgulenLe cdlgo de la clase MosLrarLlbrosAcclon:



!!!"#$%&'()*(&$#+#,#"*-.
273

Cdlgo 17.3: (MosLrarLlbrosAcclon.[ava)
public class MostrarLibrosAccion extendsAccion {

@Override
public String ejecutar(HttpServletRequestrequest,
HttpServletResponse response) {

ServicioLibros servicio =
(ServicioLibros) getBean("servicioLibros");

List<Libro>listaDeLibros = servicio.buscarTodosLosLibros();
List<Categoria>listaDeCategorias =
servicio.buscarTodasLasCategorias();
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);
return "MostrarLibros.jsp";
}

}

1ras modlflcar las acclones para que deleguen en el framework Sprlng al crear la capa
de servlclos, no olvldemos que Lamblen hemos usado en el caplLulo anLerlor el
framework Sprlng para crear ob[eLos de la capa de perslsLencla necesarlos para la capa
de servlclo, como muesLra el slgulenLe bloque de cdlgo.
Cdlgo 17.4: (ServlcloLlbroslmpl.[ava)

public ServicioLibrosImpl() {

ClassPathXmlApplicationContextfactoria =
new ClassPathXmlApplicationContext("applicationContext.xml");
libroDAO= (LibroDAO)factoria.getBean("libroDAO");
categoriaDAO=(CategoriaDAO)factoria.getBean("categoriaDAO");
}


Asl pues, en esLos momenLos hemos usado el framework Sprlng en dos parLes de
nuesLra apllcacln, prlmero a nlvel de las acclones y segundo a nlvel de los servlclos (ver
lmagen).
!"#$%&'(&$") +),)
274

Segun vayamos progresando en el dlseno de la apllcacln nos daremos cuenLa de que la
responsabllldad al lnlclallzar el framework se encuenLra lmplemenLada en varlas clases
y por lo LanLo Lenemos un problema de repeLlcln de cdlgo (ver lmagen).

vlsLo el problema, es momenLo de deflnlr los ob[eLlvos y Lareas de esLe caplLulo: nos
cenLraremos en ellmlnar las repeLlclones de cdlgo a la hora de lnlclallzar Sprlng y nos
encargaremos de cenLrallzar la responsabllldad de cmo se consLruyen cada uno de los
dlsLlnLos ob[eLos. ara ello nos apoyaremos en un paLrn denomlnado lnyeccln de
dependencla (ul) que ser abordado ms adelanLe.

Objetivos:
Lllmlnar repeLlclones de cdlgo en cuanLo a la lnlclallzacln de Sprlng.
CenLrallzar la responsabllldad de crear los dlsLlnLos ob[eLos.


!!!"#$%&'()*(&$#+#,#"*-.
275
Tareas:
1. lnLroduccln al paLrn de lnyeccln de uependencla
2. Sprlng como framework de lnyeccln de dependencla.
3. Sprlng y facLorla web.
4. Sprlng lnyeccln de dependencla y Capa uAC.

1. Introducc|n a| pr|nc|p|o de Inyecc|n de Dependenc|a
Ln esLa Larea vamos a lnLroduclr brevemenLe el paLrn de lnyeccln de dependencla
que conslsLe en lo slgulenLe:
Inyecc|n de Dependenc|a: Las dependenclas que una clase Llene no deben ser
aslgnadas por ella mlsma slno por un agenLe exLerno.
Culz la deflnlcln no sea sencllla en un prlmer momenLo, para clarlflcarla vamos
apllcar el paLrn de lnyeccln de dependencla a las clases de servlclo y perslsLencla que
Lenemos consLruldas. AnLes de abordar esLa Larea, vamos a mosLrar cul es la relacln
exlsLenLe enLre esLas clases y cules han usado Sprlng para lnlclallzar las dlsLlnLas
dependenclas relaLlvas a la clase ServlclosLlbroslmpl.


!"#$%&'(&$") +),)
276
Como podemos ver en el dlagrama, la clase ServlcloLlbroslmpl ha hecho uso de Sprlng
para lnlclallzar sus dependenclas. vamos a uLlllzar el prlnclplo de lnyeccln de
dependencla en la clase ServlcloLlbrolmpl de Lal forma que, a parLlr de esLe momenLo
no sea ella la encargada de lnlclallzar sus dependenclas slno un agenLe exLerno. ara
ello pasaremos a anadlrle los slgulenLes meLodos a su lmplemenLacln e lnLerface.

setL|broDAC(L|broDAC||broDAC) :Aslgna un ob[eLo de Llpo LlbrouAC a la clase
de servlclo
getL|broDAC() : uevuelve un ob[eLo de Llpo LlbrouAC
setCategor|aDAC (Categor|aDACcategor|aDAC): Aslgna un ob[eLo de Llpo
caLegorlauAC a la clase de servlclo.
getCategor|aDAC() :uevuelve un ob[eLo de Llpo CaLegorlauAC

una vez claro que meLodos vamos a anadlr, vamos a ver un dlagrama que muesLra
como quedan el lnLerface y la clase.

!!!"#$%&'()*(&$#+#,#"*-.
277

vlsLo el dlagrama, vamos a ver el cdlgo fuenLe de ambos
public interface ServicioLibros {
public LibroDAO getLibroDAO() {
public void setLibroDAO(LibroDAO libroDAO) {
public CategoriaDAO getCategoriaDAO()
public void setCategoriaDAO(CategoriaDAO categoriaDAO)
//resto de mtodos
}



!"#$%&'(&$") +),)
278

Cdlgo 17.3: (ServlcloLlbroslmpl.[ava)
public class ServicioLibrosImpl implements ServicioLibros {

private LibroDAOlibroDAO=null;
private CategoriaDAOcategoriaDAO=null;
public LibroDAO getLibroDAO() {
return libroDAO;
}

public void setLibroDAO(LibroDAO libroDAO) {
this.libroDAO = libroDAO;
}

public CategoriaDAO getCategoriaDAO() {
return categoriaDAO;
}

public void setCategoriaDAO(CategoriaDAO categoriaDAO) {
this.categoriaDAO = categoriaDAO;
}
//resto de codigo

una vez reallzada esLa operacln, la clase ServlcloLlbro!Almpl ya no neceslLa que se le
aslgnen las dependenclas en su consLrucLor ServlcloLlbro!Almpl() .Slno que esLas
depencenclas podrn ser aslgnadas a Lraves de los nuevos meLodos seL/geL .LsLos
meLodos sern lnvocados en nuesLro caso por una clase de Llpo Acclon (ver cdlgo).
Cdlgo 17.6: (MosLrarLlbrosAcclon.[ava)
public String ejecutar(HttpServletRequestrequest,
HttpServletResponse response) {
ServicioLibro servicio= getBean(ServicioLibro);
CategoriaDAOcategoriaDAO= getBean(categoriaDAO);
LibroDAOlibroDAO= getBean(libroDAO);
servicio.setLibroDAO(libroDAO);
servicio.setCategoriaDAO(categoriaDAO)
}

ue esLa manera habremos uLlllzado el paLrn de lnyeccln de uependencla para aslgnar
las dependenclas a nuesLra clase de servlclo. ?a no es necesarlo usar Sprlng a nlvel de
capa de servlclos en el consLrucLor del servlclo slno que son las proplas acclones las que
aslgnan las dependenclas necesarlas (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
279












ue esLa manera habremos de[ado de lnlclallzar varlas veces el framework Sprlng y
cumpllremos con el prlnclplo u8? como se ve en el dlagrama.

!"#$%&'(&$") +),)
280
2. Spr|ng e |nyecc|n de dependenc|a.
Pemos vlsLo cmo el prlnclplo de lnyeccln de dependencla permlLe cenLrallzar la
creacln de los dlsLlnLos ob[eLos y agrupar la responsabllldad de crearlos en las
acclones. Ahora blen, aunque hemos usado el prlnclplo u8? y ellmlnado el cdlgo de
lnlclallzacln de las clases de Servlclo (ver cdlgo).
Cdlgo 17.7: (ServlcloLlbroslmpl.[ava)
public ServicioLibrosImpl() {
//ya no existe codigo de Spring
}

Aun asl Lodavla nos queda un problema por resolver :Lodas las acclones comparLen el
uso de la facLorla de Sprlng y la lnyeccln de dependenclas enLre la clase de servlclos y
las clases uAC como muesLran los slgulenLes bloques de cdlgo que son prcLlcamenLe
ldenLlcos..
Cdlgo 17.8: (MosLrarLlbrosAcclon.[ava)
public String ejecutar(HttpServletRequestrequest,
HttpServletResponse response) {
ServicioLibro servicio=(ServicioLibro) getBean(ServicioLibro);
CategoriaDAOcategoriaDAO= (CategoriaDAO) getBean(categoriaDAO);
LibroDAOlibroDAO= (LibroDAO)getBean(libroDAO);
servicio.setLibroDAO(libroDAO);
servicio.setCategoriaDAO(categoriaDAO)
//resto de codigo
}

Cdlgo 17.9: (lllLroLlbrosorCaLegorlaAcclon.[ava)
publicString ejecutar(HttpServletRequestrequest,
HttpServletResponse response) {
ServicioLibro servicio=(ServicioLibro) getBean(ServicioLibro);
CategoriaDAOcategoriaDAO= (CategoriaDAO) getBean(categoriaDAO);
LibroDAOlibroDAO= (LibroDAO)getBean(libroDAO);
servicio.setLibroDAO(libroDAO);
servicio.setCategoriaDAO(categoriaDAO)
}

no es dlflcll darse cuenLa de que Lenemos cdlgo repeLldo en las dos acclones :
volvemos a Lener un problema respecLo al prlnclplo u8? (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
281

ara solvenLar esLe problema vamos a usar Sprlng como framework de Inyecc|n de
dependenc|a. Los frameworks de lnyeccln de dependencla permlLen aslgnar las
dependenclas fuera de nuesLro proplo cdlgo fuenLe apoyndonos normalmenLe en
flcheros de conflguracln xml. LsLe es el caso de Sprlng, que a Lraves de su flchero xml
es capaz de lnyecLar las dlsLlnLas dependenclas a los dlsLlnLos ob[eLos que
consLruyamos .or lo LanLo ahora Lodo el cdlgo de lnyeccln de dependencla en cada
una de nuesLras clases de accln quedar relegado a un flchero xml (ver lmagen).
!"#$%&'(&$") +),)
282

vamos a mosLrar a conLlnuacln el cdlgo fuenLe del flchero conLexLoapllcacln.xml
para ver que slnLaxls usa el framework sprlng a la hora de lnyecLar las dlsLlnLas
dependenclas y asl clarlflcar los concepLos expllcados.
Cdlgo 17.10: (conLexLoApllcaclon.xml)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="servicioLibros"
class="com.arquitecturajava.aplicacion.servicios.impl.ServicioLibrosImpl">
<propertyname="libroDAO" ref="libroDAO"></property>
<propertyname="categoriaDAO" ref="categoriaDAO"></property>
</bean>
<bean id="libroDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.LibroDAOJPAImpl">
</bean>
<bean id="categoriaDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.CategoriaDAOJPAImpl">
</bean>
</beans>

Como podemos ver, uLlllzamos la eLlqueLa <property> para usar el prlnclplo de
lnyeccln de dependencla e lnyecLar desde el flchero xML las dependenclas que
nuesLro servlclo neceslLa. ue esLa forma nuesLro cdlgo fuenLe a nlvel de cada una de
las acclones quedar slmpllflcado pues unlcamenLe neceslLaremos obLener el servlclo a
Lraves del meLodo geL8ean y Sprlng a Lraves de su flchero xml se encargar de lnyecLar
las dlsLlnLas dependenclas, como se muesLra en el slgulenLe bloque de cdlgo que
corresponde a la clase MosLrarLlbroAcclon.
Cdlgo 17.11: (MosLrarLlbrosAcclon.[ava)
public String ejecutar(HttpServletRequestrequest,
HttpServletResponse response) {
ServicioLibros servicio = (ServicioLibros)
getBean("servicioLibros");
List<Libro>listaDeLibros = servicio.buscarTodosLosLibros();
List<Categoria>listaDeCategorias = servicio.buscarTodasLasCategorias();
request.setAttribute("listaDeLibros", listaDeLibros);
request.setAttribute("listaDeCategorias", listaDeCategorias);
return "MostrarLibros.jsp";
}
!!!"#$%&'()*(&$#+#,#"*-.
283
3. Spr|ng y factor|a para ap||cac|ones web
PasLa esLe momenLo hemos esLado uLlllzando la facLorla clslca de Sprlng (ver cdlgo).
Cdlgo 17.12: (Acclon.[ava)

public Object getBean(String nombre) {
ClassPathXmlApplicationContextfactoria = new
ClassPathXmlApplicationContext("applicationContext.xml");
returnfactoria.getBean(nombre);
}

Ls momenLo de conflgurar Sprlng para que use una facLorla especlflca a nlvel de
apllcacln web. or eso es necesarlo modlflcar el meLodo geL8ean de nuesLra clase
Acclon y subsLlLulr la facLorla hablLual por el slgulenLe bloque de cdlgo.
Cdlgo 17.13: (MosLrarLlbrosAcclon.[ava)
public Object getBean(String nombre,HttpServletRequest request) {

WebApplicationContextfactoria =WebApplicationContextUtils.
getRequiredWebApplicationContext(request.getSession().
getServletContext());
return factoria.getBean(nombre);

}

ue esLa forma nos aseguraremos de que Sprlng slo carga el flchero de conflguracln
una unlca vez al arrancar la apllcacln web. 8eallzado esLe camblo, vamos a segulr
apllcando el prlnclplo de lnyeccln de dependencla a oLras clases de nuesLra
apllcacln.
4. Spr|ng |nyecc|n de dependenc|a y Capas DAC
Pemos Lraba[ado con el framework Sprlng como lnyecLor de dependencla a la hora de
crear los servlclos y las capas uAC. Ls momenLo de apllcar el prlnclplo de lnyeccln de
dependencla a las proplas clases uAC que Lenemos consLruldas. Sl revlsamos los
dlsLlnLos meLodos de la clase CenerlcuAC!Almpl como por e[emplo el slgulenLe.


!"#$%&'(&$") +),)
284
Cdlgo 17.14: (CenerlcuAC!Almpl.[ava)
public void borrar(T objeto) {

EntityManager manager = getEntityManagerFactory().createEntityManager();
EntityTransactiontx = null;
try {
tx = manager.getTransaction();
tx.begin();
manager.remove(manager.merge(objeto));
tx.commit();
} catch (PersistenceException e) {
tx.rollback();
throw e;
} finally {
manager.close();
}
}

nos daremos cuenLa de que no solo esLe meLodo slno Lodos los dems dependen de un
ob[eLo LnLlLyManagerlacLory. Asl pues vamos a refacLorlzar el cdlgo de la clase
CenerlcuAC!Almpl asl como el de su lnLerface para lnyecLar a Lraves de Sprlng dlcho
ob[eLo (ver lmagen) .

una vez que Lenemos claro que operacln vamos a reallzar, es momenLo de ver el
cdlgo fuenLe de nuesLra nueva clase.


!!!"#$%&'()*(&$#+#,#"*-.
285
Cdlgo 17.13: (CenerlcuAC!Almpl.[ava)
public abstract class GenericDAOJPAImpl<T, Id extends Serializable > implements
GenericDAO<T, Id> {
!....
public EntityManagerFactory getEntityManagerFactory() {
return entityManagerFactory;
}
public void setEntityManagerFactory(EntityManagerFactory
entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
}

una vez deflnldos los nuevos meLodos que nos permlLlrn lnyecLar la dependencla de
LnLlLyManagerlacLory a nuesLras clases uAC, es momenLo de ver que nuevos bean han
de ser anadldos a nlvel de flchero xml .A conLlnuacln se enumeran:
Dr|verManagerDataSource:8ean encargado de crear un pool de conexlones
conLra la base de daLos que selecclonemos pasando usuarlo, password , url,
drlver.
Lnt|tyManagerIactory: Pace uso del uaLaSource creado y aslgna el Llpo de
perslsLencla y algunos parmeLros adlclonales, como es el dlalecLo de !A que
se uLlllzar .
A conLlnuacln se muesLra la nueva versln del flchero.
Cdlgo 17.16: (conLexLoApllcaclon.[ava)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">


<bean id="fuenteDeDatos"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<propertyname="driverClassName" value="com.mysql.jdbc.Driver" />
<propertyname="url" value="jdbc:mysql://localhost/arquitecturaJavaORM"
/>
<propertyname="username" value="root" />
<propertyname="password" value="java" />
</bean>


!"#$%&'(&$") +),)
286

<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

<propertyname="persistenceUnitName" value="arquitecturaJava" />
<propertyname="dataSource" ref="fuenteDeDatos" />
<propertyname="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
>
<propertyname="databasePlatform"
value="org.hibernate.dialect.MySQL5Dialect" />
<propertyname="showSql" value="true" />
</bean>
</property>
</bean>
<bean id="servicioLibros"
class="com.arquitecturajava.aplicacion.servicios.impl.ServicioLibrosImpl">
<propertyname="libroDAO" ref="libroDAO"></property>
<propertyname="categoriaDAO" ref="categoriaDAO"></property>
</bean>
<bean id="libroDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.LibroDAOJPAImpl">
<propertyname="entityManagerFactory"
ref="entityManagerFactory"></property>
</bean>
<bean id="categoriaDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.CategoriaDAOJPAImpl">
<propertyname="entityManagerFactory"
ref="entityManagerFactory">
</property>
</bean>
</beans>

Ls evldenLe que ahora Lamblen las capas uAC se apoyan en Sprlng para lnyecLar la
dependencla que neceslLan de LnLlLyManagerlacLory. LsLa dependencla
(LnLlLyManagerlacLory) neceslLa a su vez la lnyeccln de varlas propledades y de una
fuenLe de daLos (pool de conexlones a base de daLos). Ls lo que hemos conflgurado en
el flchero. veamos como esLos camblos afecLan a nuesLros meLodos:




!!!"#$%&'()*(&$#+#,#"*-.
287

Cdlgo 17.16: (CenerlcuAC!Almpl.[ava)
public void salvar(T objeto) {
EntityManager manager =
getEntityManagerFactory().createEntityManager();

EntityTransaction tx = null;
try {
tx = manager.getTransaction();
tx.begin();
manager.merge(objeto);
tx.commit();

} catch (PersistenceException e) {
tx.rollback();
throw e;
} finally {
manager.close();
}
}

!"#$%"&
Ln esLe caplLulo nos hemos cenLrado en expllcar el paLrn de lnyeccln de dependencla
y cmo se conflgura a Lraves del framework Sprlng y nos hemos apoyado en el para
redeflnlr la conflguracln de las clases de servlclo y capas uAC, slmpllflcando el cdlgo
de nuesLras clases y exLernallzando la conflguracln en gran medlda.







!"#$%&'(&$") +),)
288
!"#!" $%&'(&$&) *+, - .$%&'/ 012$"3415






Ln el caplLulo anLerlor hemos vlsLo cmo usar el prlnclplo de lnyeccln de dependencla
que nos permlLe cenLrallzar la responsabllldad de crear ob[eLos en el framework Sprlng
y su flchero de conflguracln. LsLe caplLulo volver a cenLrarse en la evolucln de la
capa de perslsLencla. ara ello vamos a revlsar dos meLodos de la capa de perslsLencla .
Ln concreLo dos que perLenecen a la clase CenerlcuAC!Almpl: salvar y borrar. A
conLlnuacln mosLramos el cdlgo de los mlsmos:
Cdlgo 18.1: (CenerlcuAC!Almpl.[ava)

public void salvar(T objeto) {
EntityManager manager =
getEntityManagerFactory().createEntityManager();

EntityTransaction tx = null;
try {
tx = manager.getTransaction();
tx.begin();
manager.merge(objeto);
tx.commit();

} catch (PersistenceException e) {
tx.rollback();
throw e;
} finally {
manager.close();
}
}


!!!"#$%&'()*(&$#+#,#"*-.
289

Cdlgo 18.2: (CenerlcuAC!Almpl.[ava)
public void borrar(T objeto) {
EntityManager manager = getEntityManagerFactory().createEntityManager();
EntityTransaction tx = null;
try {
tx = manager.getTransaction();
tx.begin();
manager.remove(manager.merge(objeto));
tx.commit();
} catch (PersistenceException e) {
tx.rollback();
throw e;
} finally {
manager.close();
}
}

Como podemos ver, el cdlgo de la capa de perslsLencla de ambos meLodos, aunque no
es ldenLlco sl que se LraLa de cdlgo muy slmllar (hay bloques ldenLlcos). or lo LanLo,
nos enconLramos oLra vez en una slLuacln de vlolacln del prlnclplo u8?, ya que
Lenemos grandes bloques de cdlgo repeLldos en meLodos dlsLlnLos (ver lmagen).

una vez que Lenemos clara la repeLlcln de cdlgo, podemos ldenLlflcar que ambos
meLodos comparLen los mlsmos pasos que a conLlnuacln se enumeran.
!"#$%&'(&$") +),)
290
CbLener LnLlLyManager
Abrlr nueva 1ransacclon
L[ecuLar/AborLar 1ransacclon
Cerrar 8ecursos
Ll ob[eLlvo prlnclpal de esLe caplLulo ser ellmlnar dlchas repeLlclones de cdlgo de Lal
forma que las clases de perslsLencla queden mucho ms senclllas. ara ello
lnLroduclremos un nuevo paLrn: el paLrn 1emplaLe o planLllla.
Cb[et|vos:
Lllmlnar repeLlclones de cdlgo en la capa uAC
1areas
1. lnLroduclr el paLrn de dlseno 1emplaLe
2. Sprlng y el paLrn 1emplaLe
1. Sprlng lanLlllas y !AuACSupporL
1. L| patrn 1emp|ate
Ll paLrn 1emplaLe o planLllla es un paLrn de dlseno que se encarga de deflnlr una
serle de meLodos a nlvel de clase que funclonen en forma de planLllla . Asl que
clarlflcaremos el funclonamlenLo de esLe paLrn a Lraves de un e[emplo, para ello
vamos a crear la clase uocumenLo y dos clases hl[as: uocumenLo Senclllo y uocumenLo
Cflclal. La clase documenLo nos aporLar el meLodo lmprlmlr que se encarga de
lmprlmlr por panLalla el LexLo del documenLo .Ln la slgulenLe lmagen se muesLra la
relacln de clases y meLodos soporLados.
!!!"#$%&'()*(&$#+#,#"*-.
291
vamos a ver a conLlnuacln el cdlgo fuenLe de cada una de ellas y cmo funclona el
programa cuando lmprlme un documenLo.
Cdlgo 18.3: (uocumenLo.[ava)
package com.arquitecturajava;

public abstract class Documento {

public abstract void imprimir(String mensaje);
}


Cdlgo 18.4: (uocumenLoCflclal.[ava)
package com.arquitecturajava;

public class DocumentoOficial extends Documento{

public void imprimir(String mensaje) {
System.out.println("<oficial>cabecera documento oficial<oficial>");
System.out.println("<oficial>"+mensaje+"</oficial>");
System.out.println("<oficial>pie documento oficial</oficial>");
}

}

Cdlgo 18.3: (uocumenLo.[ava)
package com.arquitecturajava;
public class DocumentoPlano extends Documento {
public void imprimir(String mensaje) {
System.out.println("cabecera documento sencillo");
System.out.println(mensaje);
System.out.println("pie documento sencillo");
}
}

1ras consLrulr el cdlgo de cada una de nuesLras claves, vamos a ver cmo queda el
cdlgo del programa maln o prlnclpal que se encarga de lmprlmlr ambos documenLos
por panLalla.

!"#$%&'(&$") +),)
292
Cdlgo 18.6: (rlnclpal.[ava)
package com.arquitecturajava;
public class Principal {
public static void main(String[] args) {
Documento d= new DocumentoOficial();
d.imprimir("texto documento oficial");
d= new DocumentoPlano();
d.imprimir("texto documento plano");
}
}

Ll resulLado de lmprlmlr esLos documenLos ser el slgulenLe:


Como podemos ver Lodo se lmprlme correcLamenLe y parece que el programa
consLruldo no Llene flsuras. Ahora blen, lmaglnemonos que Lenemos oLro Llpo de
documenLo prcLlcamenLe ldenLlco al oflclal pero que al ser a nlvel del esLado, la
cabecera cambla de forma punLual y Llene el slgulenLe LexLo.
Cdlgo 18.7: (rlnclpal.[ava)
<oficial> cabecera documento ESTATAL</oficial>

!!!"#$%&'()*(&$#+#,#"*-.
293
Cmo podemos abordar esLe camblo de funclonalldad con el cdlgo acLual? Ln esLe
caso es senclllo: slmplemenLe debemos crear una nueva clase que exLlenda de la clase
documenLo y se denomlne uocumenLoLsLaLal. vease una lmagen aclaraLorla:

A conLlnuacln se muesLra el cdlgo fuenLe de la nueva clase que deflne el documenLo
esLaLal
Cdlgo 18.8: (uocumenLoLsLaLal.[ava)
package com.arquitecturajava;
public class DocumentoEstatal extends Documento{
public void imprimir(String mensaje) {
System.out.println("<oficial>cabecera documento ESTATAL<oficial>");
System.out.println("<oficial>"+mensaje+"</oficial>");
System.out.println("<oficial>pie documento oficial</oficial>");
}
}

A Lraves de la herencla hemos solvenLado en prlnclplo el problema del nuevo Llpo de
documenLo .Ahora blen, sl nos fl[amos ms, perclblremos un problema de cdlgo a
nlvel del prlnclplo u8?, ya que la clase uocumenLoCflclal y uocumenLoLsLaLal
comparLen cdlgo al 93(ver lmagen).
!"#$%&'(&$") +),)
294

una vez Lenemos claro cul es nuesLro problema, vamos a refacLorlzar nuesLro cdlgo
usando el paLrn 1emplaLe o planLllla. LsLe se encarga de dlvldlr la funclonalldad de un
meLodo en un con[unLo de meLodos que lmplemenLan la mlsma funclonalldad y que
forman una esLrucLura de planLllla, ya que cada uno de esLos meLodos puede ser
sobrescrlLo por las clases hl[as dependlendo de nuesLras necesldades. vamos a ver una
lmagen aclaraLorla de la esLrucLura de esLe paLrn:






!!!"#$%&'()*(&$#+#,#"*-.
295
















una vez reallzada esLa operacln, podremos crear nuevas clases que se encarguen de
sobreescrlblr aquellas parLes que nos lnLeresen. vamos a ver a conLlnuacln el cdlgo
de esLe nuevo dlagrama de clases:




!"#$%&'(&$") +),)
296
Cdlgo 18.9: (uocumenLoLsLaLal.[ava)
package com.arquitecturajava.plantillas;
public abstract class Documento {
public void imprimir(String mensaje) {
imprimirCabecera();
imprimirMensaje(mensaje);
imprimirPie();
}
protected abstract void imprimirCabecera();
protected abstract void imprimirMensaje(String mensaje);
protected abstract void imprimirPie();
}

Cdlgo 18.10: (uocumenLoCflclal.[ava)
package com.arquitecturajava.plantillas;

public class DocumentoOficial extends Documento{
@Override
public void imprimirCabecera() {
System.out.println("<oficial>cabecera documento oficial <oficial>");
}
@Override
public void imprimirMensaje(String mensaje) {
System.out.println("<oficial>"+mensaje+"</oficial>");
}
@Override
public void imprimirPie() {
System.out.println("<oficial>pie documento sencillo</oficial>");
}
}

vlslblemenLe el cdlgo es basLanLe dlsLlnLo, pero sl e[ecuLamos oLra vez nuesLro
programa, el resulLado ser ldenLlco. Ahora blen, cuando deseemos consLrulr la clase
uocumenLoLsLaLal ,podremos hacer uso del paLrn planLllla y unlcamenLe sobreescrlblr
la parLe que realmenLe cambla.




!!!"#$%&'()*(&$#+#,#"*-.
297
Cdlgo 18.11: (uocumenLoLsLaLal.[ava)
package com.arquitecturajava.plantillas;
public class DocumentoEstatal extends DocumentoOficial{
public void imprimirCabecera() {
System.out.println("<oficial>cabecera documento ESTATAL<oficial>");
}
}

ara consLrulr el documenLo esLaLal unlcamenLe hemos Lenldo que sobrescrlblr un
meLodo y hemos podldo ellmlnar las repeLlclones de cdlgo (ver lmagen).


A conLlnuacln vamos a usar el paLrn 1emplaLe [unLo al framework Sprlng para
ellmlnar repeLlclones en la capa de perslsLencla.
2. Spr|ng y p|ant|||as.
Sl revlsamos cualqulera de los meLodos que en esLos momenLos Lenemos en la capa de
perslsLencla, nos daremos cuenLa de que se comporLan de una forma muy slmllar al
paLrn 1emplaLe que acabamos de comenLar, ya que cada meLodo de perslsLencla
puede dlvldlrse en varlas operaclones (ver lmagen).

!"#$%&'(&$") +),)
298

rcLlcamenLe Loda la funclonalldad que consLrulmos en los dlsLlnLos meLodos de
perslsLencla es ldenLlca, salvo la operacln concreLa que el LnLlLyManager e[ecuLa. Asl
pues Loda esLa funclonalldad puede ser redlsenada para que se apoye en el paLrn
1emplaLe. ara ello el framework Sprlng nos provee de una clase que lmplemenLa Loda
la funclonalldad de Mane[o de Lxcepclones, CesLln de LnLlLy Manager y 1ransacclones.
A conLlnuacln se muesLra un dlagrama con la clase.

!!!"#$%&'()*(&$#+#,#"*-.
299

una vez que sabemos que el framework Sprlng nos puede ayudar a gesLlonar la capa de
perslsLencla a Lraves de una clase planLllla, vamos a apoyarnos en esLa clase para
refacLorlzar el cdlgo de las clases uAC. ara ello refacLorlzaremos nuesLra clase
CenerlcuAC!Almpl para que delegue en la clase !A1emplaLe del framework Sprlng al
reallzar Lodas las operaclones de perslsLencla.

vamos a ver a conLlnuacln cmo queda refacLorlzado el cdlgo de nuesLra clase y
cmo se apoya en la planLllla.






!"#$%&'(&$") +),)
300
Cdlgo 18.12: (CenerlcuAC!Almpl.[ava)
package com.arquitecturajava.aplicacion.dao.jpa;
//omitimos imports
public abstract class GenericDAOJPAImpl<T, Id extends Serializable>implements
GenericDAO<T, Id> {

private Class<T> claseDePersistencia;
private JpaTemplate plantillaJPA;

public JpaTemplate getPlantillaJPA() {
return plantillaJPA;
}
public void setPlantillaJPA(JpaTemplate plantillaJPA) {
this.plantillaJPA = plantillaJPA;
}
@SuppressWarnings("unchecked")
public GenericDAOJPAImpl() {

this.claseDePersistencia = (Class<T>) ((ParameterizedType)getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
@Override
public T buscarPorClave(Id id) {
return plantillaJPA.find(claseDePersistencia, id);
}
@SuppressWarnings("unchecked")
public List<T> buscarTodos() {
return plantillaJPA.find("select o from "
+ claseDePersistencia.getSimpleName() + " o");
}
publicvoid borrar(T objeto) {
plantillaJPA.remove(plantillaJPA.merge(objeto));
}
publicvoid salvar(T objeto) {
plantillaJPA.merge(objeto);
}
publicvoid insertar(T objeto) {
plantillaJPA.persist(objeto);
}
}

Como podemos ver el framework Sprlng nos aporLa una clase !A1emplaLe que ya
lmplemenLa Loda la funclonalldad necesarla de !A y que es lnyecLada (ver cdlgo).


!!!"#$%&'()*(&$#+#,#"*-.
301
Cdlgo 18.13: (CenerlcuAC!Almpl.[ava)
private JpaTemplate plantillaJPA;
public JpaTemplate getPlantillaJPA() {
return plantillaJPA;
}
public void setPlantillaJPA(JpaTemplate plantillaJPA) {
this.plantillaJPA = plantillaJPA;}

Al reallzar esLa operacln Lodos los meLodos de la clase CenerlcuAC!Almpl quedarn
claramenLe slmpllflcados. Ls evldenLe que la clase !A1emplaLe acLua como una
planLllla y unlcamenLe neceslLamos e[ecuLar un meLodo concreLo ya que el resLo de
funclonalldad vlene lmplemenLada por defecLo.
Cdlgo 18.14: (CenerlcuAC!Almpl.[ava)
public void borrar(T objeto) {
plantillaJPA.remove(plantillaJPA.merge(objeto));
}

La slgulenLe lmagen clarlflca cmo funclona la clase !A1emplaLe en cuanLo a los
meLodos que mane[a y que parLes de la funclonalldad vlenen lmplemenLadas ya por
defecLo, de Lal forma que no debemos preocuparnos por ello.

!"#$%&'(&$") +),)
302
una vez reallzada esLa operacln, deberemos usar Sprlng como lnyecLor de
dependencla y conflgurar la planLllla de !A a nlvel del flchero xML al ser la planLllla la
encargada de la gesLln de la capa de perslsLencla .Ser esLa clase a la que lnyecLemos
el enLlLyManagerlacLory (ver lmagen).
Cdlgo 18.13: (conLexLoApllcaclon.xml)
<bean id="plantillaJPA" class="org.springframework.orm.jpa.JpaTemplate">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="servicioLibros"
class="com.arquitecturajava.aplicacion.servicios.impl.ServicioLibrosImpl">
<property name="libroDAO" ref="libroDAO"></property>
<property name="categoriaDAO" ref="categoriaDAO"></property>
</bean>
<bean id="libroDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.LibroDAOJPAImpl">
<property name="plantillaJPA" ref="plantillaJPA" />
</bean>
<bean id="categoriaDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.CategoriaDAOJPAImpl">
<property name="plantillaJPA" ref="plantillaJPA" />
</bean>

L[ecuLada esLa operacln, la apllcacln segulr funclonando de la mlsma forma con la
venLa[a de haber slmpllflcado sobremanera el cdlgo que exlsLla en nuesLras clases
uAC, cumpllendo con el prlnclplo u8?.
3. Spr|ng nerenc|a |ant|||as y IDADACSupport
CLra opcln ms pracLlca es usar una clase que ya aporLe la planLllla que neceslLamos y
que nuesLra clase generlca exLlenda de ella. Ll lramework Sprlng nos aporLa esLa clase
a nlvel de !A y se denomlna !AuACSupporL (ver lmagen).

!!!"#$%&'()*(&$#+#,#"*-.
303
una vez que esLa clase hace uso de !A1emplaLe, podemos hacer que nuesLra clase
generlca exLlenda de ella y asl Lodas nuesLras clases uAC lmplemenLarn la
funclonalldad (ver lmagen).









A conLlnuacln se muesLra el cdlgo con la nueva versln de la clase:
Cdlgo 18.16: (CenerlcuAC!Almpl.[ava)
package com.arquitecturajava.aplicacion.dao.jpa;
//omitimos imports
public abstract class GenericDAOJPAImpl<T, Id extends Serializable>extends
JpaDaoSupport implements
GenericDAO<T, Id> {

private Class<T> claseDePersistencia;
@SuppressWarnings("unchecked")
public GenericDAOJPAImpl() {

this.claseDePersistencia = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
@Override
public T buscarPorClave(Id id) {
return getJpaTemplate().find(claseDePersistencia, id);
}
// resto de mtodos de persistencia no cambian

!"#$%&'(&$") +),)
304
Como podemos ver la clase ha quedado muy slmpllflcada y la capa de perslsLencla muy
sencllla, pero debemos modlflcar de nuevo nuesLro flchero de conflguracln de Sprlng
ya que nuesLras clases ahora se apoyaran en el meLodo seLLnLlLyManagerlacLory que
lmplemenLa la clase !AuACSupporL (ver cdlgo).
Cdlgo 18.17: (conLexLoApllcaclon.xml)
<bean id="servicioLibros"
class="com.arquitecturajava.aplicacion.servicios.impl.ServicioLibrosImpl">
<property name="libroDAO" ref="libroDAO"></property>
<property name="categoriaDAO" ref="categoriaDAO"></property>
</bean>
<bean id="libroDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.LibroDAOJPAImpl">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="categoriaDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.CategoriaDAOJPAImpl">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
!"#$%"&
Pemos refacLorlzado nuesLra capa uAC a Lraves del uso del paLrn planLllla (LemplaLe)
y hemos ellmlnado mucho cdlgo redundanLe. Ln esLos momenLos la capa de
perslsLencla ha quedado muy slmpllflcada, el prlnclplo u8? ha vuelLo a ser una de las
plezas claves para poder segulr avanzando con el dlseno.









!!!"#$%&'()*(&$#+#,#"*-.
305



















!"#$%&'(&$") +),)
306
!"#!!"#!$%$&'() +!',)-$.$ $
!"#$%&' !"#$%





Ln el caplLulo anLerlor hemos uLlllzado el prlnclplo u8? para slmpllflcar el cdlgo de la
capa de perslsLencla y reduclrlo a la mlnlma expresln, como muesLra el slgulenLe
meLodo.
Cdlgo 19.1: (CenerlcuAC!Almpl.[ava)
public void borrar(T objeto) {
getJpaTemplate().remove(getJpaTemplate().merge(objeto));
}

arece que es lmposlble slmpllflcar ms el cdlgo que Lenemos y esLamos en lo clerLo
en cuanLo al prlnclplo u8? se reflere. Aun asl, exlsLen algunas me[oras que se pueden
reallzar en la capa de perslsLencla aunque no son evldenLes. Sl revlsamos el cdlgo que
acabamos de mosLrar, nos podremos dar cuenLa de que no solo se encarga de borrar
un ob[eLo de la base de daLos, slno que adems e[ecuLa esa operacln denLro de una
Lransaccln. lgual que esLe meLodo e[ecuLa una Lransaccln, el resLo de meLodos de
modlflcacln Lamblen reallzan esLa operacln, como se muesLra en la lmagen.
!!!"#$%&'()*(&$#+#,#"*-.
307

Ln prlnclplo esLo no parece acarrear nlngun problema ya que al habernos apoyado en
las planLlllas en el caplLulo anLerlor, no Lenemos cdlgo repeLldo en esLas clases. Lo que
sucede es que la responsabllldad sobre la gesLln de Lransacclones esL dlsLrlbulda y
cada uno de los meLodos es responsable de gesLlonar sus proplas Lransacclones. Ahora
blen, supongamos que deseamos reallzar la slgulenLe Lransaccln:
lnserLar un nuevo llbro
borrar un llbro
Ambas operaclones se Llenen que reallzar de una forma aLmlca e lndlvlslble es declr:
o se reallzan ambas operaclones o nlnguna. Ls en esLe momenLo cuando nos
enconLraremos con el slgulenLe problema: cada una de esLas operaclones es una
Lransaccln compleLamenLe lndependlenLe de la oLra (ver lmagen).

no es poslble ,Lal como Lenemos consLrulda la solucln, deflnlr una Lransaccln que
agrupe operaclones de varlos meLodos de forma con[unLa (ver lmagen).
!"#$%&'(&$") +),)
308

Asl pues nuesLro dlseno acLual Llene un problema lmporLanLe ya que la necesldad de
que varlos meLodos se e[ecuLen de forma con[unLa (Lransacclonal) es algo muy
necesarlo para las apllcaclones. ara solvenLar esLe problema, neceslLamos cenLrallzar
la gesLln de las Lransacclones y no Lenerla dlspersa por Lodo el cdlgo. LsLe caplLulo se
cenLrar en solvenLar esLa cuesLln. ara ello lnLroduclremos el concepLo de
programacln orlenLada a aspecLo o AC (AspecLCrlenLedrogramlng).
Objetivos:
CenLrallzar la gesLln de Lransacclones.
Tareas:
1. lnLroduccln a AC.
2. Sprlng y roxles.
3. Conflguracln de proxles con sprlng

1. Introducc|n a AC
Ln esLos momenLos cada uno de los meLodos de nuesLras clases se encarga de
gesLlonar de forma lndependlenLe las Lransacclones .Sl queremos unlflcar la gesLln de
Lransacclones, deberemos exLraer la responsabllldad de e[ecuLar las Lransacclones de
nuesLras clases (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
309

no parece senclllo reallzar esLa operacln ya que sl exLraemos la responsabllldad de
nuesLras clases, no podremos e[ecuLar los meLodos de forma Lransacclonal ya que no
dlspondrn de esa capacldad. ara solvenLar esLo, vamos a volver a reLomar el e[emplo
de la clase Mensa[e y vamos a usar esLa clase para lnLroduclr algunos concepLos
fundamenLales de la programacln orlenLada a aspecLo. Ln esLe caso, un paLrn de
dlseno fundamenLal para esLe Llpo de programacln el paLrn proxy.
atrn roxy : LsLe paLrn hace las Lareas de lnLermedlarlo enLre un ob[eLo y su cllenLe
permlLlendo conLrolar el acceso a el anadlendo o modlflcando la funclonalldad
exlsLenLe de forma LransparenLe. ara aclarar el concepLo, vamos a consLrulr un
e[emplo senclllo que nos faclllLe enLender cmo se consLruye un roxy, a Lal fln vamos a
parLlr del lnLerface Mensa[e y de su lmplemenLacln Mensa[eP1ML, como se muesLra
en la slgulenLe flgura y bloque de cdlgo.
!"#$%&'(&$") +),)
310

Cdlgo 19.2: (Mensa[eP1ML.[ava)
public class MensajeHTML implements Mensaje {
public void hola() {
System.out.println("<html>hola</html>");
}
}

ara consLrulr ob[eLos de la clase Mensa[eP1ML vamos a hacer uso de una sencllla
facLorla (ver lmagen).


!!!"#$%&'()*(&$#+#,#"*-.
311
Ll cdlgo de la facLorla es el slgulenLe.
Cdlgo 19.3: (rlnclpal.[ava)
public class MensajeFactory {
public static Mensaje getMensaje() {
return new MensajeHTML();
}
}

8eallzada esLa operacln, vamos a crear un ob[eLo de nuesLra clase a Lraves de la
facLorla.
Cdlgo 19.4: (rlnclpal.[ava)
MensajeFactorymifactoria= new MensajeFactory()
Mensaje mensaje= mifactoria.getMensaje();
mensaje.hola ()

A conLlnuacln podemos ver el resulLado por la consola.

Asl pues la clase facLorla se encarga slmplemenLe de crear el ob[eLo y luego nosoLros
slmplemenLe lnvocamos al meLodo hola() y el cdlgo funclona perfecLamenLe.Ahora
blen, sl qulsleramos anadlr una nueva responsabllldad a la clase de Lal forma que al
lnvocar el meLodo hola se lmprlma por panLalla lo slgulenLe.

!"#$%&'(&$") +),)
312

no nos quedarla ms remedlo que anadlr una nueva funclonalldad al meLodo mensa[e
(ver lmagen).
Cdlgo 19.3: (Mensa[e.[ava)
public void mensaje(String ) {
System.out.println(funcionalidad adicional proxy);
System.out.println(<html>+mensaje+</html>);
System.out.println(funcionalidad adicional proxy);
}
ue esLa manera la funclonalldad que anadlmos queda llgada a nuesLro cdlgo de forma
LoLalmenLe esLLlca y deflnlLlva. A parLlr de ahora cuando lnvoquemos al meLodo
mensa[e slempre se lmprlmlr la funclonalldad de log. Sl queremos que la funclonalldad
anadlda sea dlnmlca y podamos e[ecuLarla en un momenLo deLermlnado o no, hay
que exLraerla de la clase en la cul la acabamos de ublcar (ver lmagen).


!!!"#$%&'()*(&$#+#,#"*-.
313
ara exLraer la responsabllldad de log crearemos una clase que se denomlne
roxyMensa[eLog. LsLa clase har de lnLermedlarla enLre la facLorla y la clase mensa[e,
anadlendo la funclonalldad exLra sln modlflcar la clase orlglnal. A conLlnuacln el cdlgo
fuenLe de la nueva clase asl como un dlagrama que ayuda a clarlflcar.
Cdlgo 19.6: (Mensa[eroxy.[ava)
public class MensajeProxy implements Mensaje {
private Mensaje mensaje;
public Mensaje getMensaje() {
return mensaje;
}
public void hola() {
System.out.println("funcionalidad adicional proxy");
mensaje.hola();
System.out.println("funcionalidad adicional proxy");
}
public MensajeProxy() {
this.mensaje = newMensajeHTML();
}
}


!"#$%&'(&$") +),)
314
La lmagen muesLra con clarldad cmo la clase Mensa[eP1ML no ha sldo modlflcada.
odemos volver a e[ecuLar nuesLro programa y veremos cmo hemos anadldo nueva
funclonalldad al concepLo de mensa[e (ver lmagen).
Sln embargo la clase Mensa[elacLory sl se habr modlflcldado para devolver un ob[eLo
de Llpo Mensa[eroxy como se muesLra a conLlnuacln.
Cdlgo 19.3: (Mensa[elacLory.[ava)
public class MensajeFactory
public static Mensaje getMensaje() {
return new MensajeProxy();
}
}

ara el cllenLe que usa la facLorla nl slqulera es vlslble que exlsLe un proxy lnLermedlo
reallzando las operaclones adlclonales ,esLo es LoLalmenLe LransparenLe para el
programador ya que el cdlgo del programa prlnclpal no varla. nosoLros podrlamos
conflgurar la facLorla para que use la clase proxy o la clase orlglnal segun nuesLras
necesldades a Lraves por e[emplo de un flchero de properLles.
2. Usando rox|es con Spr|ng
Ahora blen sl volvemos a nuesLra apllcacln e lnLenLamos reallzar un slmll, nos daremos
cuenLa de que Loda la capa de servlclos y uAC es creada a Lraves del lramework Sprlng
el cul Llene la funcln de facLorla (ver lmagen).

!!!"#$%&'()*(&$#+#,#"*-.
315

or lo LanLo al ser Sprlng una facLorla, podrla ser el encargado de consLrulr un proxy
para cada uno de los ob[eLos creados de Lal forma que sean esLos proxles los
encargados de agluLlnar la responsabllldad relaLlva a las Lransacclones (funclonalldad
adlclonal), como se muesLra en la slgulenLe flgura en la que Lodos los ob[eLos dlsponen
de un proxy a Lraves del cual se accede a los mlsmos .

Ahora blen, aunque podamos usar el framework Sprlng para que cada uno de nuesLros
ob[eLos dlsponga de un proxy con el cul gesLlonar las Lransacclones, Lenemos el
!"#$%&'(&$") +),)
316
problema de crear una clase proxy por cada una de las clases que de servlclo y uAC que
Lenemos en esLos momenLos (ver lmagen).

LsLo parece una Larea LlLnlca ya que en una apllcacln podemos Lener clenLos de
clases de servlclo o uAC. Sln embargo Sprlng posee la capacldad de generar
dlnmlcamenLe proxles basndose en las clases ya exlsLenLes sln Lener que escrlblr una
llnea de cdlgo. LsLos proxles son especlales y se les denomlna prox|es d|nm|cos ya
que son creados en &)"32* de e[ecucln. vease una lmagen del proxy:

!!!"#$%&'()*(&$#+#,#"*-.
317
LsLos Llpos de proxles quedan asoclados a los ob[eLos reales .Ll proceso de consLruccln
auLomLlca de un proxy es comple[o (ver lmagen).

vamos a expllcarlo a conLlnuacln con mayor profundldad :
1. Sprlng lee el flchero de conflguracln con los dlsLlnLos Llpos de beans exlsLenLes
2. Sprlng lnsLancla los ob[eLos requerldos por el flchero
3. Sprlng lee los meLadaLos de un ob[eLo deLermlnado que acabamos de lnsLanclar
(clase, meLodos, lnLerfaces, eLc) a Lraves del apl de reflecLlon.
4. Sprlng crea un proxy por cada ob[eLo lnsLanclado que lo neceslLe
3. Sprlng asocla el proxy al ob[eLo
or lo LanLo con Sprlng podemos crear el con[unLo de ob[eLos que neceslLemos y
aslgnarles a Lodos un proxy de forma auLomLlca . una vez hecho esLo, cada vez que
una apllcacln cllenLe desee acceder a un ob[eLo deLermlnado, el proxy acLuar de
lnLermedlarlo y anadlr la funclonalldad adlclonal que deseemos (ver lmagen).

!"#$%&'(&$") +),)
318

LsLa funclonalldad adlclonal que anadlmos a Lraves del proxy es comunmenLe conoclda
como AspecLo y es comparLldad hablLualmenLe por varlos proxles (ver lmagen).


una vez que Lenemos claro que el framework Sprlng puede generar esLos proxles,
debemos decldlr que Llpo de proxy queremos crear pues Sprlng soporLa varlos (ver
lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
319

Ln nuesLro caso vamos a deflnlr proxles que nos ayuden a gesLlonar las Lransacclones
enLre las dlsLlnLas lnvocaclones a los meLodos de la capa de perslsLencla. or ello
eleglremos los proxles de Lransaccln, que sern los encargados de e[ecuLar la
funclonalldad relaLlva a las Lransacclones (ver lmagen).



3. Conf|gurac|n de prox|es y transacc|ones.
ara poder Lraba[ar con proxles que gesLlonen Lransacclones en nuesLra apllcacln
deberemos anadlr un gesLor Lransacclonal a la conflguracln del framework Sprlng
!"#$%&'(&$") +),)
320
como la flgura anLerlor muesLra .Ln esLe caso uLlllzaremos un gesLor Lransacclonal
orlenLado a !A, que se deflne a Lraves de un bean de Sprlng.
Cdlgo 19.7: (conLexLoApllcaclon.xml)
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<propertyname="entityManagerFactory" ref="entityManagerFactory" />
</bean>

Ln segundo lugar, al flchero de conflguracln debemos anadlr una nueva eLlqueLa que
ser la encargada de crear los dlsLlnLos proxles Lransacclonales para Lodas nuesLras
clases .
Cdlgo 19.8: (conLexLoApllcaclon.[ava)
<tx:annotation-driven />

LsLa eLlqueLa, a nlvel de flchero xml, permlLlr al framework Sprlng dar de alLa proxles
para Lodas aquellas clases que dlspongan de meLodos marcados como Lransacclonales.
ara marcar los meLodos como Lransacclonales debemos anadlr un nuevo con[unLo de
anoLaclones a nuesLra apllcacln (ver cdlgo).
Cdlgo 19.9: (CenerlcuAC!Almpl.[ava)
@Transaccional

LsLas anoLaclones son aporLadas por el framework Sprlng y se encargan de deflnlr la
Lransacclonalldad para cada uno de los meLodos de nuesLras clases. A conLlnuacln se
muesLra una llsLa con los dlsLlnLos Llpos de Lransacclones soporLadas por Sprlng:
1. kequ|red :Se requlere de una Lransaccln, sl exlsLe una Lransaccln en curso, el
meLodo se e[ecuLara denLro de ella sl no, el meLodo se encargar de lnlclar una
nueva.
2. kequ|red_New :8equlere e[ecuLarse de forma Lransacclonal , sl exlsLe una
Lransaccln creada , suspender la que esLa en curso. Ln el caso de no exlsLlr
una Lransaccln, crear una.
3. Supports : Sl exlsLe una Lransaccln, se e[ecuLar denLro de ella. Sl no exlsLe, no
lnlclar nlnguna
4. Not_Supported : Se e[ecuLar fuera de una Lransaccln. Sl esLa Lransaccln
exlsLe, ser suspendlda.
!!!"#$%&'()*(&$#+#,#"*-.
321
3. Mandatory: uebe e[ecuLarse obllgaLorlamenLe de forma Lransacclonal. Sl no lo
hace, lanzar una excepcln.
6. Never :uebe e[ecuLarse slempre de forma no Lransacclonal. Sl exlsLe una
Lransaccln, lanzar una excepcln.
7. Nested :Crear una nueva Lransaccln denLro de la Lransaccln acLual.
una vez declarados los dlsLlnLos aLrlbuLos se usarn asl a nlvel de clase:
Cdlgo 19.10: (Llbro!AuAClmpl.[ava)
@Transactional(propagation=Propagation.Required)
public void insertarLibro() {
// codigo
}

ue esLa manera el meLodo se e[ecuLar de forma Lransacclonal. Ll valor
ropagaLlon.8equlred se apllca por defecLo en el caso de que no se haya especlflcado
nada. or lo LanLo, el meLodo Lamblen podrla haberse anoLado de la slgulenLe forma:

Cdlgo 19.10: (Llbro!uAuAClmpl.[ava)
@Transactional
public void insertarLibro() {
// codigo
}

Asl esLaremos senalando que el meLodo se e[ecuLa denLro de una Lransacclon.vamos a
ver como afecLan esLas anoLaclones a nuesLras clases de la capa uAC y de la capa de
Servlclos.





!"#$%&'(&$") +),)
322
Cdlgo 19.11: (CenerlcuAC!Almpl.[ava)
public abstract class GenericDAOJPAImpl<T, Id extends Serializable> extends
JpaDaoSupport implements
GenericDAO<T, Id> {
private Class<T> claseDePersistencia;

@SuppressWarnings("unchecked")
public GenericDAOJPAImpl() {
this.claseDePersistencia = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
@Override
public T buscarPorClave(Id id) {
return getJpaTemplate().find(claseDePersistencia, id);
}
@SuppressWarnings("unchecked")
@Transactional(readOnly=true)
public List<T> buscarTodos() {

return getJpaTemplate().find("select o from "
+ claseDePersistencia.getSimpleName() + " o");
}
@Transactional
public void borrar(T objeto) {
getJpaTemplate().remove(getJpaTemplate().merge(objeto));
}
@Transactional
public void salvar(T objeto) {

getJpaTemplate().merge(objeto);
}
@Transactional
public void insertar(T objeto) {
getJpaTemplate().persist(objeto);
}
}






!!!"#$%&'()*(&$#+#,#"*-.
323
Cdlgo 19.12: (ServlcloLlbroslmpl.[ava)
package com.arquitecturajava.aplicacion.servicios.impl;

//omitimos imports
public class ServicioLibrosImpl implements ServicioLibros {

private LibroDAO libroDAO=null;
private CategoriaDAO categoriaDAO=null;
//omitimos set/get
@Transactional
public void salvarLibro(Libro libro) {
libroDAO.salvar(libro);
}
@Transactional
public void borrarLibro(Libro libro) {
libroDAO.borrar(libro);
}
@Transactional
public List<Libro> buscarTodosLosLibros() {
return libroDAO.buscarTodos();
}
@Transactional
public void insertarLibro(Libro libro) {
libroDAO.insertar(libro);
}
@Transactional
public List<Libro> buscarLibrosPorCategoria(Categoria categoria) {
return libroDAO.buscarPorCategoria(categoria);
}
@Transactional
public Libro buscarLibroPorISBN(String isbn) {
return libroDAO.buscarPorClave(isbn);
}
@Transactional
public Categoria buscarCategoria(int id) {
// TODO Auto-generated method stub
return categoriaDAO.buscarPorClave(id);
}
@Transactional
public List<Categoria> buscarTodasLasCategorias() {
// TODO Auto-generated method stub
return categoriaDAO.buscarTodos();
}

}


!"#$%&'(&$") +),)
324
una vez dlspuesLas las anoLaclones que marcan los meLodos que soporLan
Lransacclones, es momenLo para mosLrar como Sprlng se encarga de e[ecuLar una
Lransaccln aLmlca enLre varlos meLodos a Lraves del uso de un con[unLo de proxles
que comparLen el mlsmo ob[eLo conexln. A conLlnuacln se muesLra un dlagrama
aclaraLorlo:


vamos a ver cul es la esLrucLura flnal del flchero de conflguracln de Sprlng con las
nuevas eLlqueLas.



!!!"#$%&'()*(&$#+#,#"*-.
325
Cdlgo 19.13: (conLexLoApllcaclon.xml.[ava)
<beans>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="dataSource
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<propertyname="driverClassName" value="com.mysql.jdbc.Driver" />
<propertyname="url"
value="jdbc:mysql://localhost/arquitecturaJavaORM" />
<propertyname="username" value="root" />
<propertyname="password" value="java" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<propertyname="persistenceUnitName" value="arquitecturaJava" />
<propertyname="dataSource" ref="dataSource" />
<propertyname="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<propertyname="databasePlatform"
value="org.hibernate.dialect.MySQL5Dialect" />
<propertyname="showSql" value="true" />
</bean>
</property>
</bean
<bean id="servicioLibros"
class="com.arquitecturajava.aplicacion.servicios.impl.ServicioLibrosImpl">
<propertyname="libroDAO" ref="libroDAO"></property>
<propertyname="categoriaDAO" ref="categoriaDAO"></property>
</bean>
<bean id="libroDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.LibroDAOJPAImpl">
<propertyname="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="categoriaDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.CategoriaDAOJPAImpl">
<propertyname="entityManagerFactory" ref="entityManagerFactory" />

</bean>
</beans>

8eallzada esLa operacln, sern los proxles los que conLrolen cmo se e[ecuLa una
Lransaccln y a cunLos meLodos afecLa de forma slmulLnea (ver lmagen).
!"#$%&'(&$") +),)
326

!"#$%"&
Ln esLe caplLulo hemos anadldo una gesLln Lransacclonal LransparenLe ,dlsLrlbulda
enLre los dlsLlnLos meLodos de la capa de servlclo y cada uAC, usando programacln
orlenLada a ob[eLo y un gesLor Lransaclonal. Asl slmpllflcamos sobremanera la gesLln
Lransaclonal que habrla sldo necesarlo desarrollar en una programacln clslca.






!!!"#$%&'()*(&$#+#,#"*-.
327

!"#$%&'(&$") +),)
328
!"#$!" $% &'"(&)*"'%! ! #$#





Pemos slmpllflcado la capa de perslsLencla y la capa de servlclos a Lraves del uso de
Sprlng LanLo como framework de lnversln de ConLrol e lnyeccln de dependencla
como usando sus capacldades de programacln orlenLada a aspecLo a la hora de
dlsenar la gesLln de Lransacclones. Sln embargo, aunque prlmeramenLe parece que no
hemos pagado nlngun preclo por ello, la realldad es dlsLlnLa. Segun pasan los caplLulos
el flchero de conflguracln (conLexLoApllcaclon.xml) que Lenemos es cada vez ms
grande y con ms elemenLos. or lo LanLo cada vez ser ms dlflcll de conflgurar y de
enLender . volvemos a la slLuacln de los caplLulos de PlbernaLe donde podlamos
acabar con un numero muy elevado de flcheros xml de mapeo. Ls momenLo de hacer
uso del prlnclplo de convencln sobre conflguracln (CCC) y, a Lraves del uso de
anoLaclones, slmpllflcar el flchero xml con el que Lraba[amos. Lse ser el ob[eLlvo del
presenLa caplLulo.









!!!"#$%&'()*(&$#+#,#"*-.
329
Objetivos:
Slmpllflcar el flchero de conflguracln de Sprlng apoyndonos en anoLaclones y
en el prlnclplo CCC.
Tareas:
1. [erslsLenceConLexL y LnLlLy manager
2. [8eposlLory y mane[o de excepclones
3. [Servlce y capas de Servlclo
4. [AuLoWlred e lnyeccln de dependencla
1. Qers|stenceContext y Lnt|tyManager
Ln esLos momenLos Lenemos dlsenada nuesLra capa uAC a Lraves de !A y uLlllzando la
clase !AuACSupporL como apoyo a la hora de crear cualqulera de nuesLras clases uAC
(ver cdlgo)

Al depender Lodas nuesLras clases de la clase !AuACSupporL, Lodas soporLarn la
aslgnacln de un enLlLyManagerlacLory a Lraves del flchero conLexLoApllcaclon.xml de
Sprlng (ver flgura).


!"#$%&'(&$") +),)
330
Cdlgo 20.1: (conLexLoApllcaclon.xml)
<bean id="libroDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.LibroDAOJPAImpl">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="categoriaDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.CategoriaDAOJPAImpl">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

Como anLerlormenLe hemos comenLado, es momenLo de lnLenLar poco a poco reduclr
esLe flchero de conflguracln y ellmlnar eLlqueLas .A Lal fln, haremos uso de una
anoLacln soporLada por el esLndar de !A: la anoLacln [erslsLenceConLexL .LsLa
anoLacln nos lnyecLar de forma dlrecLa un enLlLyManager a cada una de nuesLras
clases uAC de forma LransparenLe, sln Lener que usar eLlqueLas <properLy> a nlvel del
flchero conLexLoApllcaclon.xml . ara ello debemos anadlr esLa nueva llnea:
Cdlgo 20.2: (conLexLoApllcaclon.xml)
<context:annotation-config />

LsLa llnea se encarga de lnyecLar de forma auLomLlca el enLlLy manager a Lodas las
clases que usen la anoLacln [erslsLenceConLexL. or lo LanLo, a parLlr de esLe
momenLo, nlnguna de las clases de la capa de perslsLencla Lendr aslgnada propledades
de enLlLy manager (ver flgura).
Cdlgo 20.3: (conLexLoApllcaclon.xml)
<bean id="libroDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.LibroDAOJPAImpl">
</bean>
<bean id="categoriaDAO"
class="com.arquitecturajava.aplicacion.dao.jpa.CategoriaDAOJPAImpl">
</bean>

SeguldamenLe se muesLra la modlflcacln que hemos Lenldo que reallzar a nlvel de la
clase CenerlcuAC!Almpl.


!!!"#$%&'()*(&$#+#,#"*-.
331
Cdlgo 20.4: (CenerlcuAC!Almpl.[ava)
public abstract class GenericDAOJPAImpl<T, Id extends Serializable> implements
GenericDAO<T, Id> {
private Class<T> claseDePersistencia;
@PersistenceContext
private EntityManager manager;

public EntityManager getManager() {
return manager;
}
public void setManager(EntityManager manager) {
this.manager = manager;
}
@SuppressWarnings("unchecked")
public GenericDAOJPAImpl() {

this.claseDePersistencia = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
public T buscarPorClave(Id id) {
return getManager().find(claseDePersistencia, id);
}

@Transactional(readOnly=true)
public List<T> buscarTodos() {
List<T> listaDeObjetos = null;
TypedQuery<T> consulta = manager.createQuery("select o from "
+ claseDePersistencia.getSimpleName() + " o",
claseDePersistencia);
listaDeObjetos = consulta.getResultList();
return listaDeObjetos;
}
@Transactional
public void borrar(T objeto) {
getManager().remove(getManager().merge(objeto));
}
@Transactional
public void salvar(T objeto) {
getManager().merge(objeto);
}
@Transactional
public void insertar(T objeto) {

getManager().persist(objeto);
}
}

!"#$%&'(&$") +),)
332
Como podemos ver hemos usado dlrecLamenLe la clase manager para lnvocar los
meLodos de perslsLencla y no hemos usado para nada el meLodo geL1emplaLe() de la
clase !AuACSupporL. LsLa clase se encargaba de obLener el manager de Sprlng y de
gesLlonar las excepclones. ?a no heredamos de ella puesLo que no la neceslLamos para
lnyecLar el ob[eLo LnLlLyManager. Sln embargo sl Lenemos que gesLlonar excepclones,
una vez que hemos de[ado de heredar de !AuACSupporL, deberemos anadlr algo ms
para que Lodo funclone como anLes. La slgulenLe Larea se encargara de esLo.
2. Qkepos|tory y mane[o de excepc|ones
Sprlng puede Lraba[ar con varlos frameworks de perslsLencla desde !u8C a PlbernaLe
pasando por !A o l8aLls y para cada una de esLas soluclones genera un con[unLo de
excepclones dlsLlnLo. or lo LanLo, para que nuesLra apllcacln se comporLe de la mlsma
forma sln lmporLar cul es el framework de perslsLencla usado o cules son las
excepclones que se lanzan, deberemos marcar nuesLras clases de capa uAC con la
anoLacln [8eposlLory, la cul se encargar de Lraduclr las excepclones que se hayan
consLruldo, asl como de cerrar recursos (ver flgura).

vamos a ver cmo nuesLras clases hacen uso de la anoLacln .A conLlnuacln se
muesLra el cdlgo fuenLe de una de ellas. 1odas las clases uAC lncorporan a parLlr de
ahora esLa anoLacln.



!!!"#$%&'()*(&$#+#,#"*-.
333
Cdlgo 20.3: (conLexLoApllcaclon.xml)
@Repository
public abstract class GenericDAOJPAImpl<T, Id extends Serializable>implements
GenericDAO<T, Id>{
private Class<T> claseDePersistencia;
@PersistenceContext
private EntityManager manager;
public EntityManager getManager() {
return manager;
}

Al marcar nuesLras clases con la anoLacln [8eposlLory, consegulmos que Sprlng
gesLlone el mane[o de excepclones de una forma ms lnLegrada, encargndose de
cerrar los recursos de conexlones ablerLas eLc . Ahora blen, al marcar la clase con esLa
anoLacln, ya no ser necesarlo reglsLrar esLa clase a nlvel de conLexLoApllcaclon.xml
pues al anoLarla queda reglsLrada de forma auLomLlca. A conLlnuacln se muesLra
cmo queda nuesLro flchero.
Cdlgo 20.6: (conLexLoApllcaclon.xml)
<bean id="servicioLibros"
class="com.arquitecturajava.aplicacion.servicios.impl.ServicioLibrosImpl>
</bean>
<!eliminamos las clases dao!

Lllmlnadas las clases uAC del flchero xml, pasaremos a revlsar las clases de servlclo
para reallzar la mlsma operacln
3. Anotac|n QServ|ce
vamos a anadlr una nueva anoLacln a nuesLra clase de servlclos denomlnada [Servlce
que nos permlLe ellmlnar Lamblen esLas clases del flchero de conflguracln xml donde
las Lenemos ublcadas . A conLlnuacln se muesLra el cdlgo fuenLe de nuesLra clase una
vez anadlda la anoLacln:
Cdlgo 20.7: (conLexLoApllcaclon.xml)
@Service(value=servicioLibros)
public class ServicioLibrosImpl implements ServicioLibros {
// resto de cdigo
}

!"#$%&'(&$") +),)
334
una vez reallzada esLa operacln, podremos ellmlnar las clases de servlclo del flchero
xml y slmpllflcarlo (ver cdlgo).
Cdlgo 20.8: (conLexLoApllcaclon.xml)
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!eliminamos las clases de servicio!

Pemos ellmlnado Lodas las clases de servlclo y clases uAC de nuesLro flchero xml ya
que a Lraves de las anoLaclones se reglsLran como componenLes de forma auLomLlca.
ara ello, unlcamenLe deberemos anadlr la slgulenLe llnea de cdlgo a nuesLro flchero:
<context:component-scan base-package="com.arquitecturajava.aplicacion.*" />

LsLa llnea se encargar de buscar en los dlsLlnLos paqueLes clases anoLadas y
reglsLrarlas sln necesldad de que aparezcan en el flchero. Pecho esLo, ya Lenemos Lodas
las clases reglsLradas. LamenLablemenLe el flchero xml no slo se encargaba de
reglsLrarlas slno Lamblen de relaclonarlas a Lraves de la eLlqueLa <properLy> y esLa
funclonalldad Lodavla no la hemos cublerLo. La slgulenLe anoLacln nos ayudar a
cumpllr con esLa Larea.
4. Anotac|ones QAutoW|red
La anoLaclon [AuLoWlred esL basada en el prlnclplo de convencln sobre
conflguracln para slmpllflcar la lnyecclon de dependenclas enLre las dlsLlnLas clases. Se
encarga de buscar las relaclones exlsLenLes enLre los dlsLlnLos ob[eLos reglsLrados e
lnyecLa de forma auLomLlca las dependenclas( ver lmagen).

!!!"#$%&'()*(&$#+#,#"*-.
335

una vez Lenemos claro cmo funclona esLa anoLacln, vamos a ver cmo queda el
codlgo de la clase de servlclo.
Cdlgo 20.6: (ServlcloLlbroslmpl.xml)
@Service(value="servicioLibros")
public class ServicioLibrosImpl implements ServicioLibros {
private LibroDAO libroDAO=null;
private CategoriaDAO categoriaDAO=null;
@Autowired
public void setLibroDAO(LibroDAO libroDAO) {
this.libroDAO = libroDAO;
}
@Autowired
public void setCategoriaDAO(CategoriaDAO categoriaDAO) {
this.categoriaDAO = categoriaDAO;
}
//resLo de cdlgo

ue esLa manera hemos pasado de una conflguracln basada excluslvamenLe en flcheros
xml a una conflguracln en la que las anoLaclones Llenen mas peso y el flchero se
reduce slgnlflcaLlvamenLe (ver lmagen).
!"#$%&'(&$") +),)
336

Las anoLaclones y el prlnclplo de convenclon sobre conflguracln nos han permlLldo
ellmlnar lnformacln redundanLe a nlvel de la conflguracln. SeguldamenLe se muesLra
cmo queda el flchero conLexLoApllcaclon.xml , podemos ver cmo claramenLe ha sldo
slmpllflcado sln Lener que reglsLrar nlnguna clase.
<tx:annotation-driven />
<context:annotation-config />
<context:component-scan base-package="com.arquitecturajava.aplicacion.*" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost/arquitecturaJavaORM" />
<property name="username" value="root" />
<property name="password" value="java" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
>
<property name="persistenceUnitName" value="arquitecturaJava" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform"
value="org.hibernate.dialect.MySQL5Dialect" />
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
!!!"#$%&'()*(&$#+#,#"*-.
337
!"#$%"&
Ln esLe caplLulo hemos conseguldo slmpllflcar sobremanera el flchero de conflguracln
de Sprlng apoyandomos en el concepLos de convencln sobre conflguracln asl como
en la programacln orlenLada a aspecLo.

!"#$%&'(&$") +),)
338
!"#!"#" %&'#&' (")&*






Ln los ulLlmos caplLulos nos hemos cenLrado en el uso de Sprlng para me[orar y
slmpllflcar la consLruccln de la capa de perslsLencla y de servlclos de nuesLra
apllcacln. Ls momenLo de volver a mlrar hacla la capa de presenLacln que hemos
consLruldo apoyndonos en el sLandard de !S1L y hacerla evoluclonar hacla esLndares
ms acLuales, en concreLo hacla !ava Server laces o !Sl . !Sl es el framework sLandard
a nlvel de capa de presenLacln en arqulLecLuras !LL. LsLe caplLulo servlr de
lnLroduccln a !Sl .Se crearn algunos e[emplos uLlles a la hora de mlgrar la apllcacln a
esLa Lecnologla en prxlmos caplLulos
Cb[et|vos:
lnLroduclr !Sl y desarrollar unos e[emplos bslcos que nos sean uLlles cuando
mlgremos nuesLra apllcacln

1areas:
1. lnLroducclon a !Sl.
2. lnsLalar !Sl 2.0.
3. PolaMundo con !Sl
4. ConsLruccln de un combo con !Sl
3. Creacln de Labla con !Sl

!!!"#$%&'()*(&$#+#,#"*-.
339
1. Introducc|n a ISI
PasLa esLe momenLo hemos usado !S1L y un modelo MvC2 para gesLlonar la capa de
presenLacln. Ahora blen, la capa de presenLacln consLrulda hasLa esLe momenLo se
basa en el uso de un con[unLo de eLlqueLas senclllas como son las eLlqueLas <c:forLach>
y <c:ouL> que se muesLran en la slgulenLe flgura y que esLn llgadas al modelo MvC2 y
su conLrolador.


Ls momenLo de avanzar y modlflcar el con[unLo de eLlqueLas que Lenemos para poder
usar eLlqueLas ms comple[as que aporLen mayor funclonalldad. Son eLlqueLas
aporLadas por el framework de !Sl y en lugar de deflnlr bubles senclllos o senLenclas lf
esLn orlenLadas a deflnlr conLroles comple[os , de Lal forma que el desarrollador pueda
uLlllzar esLos conLroles para desarrollar apllcaclones de mayor comple[ldad ms
rpldamenLe . A conLlnuacln se muesLra una lmagen aclaraLorla.

!"#$%&'(&$") +),)
340


Como podemos ver, en esLe caso las eLlqueLas deflnen un formularlo y una Labla que
muesLra una llsLa de daLos asl como un nuevo conLrolador. Ls evldenLe que el nlvel de
absLraccln se ha lncremenLado. una vez expllcado el concepLo a nlvel general, vamos a
lnsLalar el framework de !Sl y crear unos e[emplos senclllos.
2. Insta|ac|n de ISI
ara lnsLalar el framework de !ava Server laces en nuesLra apllcacln debemos
acceder a la slgulenLe url y obLener las llbrerlas necesarlas. Ln esLe caso las que
correspondan a la versln 2.x.
hLLp://[avaserverfaces.[ava.neL/
una vez obLenldo el framework, es necesarlo exLraer los slgulenLes flcheros [ar del zlp
que acabamos de ba[ar
[sf-apl.[ar.
[sf-lmpl.[ar.

!!!"#$%&'()*(&$#+#,#"*-.
341
llnalmenLe exLraemos los flcheros al dlrecLorlo llb de nuesLra apllcacln.

8eallzada esLa operacln, vamos a pasar a conflgurar el proplo framework .A dlferencla
de la slLuacln acLual en la que nosoLros Lenemos consLruldo con conLrolador para
nuesLra apllcacln ,el framework de !Sl aporLa un conLrolador pre consLruldo que se
denomlna lacesServleL. Asl , para poder Lraba[ar con !Sl hay que dar de alLa un nuevo
conLrolador a nlvel de web.xml y ellmlnar el exlsLenLe. A conLlnuacln se muesLra
cmo dar de alLa el nuevo conLrolador en el web.xml.
Cdlgo 21.1: (web.xml)
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>

AnLes de enLrar a modlflcar nuesLra apllcacln, vamos a consLrulr una serle de e[emplos
senclllos que nos permlLan conocer la Lecnologla y mane[ar esLe nuevo conLrolador.
!"#$%&'(&$") +),)
342
3. no|a Mundo con ISI
PasLa esLe momenLo nuesLra capa de presenLacln se basaba fundamenLalmenLe en un
conLrolador y un con[unLo de acclones asoclados a esLe (ver lmagen).

Al usar el framework de !Sl no vamos a Lener la necesldad de apoyarnos en un
con[unLo de acclones como Lal, slno que el framework se apoya en un nuevo concepLo
denomlnado Managed8ean. or lo LanLo a parLlr de ahora nuesLro nuevo conLrolador
laceServleL se apoyar en un con[unLo de Managed8eans para reallzar las operaclones
(ver lmagen).


un managed8ean es una clase que reallza Lareas de lnLermedlarlo enLre la capa de
presenLacln y la capa de servlclos . or lo LanLo Lodas las paglnas !Sl se apoyan en
ellas para envlar o reclblr lnformacln (ver lmagen).

!!!"#$%&'()*(&$#+#,#"*-.
343


Los Managed8eans desempenan el mlsmo rol que Lenlan hasLa ahora los comandos o
acclones pero a dlferencla de esLos, son capaces de LraLar con varlos evenLos y no con
uno solo, como ocurre con las acclones consLruldas hasLa ahora. vamos a comenzar a
Lomar conLacLo con !Sl como Lecnologla de capa de presenLacln. ara ello nos vamos
a consLrulr nuesLra paglna de PolaMundo usando !Sl. Ln esLe caso vamos a parLlr de un
formularlo elemenLal que nos sollclLa un nombre (ver lmagen).
una vez que Lenemos claro cul es el aspecLo del formularlo, vamos a ver el codlgo
fuenLe a nlvel de !Sl.
Cdlgo 21.2: (formularlonombre.xhLml)

<htmlxmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:viewcontentType="text/html"/>
<h:head>
<title>HolaMundo</title>
</h:head>
<h:body>
<h:form id="holaMundo">
<h:inputText id="nombreUsuario"value="#{usuarioBean.nombre}"/>
<h:commandButton id="submit"action="resultado"value="Aceptar"/>
</h:form>
</h:body>
</html>

!"#$%&'(&$") +),)
344
odemos observar que las eLlqueLas de !Sl Llenen clerLa slmlllLud con las eLlqueLas !S1L
y la dlferencla ms lmporLanLe enLre ellas es que las !Sl esLn claramenLe orlenLadas a
la deflnlcln de conLroles, como es el caso de la eLlqueLa <h:lnpuL1exL> que deflne una
ca[a de LexLo.
Cdlgo 21.3: (formularlonombre.xhLml)
<h:inputText id="nombreUsuario"value="#{usuarioBean.nombre}"/>

una vez deflnlda la ca[a de LexLo, deflne el slgulenLe aLrlbuLo
Cdlgo 21.4: (formularlonombre.xhLml)
value="#{usuarioBean.nombre}"

LsLe aLrlbuLo deflne que el valor que se escrlba en la ca[a de LexLo esL asoclado a un
Managed8ean , concreLamenLe al campo nombre de esLe managed8ean. vamos pues a
ver cmo se consLruye un Managed8ean que esLe asoclado a esLe formularlo.
Cdlgo 21.3: (formularlonombre.xhLml)
package com.arquitectura.beans;
import javax.faces.bean.ManagedBean;

@ManagedBean
public class UsuarioBean {

private String nombre;
Public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
}

vlslblemenLe se LraLa de una sencllla clase [ava a la que se le aslgna una nueva
anoLaclon [Managed8ean. una vez aslgnada esLa anoLacln al formularlo, !Sl y el
managed8ean se relaclonan a Lraves de la eLlqueLa.

!!!"#$%&'()*(&$#+#,#"*-.
345
Cdlgo 21.6: (formularlonombre.xhLml)
<h:inputText id="nombreUsuario"value="#{usuarioBean.nombre}"/>

Como la slgulenLe lmagen muesLra.

una vez que Lenemos claro esLa relacln, vamos a expllcar el oLro conLrol que exlsLe a
nlvel de la pglna y que conslsLe en un boLn.
Cdlgo 21.7: (formularlonombre.xhLml)
<h:commandButton id="submit"action="resultado"value="Aceptar"/>

LsLe boLn slmplemenLe se encarga de lnvocar a oLra paglna denomlnada
resulLado.xhLml haclendo uso del aLrlbuLo acLlon. una vez pulsado el boLn
accederemos a la hora paglna que mosLrar la slgulenLe esLrucLura:

vlsLo el resulLado, vamos a comprobar cul es la esLrucLura de la pglna
resulLado.xhLml.
!"#$%&'(&$") +),)
346

Cdlgo 21.8: (formularlonombre.xhLml)
<htmlxmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:viewcontentType="text/html; charset=iso-8859-1"/>
<head><title>Respuesta</title></head>
<body>
<h:form id="formularioRespuesta">
<h2>Hola, #{usuarioBean.nombre}</h2>
<h:commandButton id="volver" value="volver" action="formularioNombre" />
</h:form>
</body>
</html>

ue esLa manera quedan llgadas las dos pglnas al managed8ean. La prlmera envla
daLos al managed8ean, que los almacena. La segunda pglna lee daLos del
Managed8ean. La slgulenLe flgura aclara los concepLos:

4. Constru|r un combo con ISI
Acabamos de ver el e[emplo ms senclllo de !Sl .Sln embargo en nuesLra apllcacln
exlsLen dos slLuaclones algo mas comple[as. La prlmera es la carga del desplegable de
caLegorlas y la segunda la presenLacln de daLos en una Labla . vamos a cubrlr cada una
de esLas slLuaclones usando !Sl con e[emplos bslcos para luego lnLegrarlos en nuesLra
!!!"#$%&'()*(&$#+#,#"*-.
347
apllcacln. A Lal fln comenzaremos usando !Sl para cargar una llsLa de elemenLos en un
formularlo senclllo (ver lmagen).
una vez que Lenemos claro que debemos consLrulr vamos a verlo con deLalle en el
slgulenLe bloque de cdlgo.
Cdlgo 21.9: (formularloSelecclon.xhLml)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<htmlxmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:viewcontentType="text/html"/>
<h:head>
<title>HolaLista</title>
</h:head>
<h:body>
<h:form id="holaMundo">
<h:selectOneMenuvalue="#{usuarioBeanLista.nombre}">
<f:selectItemsvalue="#{usuarioBeanLista.listaNombres}" />
</h:selectOneMenu>
<h:commandButton id="submit"action="resultadoLista"value="Aceptar"/>
</h:form>
</h:body>
</html>

Ls evldenLe que nuesLro cdlgo fuenLe hace uso de un nuevo conLrol como se muesLra
a conLlnuacln.


!"#$%&'(&$") +),)
348
Cdlgo 21.10: (formularloSelecclon.xhLml)
<h:selectOneMenuvalue="#{usuarioBeanLista.nombre}">

LsLe conLrol es el encargado de deflnlr un combo desplegable .Ahora blen, recordemos
que esLos conLroles reallzan las dos slgulenLes funclones:
MosLrar una llsLa de elemenLos
ermlLlr selecclonar uno
ara mosLrar la llsLa de elemenLos nuesLro conLrol hace uso de la slgulenLe eLlqueLa

Cdlgo 21.11: (formularloSelecclon.xhLml)
<f:selectItems value="#{usuarioBeanLista.listaNombres}" />

apoyndose en un managed8ean denomlnado usuarlo8eanLlsLa, que carga
una llsLa de elemenLos .or oLro lado, para eleglr un elemenLo y almacenarlo, hace uso
del mlsmo bean y de la propledad nombre.
Cdlgo 21.12: (formularloSelecclon.xhLml)
<h:selectOneMenu value="#{usuarioBeanLista.nombre}">

una vez claros cules son los elemenLos que ha de Lener nuesLro Managed8ean, vamos
a mosLrar su cdlgo fuenLe.






!!!"#$%&'()*(&$#+#,#"*-.
349
Cdlgo 20.12: (formularloSelecclon.xhLml)
package com.arquitectura.beans;
//omitimos import
@ManagedBean
public class UsuarioBeanLista {
privateList<SelectItem>listaNombres;

private String nombre;

public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public List<SelectItem>getListaNombres() {

listaNombres= new ArrayList<SelectItem>();
listaNombres.add(new SelectItem("1","nombre1"));
listaNombres.add(new SelectItem("2","nombre2"));
listaNombres.add(new SelectItem("2","nombre3"));
returnlistaNombres;
}

}

ConsLruldos Lodos los elemenLos, podemos cargar la pglna y selecclonar un elemenLo
de la llsLa.uespues, pulsamos el boLon que dlspone de un aLrlbuLo acLlon.
Cdlgo 20.13: (formularloSelecclon.xhLml)
<h:commandButton id="submit" action="resultadoLista"value="Aceptar"/>

LsLe aLrlbuLo se encarga de redlrlglrnos a la pglna de desLlno denomlnada
resulLadoLlsLa.xhLml que se muesLra a conLlnuacln:
!"#$%&'(&$") +),)
350
odemos ver cmo se muesLra el valor del elemenLo que selecclonamos prevlamenLe.
SeguldamenLe se muesLra el cdlgo de la paglna de desLlno.

Cdlgo 20.14: (formularloSelecclon.xhLml)
<htmlxmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:viewcontentType="text/html; charset=iso-8859-1"/>
<head><title>RespuestaLista</title></head>
<body>
<h:form id="formularioRespuesta">
<h2>Hola, #{usuarioBeanLista.nombre}</h2>
<h:commandButton id="volver" value="volver" action="formularioSeleccion" />
</h:form>
</body>
</html>

Pemos Lermlnado de ver como consLrulr un desplegable con !Sl y cargarlo con daLos,
concreLamenLe con elemenLos del Llpo SelecLlLem. Ls momenLo de avanzar un poco
ms y ver cmo consLrulr una Labla : el ulLlmo elemenLo que neceslLamos.
S. Crear 1ab|a con ISI
vamos a consLrulr una Labla y cargarla de daLos usando la Lecnologla !Sl. ara ello
vamos a apoyarnos en el concepLo de usuarlo (nombre, edad) . La Labla que aparecer
ser algo slmllar a lo slgulenLe:

una vez que Lenemos claro como ha de ser la Labla, vamos a ver el cdlgo fuenLe de la
pglna 1ablausuarlos.xhLm.
!!!"#$%&'()*(&$#+#,#"*-.
351
Cdlgo 20.13: (1ablausuarlos.xhLml)
<htmlxmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:viewcontentType="text/html"/>
<body>
<h:form>
<h:dataTable id="tabla"value="#{tablaUsuarioBean.usuarios}" var="usuario">
<h:column>
<h:outputTextvalue="#{usuario.nombre}"/>,
<h:outputTextvalue="#{usuario.edad}"/>
</h:column>
</h:dataTable>
</h:form>
</body>
</html>

Llaborada la paglna !Sl, vamos a consLrulr los dos elemenLos que neceslLamos para
cargar la Labla de daLos: una clase usuarlo y un Managed8ean que nos devuelva una
llsLa de ellos .vamos a ver el cdlgo fuenLe de cada uno:
Cdlgo 20.16: (1ablausuarlos.xhLml)
package com.arquitectura.beans;
public class Usuario {
private String nombre;
private int edad;
public Usuario(String nombre, int edad) {
super();
this.nombre = nombre;
this.edad = edad;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public int getEdad() {
return edad;
}
public void setEdad(int edad) {
this.edad = edad;
}
}

!"#$%&'(&$") +),)
352
Cdlgo 20.17: (1ablausuarlo8ean)
//omitimos imports
@ManagedBean
public class TablaUsuarioBean {

private List<Usuario> usuarios;

public void setUsuarios(List<Usuario> usuarios) {
this.usuarios=usuarios;
}

public List<Usuario> getUsuarios() {
return usuarios;
}

@PostConstruct
public void iniciar() {
Usuario u= new Usuario("pedro",25);
Usuario u1= new Usuario("crhistina",30);
usuarios = new ArrayList<Usuario>();
usuario.add(u);
usuario.add(u1);

}
}


Como podemos ver el cdlgo del meLodo lnlclar() se encarga de rellenar la llsLa de
usuarlos que neceslLaremos en la Labla haclendo uso de la anoLacln [osLConsLrucL
que deflne que meLodo e[ecuLar una vez creado el Managed8ean. vlsLo cmo consLrulr
Lres de los elemenLos bslcos necesarlos para nuesLra apllcacln, podremos en el
slgulenLe caplLulo abordar la mlgracln de nuesLra apllcacln a !Sl.
!"#$%"&
Ln esLe caplLulo no hemos avanzado en el a dlseno de la arqulLecLura de la apllcacln
pero hemos presenLado una Lecnologla que perLenece a los esLndares !LL y que
usaremos en el prxlmo caplLulo para slmpllflcar la apllcacln .



!!!"#$%&'()*(&$#+#,#"*-.
353







!"#$%&'(&$") +),)
354
!!"#$%&'($)* ' ,'-' ./&-/& 0'(/1






Ln el caplLulo anLerlor hemos reallzado una breve lnLroduccln a !Sl ya que se LraLa de
un framework de capa de presenLacln que Llene clerLa comple[ldad .Ln esLe caplLulo
vamos a hacer mlgrar nuesLra apllcacln a !Sl. ara ello neceslLaremos ellmlnar algunas
clases consLruldas anLerlormenLe y agregar oLras nuevas.

Cb[et|vos:
usar !Sl como framework de presenLacln en nuesLra apllcacln.
1areas:
1. Anadlr conLrolador de !Sl y ellmlnar el exlsLenLe con sus acclones.
2. Crear un Managed8ean
3. Crear la paglna MosLrarLlbros.xhLml
4. 8orrar Llbro
3. lnserLar Llbro
6. LdlLar Llbro
7. lllLrar llsLa de Llbros
8. Me[ora Lxpresslon Language
9. lnLegracln Sprlng


!!!"#$%&'()*(&$#+#,#"*-.
355
1. Aad|r contro|ador de ISI y e||m|nar e| ex|stente
PasLa esLe momenLo hemos usado un conLrolador consLruldo por nosoLros mlsmos
para gesLlonar Lodo el flu[o de la capa de presenLacln. A parLlr de esLos momenLos no
nos ser necesarlo ya que como hemos vlsLo en el caplLulo anLerlor, !Sl nos provee de
un conLrolador proplo. Asl pues nuesLro prlmer paso a la hora de mlgrar la apllcacln a
!Sl es ellmlnar el cdlgo del conLrolador exlsLenLe mosLrado a conLlnuacln.
Cdlgo 22.1 (web.xml)
<servlet>
<description></description>
<display-name>ControladorLibros</display-name>
<servlet-name>ControladorLibros</servlet-name>
<servlet-class>com.arquitecturajava.aplicacion.controlador.ControladorLibros</servlet-
class>
</servlet>
<servlet-mapping>
<servlet-name>ControladorLibros</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

Lllmlnado esLe conLrolador, lnsLalaremos como en el caplLulo anLerlor las llbrerlas de
!Sl en la carpeLa llb y anadlremos el conLrolador de !Sl a nuesLro web.xml (ver lmagen)
Cdlgo 22.2: (web.xml)
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>

una vez ellmlnado el conLrolador anLlguo y creado uno nuevo, se presenLa oLro
problema: a nlvel de nuesLro cdlgo fuenLe el conLrolador anLlguo gesLlonaba un
con[unLo de acclones (ver lmagen).

!"#$%&'(&$") +),)
356







Ls en esLas acclones donde se encuenLra ublcada la lglca que llga la capa de
presenLacln con la capa de negoclo y perslsLencla. Sl revlsamos esLas acclones en
profundldad, observaremos que, para las pocas que hemos dlsenado, muchas
comparLen cdlgo, como es el caso de ModlflcarLlbroAcclon y lnserLarLlbroAcclon, que
gesLlonan las mlsmas varlables y no cumplen con el prlnclplo u8?, ya que gesLlonan
varlables ldenLlcas de la mlsma forma (ver lmagen)


ue la mlsma forma que hemos subsLlLuldo un conLrolador por oLro, es momenLo de
subsLlLulr un con[unLo de acclones por un Managed8ean (ver lmagen)
!!!"#$%&'()*(&$#+#,#"*-.
357

Asl pues una vez ellmlnado el conLrolador y las acclones de nuesLra apllcacln, la
esLrucLura de paqueLes a nlvel de capa de presenLacln ser la slgulenLe.


Ls evldenLe que han sldo ellmlnados los paqueLes relaclonados con el conLrolador y las
acclones y unlcamenLe se ha anadldo un nuevo paqueLe denomlnado beans, que
conLlene un unlcoManagedbean debldo a reducldo Lamano de nuesLra apllcacln.
AnLes de crear nuesLro Managed8ean debemos recordar que esLa clase es la que hace
las funclones de nexo con la capa de servlclos y por lo LanLo con Loda la lnfraesLrucLura
que hemos dlsenado con Sprlng framework. Asl, el prlmer paso que debemos dar es ver
cmo podemos conflgurar el framework de !Sl para que pueda hacer uso de Sprlng. Ln
prlnclplo no hace falLa reallzar nlnguna operacln especlal y lo conflgurado
anLerlormenLe valdr. Ahora blen, cuando consLruyamos el Managed8ean debemos
!"#$%&'(&$") +),)
358
Lener en cuenLa que hacemos uso de Sprlng a la hora de llgar la capa de servlclos con el
de una forma orlenLada a !Sl.
2. Creac|n Managed8ean
Como vlmos en el caplLulo anLerlor, consLrulr un managed8ean no es algo compllcado.
SlmplemenLe deberemos usar la anoLacln [Managed8ean .no obsLanLe, el
Managed8ean que nosoLros vamos a consLrulr almacenar Loda la funclonalldad
ublcada en las dlsLlnLas acclones en una sola clase (ver lmagen).

A conLlnuacln se muesLra el codlgo fuenLe de esLa clase, que Llene un mblLo de
sesln que en nuesLro caso es lo mas cmodo debldo al Lamano de la apllcacln
(pequena), asl esLar acceslble slempre. Aunque Lenemos que Lener claro que abusar
de esLe Llpo de mblLo puede produclr problemas lmporLanLes de escalabllldad . Ln el
mane[o de !Sl es clave Lraba[ar de forma correcLa con los dlsLlnLos mblLos.





!!!"#$%&'()*(&$#+#,#"*-.
359
Cdlgo 22.3: (lormularloLlbroManaged8ean.[ava)
//omitimos imports
@ManagedBean
@SessionScoped
public class FormularioLibroManagedBean {

private String isbn;
private String titulo;
private String categoria;
private List<SelectItem> listaDeCategorias;
private List<Libro> listaDeLibros;

public List<Libro> getListaDeLibros() {

return listaDeLibros;
}

@PostConstruct
public void iniciar() {

listaDeLibros = getServicioLibros().buscarTodosLosLibros();

List<Categoria> categorias = getServicioLibros()
.buscarTodasLasCategorias();
listaDeCategorias = new ArrayList<SelectItem>();
for (Categoria categoria : categorias) {
listaDeCategorias.add(new SelectItem(categoria.getId(),
!!!!!!!!!!..categoria.getDescripcion()));
}


}

public void setListaDeLibros(List<Libro> listaDeLibros) {
this.listaDeLibros = listaDeLibros;
}

public List<SelectItem> getListaDeCategorias() {


return listaDeCategorias;
}

public void setListaDeCategorias(List<SelectItem> listaDeCategorias) {
this.listaDeCategorias = listaDeCategorias;
}

public String getIsbn() {
return isbn;
!"#$%&'(&$") +),)
360
}

public void setIsbn(String isbn) {
this.isbn = isbn;
}

public String getTitulo() {
return titulo;
}

public void setTitulo(String titulo) {
this.titulo = titulo;
}

public String getCategoria() {
return categoria;
}

public void setCategoria(String categoria) {
this.categoria = categoria;
}

public void insertar(ActionEvent evento) {

getServicioLibros().insertarLibro(
new Libro(isbn, titulo, new Categoria(Integer
.parseInt(categoria))));
setListaDeLibros(getServicioLibros().buscarTodosLosLibros());
categoria="0";
}

public void borrar(ActionEvent evento) {


UIComponent componente = (UIComponent) evento.getComponent();
String isbn = componente.getAttributes().get("isbn").toString();
getServicioLibros().borrarLibro(new Libro(isbn));
setListaDeLibros(getServicioLibros().buscarTodosLosLibros());


}

public void filtrar(ValueChangeEvent evento) {

int idCategoria = Integer.parseInt(evento.getComponent()
.getAttributes().get("value").toString());

if(idCategoria!=0) {

setListaDeLibros(getServicioLibros().
!!!"#$%&'()*(&$#+#,#"*-.
361
buscarLibrosPorCategoria(new Categoria(idCategoria)));
}else {

!!!!!!!setListaDeLibros(getServicioLibros().
buscarTodosLosLibros());
}
}

public void editar(ActionEvent evento) {

UIComponent componente = (UIComponent) evento.getComponent();
Libro libro = getServicioLibros().buscarLibroPorISBN(
componente.getAttributes().get("isbn").toString());
isbn = libro.getIsbn();
titulo = libro.getTitulo();
}
public void formularioInsertar(ActionEvent evento) {
isbn = "";
titulo = "";
}
public void salvar(ActionEvent evento) {
getServicioLibros().salvarLibro(
new Libro(isbn, titulo, new Categoria(Integer
.parseInt(categoria))));
setListaDeLibros(getServicioLibros().buscarTodosLosLibros());
categoria="0";
}
public ServicioLibros getServicioLibros() {
ApplicationContext contexto = FacesContextUtils

.getWebApplicationContext(FacesContext.getCurrentInstance());
return (ServicioLibros) contexto.getBean("servicioLibros");
}
}

Como podemos ver, el Managed8ean que hemos consLruldo Llene basLanLe cdlgo
mucho del cul Lodavla no hemos expllcado . vamos a lr comenLando los dlsLlnLos
bloques segun los vayamos neceslLando. Ln prlmer lugar vamos a hablar del meLodo
geLServlcloLlbros() cuyo cdlgo mosLramos a conLlnuacln.




!"#$%&'(&$") +),)
362
Cdlgo 22.4: (lormularloLlbroManaged8ean.[ava)
public ServicioLibros getServicioLibros() {
ApplicationContext contexto = FacesContextUtils
.getWebApplicationContext(FacesContext.getCurrentInstance());
return (ServicioLibros) contexto.getBean("servicioLibros");
}

LsLe meLodo es el que se encarga de cargar Lodos los beans a nlvel de framework
Sprlng y ponerlos a dlsposlcln de !Sl. una vez conflgurado el framework Sprlng,
podemos lnvocar a la clase ServlcloLlbros y e[ecuLar los dlsLlnLos meLodos, como por
e[emplo geLLlbros() y geLCaLegorlas(). LsLa operacln la reallzaremos a Lraves del
meLodo lnlclar, que se encargar de que la propledad llsLaueLlbros y llsLaueCaLegorlas
se rellenen de forma correcLa . A conLlnuacln se muesLra el cdlgo fuenLe de esLe
meLodo:
Cdlgo 22.3: (lormularloLlbroManaged8ean.[ava)
@PostConstruct
public void iniciar() {
listaDeLibros = getServicioLibros().buscarTodosLosLibros();
List<Categoria> categorias = getServicioLibros()
.buscarTodasLasCategorias();
listaDeCategorias = new ArrayList<SelectItem>();
for (Categoria categoria : categorias) {
listaDeCategorias.add(new SelectItem(categoria.getId(),
!!!!!!!categoria.getDescripcion()));
}
}

vamos a crear seguldamenLe la pglna MosLrarLlbros.xhml y ver cmo se apoya en las
varlables que hemos aslgnado en el consLrucLor.
3. Crear MostrarL|bro.xhtm|
Ln el caplLulo anLerlor hemos vlsLo cmo podemos consLrulr una paglna !Sl que sea
capaz de mosLrar una llsLa de personas.Ln cuanLo a nuesLra apllcacln, se LraLa de un
e[emplo slmllar en el cul debemos mosLrar una llsLa de llbros .ara ello el cdlgo que
consLrulremos ser el slgulenLe, que se apoya compleLamenLe en !Sl.


!!!"#$%&'()*(&$#+#,#"*-.
363
Cdlgo 22.6: (MosLrarLlbro.xhLml.)
<htmlxmlns=http://www.w3.org/1999/xhtml xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:view>
<body>
<h:form>
<h:selectOneMenu id="combo"
valueChangeListener="#{formularioLibroManagedBean.filtrar}"
value="#{formularioLibroManagedBean.categoria}" onchange="submit()">
<f:selectItemitemValue="0" itemLabel="seleccionar" />
<f:selectItems
value="#{formularioLibroManagedBean.listaDeCategorias}" />
</h:selectOneMenu>
<h:dataTable id="tabla"
value="#{formularioLibroManagedBean.listaDeLibros}"
var="libro">
<h:column>
#{libro.isbn}
</h:column>
<h:column>
#{libro.titulo}
</h:column>
<h:column>
#{libro.categoria.descripcion}
</h:column>
<h:column>
<h:commandLinkvalue="borrar"
actionListener="#{formularioLibroManagedBean.borrar}" >
<f:attributename="isbn" value="#{libro.isbn}" />
</h:commandLink>
</h:column>
<h:column>
<h:commandLinkvalue="editar"
actionListener="#{formularioLibroManagedBean.editar}"
action="FormularioEditarLibro">
<f:attributename="isbn" value="#{libro.isbn}" />
</h:commandLink>
</h:column>
</h:dataTable>
<h:commandButton
actionListener="#{formularioLibroManagedBean.formularioInsertar}"
action="FormularioInsertarLibro" value="insertar"/>
</h:form>
</body>
</f:view>
</html>

!"#$%&'(&$") +),)
364
una vez Lenemos el cdlgo de la paglna MosLrarLlbros.xhml vamos a comenLar algunas
de las llneas como la slgulenLe.
Cdlgo 22.6: (MosLrarLlbro.xhLml.)
<f:selectItems value="#{formularioLibroManagedBean.listaDeCategorias}" />

LsLa llnea de encarga de cargar el combo de caLegorlas con la llsLa de caLegorlas que
nos devuelve nuesLro managed8ean. Algo slmllar hace la slgulenLe llnea
Cdlgo 22.7: (MosLrarLlbro.xhLml)
<h:dataTable id="tabla"
value="#{formularioLibroManagedBean.listaDeLibros}"
var="libro">

Cue se encarga de cargar la llsLa de llbros a Lraves del managed8ean. una vez que
Lenemos ambas colecclones cargadas !Sl nos mosLrara la slgulenLe pglna al sollclLar
MosLrarLlbros.xhLml.

or ahora unlcamenLe hemos comenLado la funclonalldad que se encarga de cargar
correcLamenLe los daLos en la paglna .Sln embargo no hemos cublerLo Lodavla el boLn
de lnserLar nl los llnks de edlLar y borrar. vamos a lr avanzando con esLos elemenLos
poco a poco.

!!!"#$%&'()*(&$#+#,#"*-.
365
4. 8orrar L|bro
Sl revlsamos el cdlgo de la paglna MosLrarLlbros.xhLml nos enconLraremos con lo
slgulenLe.
Cdlgo 22.7: (MosLrarLlbro.xhLml)

<h:commandLink value="borrar"
actionListener="#{formularioLibroManagedBean.borrar}">
<f:attribute name="isbn"value="#{libro.isbn}" />
</h:commandLink>


LsLe conLrol de !Sl es un conLrol de Llpo CommandLlnk o enlace se encargar de
lnvocar a nuesLro managed8ean y e[ecuLara el meLodo borrar. una vez e[ecuLado,
volver a cargar la mlsma pglna. vamos a mosLrar a conLlnuacln el cdlgo de la
funcln borrar de nuesLro managed8ean.
Cdlgo 22.8: (lormularloLlbroManaged8ean.xhLml)
public void borrar(ActionEvent evento) {
UIComponent componente = (UIComponent) evento.getComponent();
String isbn = componente.getAttributes().get("isbn").toString();
getServicioLibros().borrarLibro(new Libro(isbn));
setListaDeLibros(getServicioLibros().buscarTodosLosLibros());
}

LsLe meLodo se encarga prlmero de obLener el componenLe que lo lnvoc, en esLe caso
es un CommandLlnk ,componenLe que exLlende de ulComponenL. una vez que
Lenemos el componenLe accedemos a su coleccln de aLrlbuLos y obLenemos el lsbn del
Llbro. Pecho esLo dlsponemos del lsbn e lnvocamos al meLodo borrar de la clase
ServlcloLlbros y borramos el reglsLro de la base de daLos .or ulLlmo volvemos a cargar
la nueva llsLa de llbros.
Acabamos de ver como nuesLra apllcacln usa !Sl para mosLrar y ellmlnar reglsLros es
momenLo de segulr cubrlendo funclonalldad y ver como lmplemenLar la lglca de
lnsercln de llbros a Lraves de !Sl.
!"#$%&'(&$") +),)
366
S. Inserc|n L|bro
ara reallzar la Larea de lnsercln debemos apoyarnos en el cdlgo que hemos
consLruldo en la paglna MosLrarLlbros.xhLml. Ln esLa pglna dlsponemos de un boLn
de lnsercln del cul a conLlnuacln mosLramos su cdlgo.
Cdlgo 22.9: (MosLrarLlbros.xhLml)
<h:commandButton actionListener="#{formularioLibroManagedBean.formularioInsertar}"
action="FormularioInsertarLibro" value="insertar"/>

Como podemos ver, el funclonamlenLo del boLn es muy senclllo: slmplemenLe usa el
aLrlbuLo acLlon para redlrlglrnos a oLra pglna !Sl, en concreLo la pglna
lormularlolnserLarLlbro.xhLml, e[ecuLando prevlamenLe el evenLo formularlolnserLar.
LsLe senclllo evenLo unlcamenLe se encarga de vaclar las varlables lsbn y LlLulo como se
muesLra a conLlnuacln.
Cdlgo 22.10: (MosLrarLlbros.xhLml)
public void formularioInsertar(ActionEvent evento) {
isbn = "";titulo = "";
}

una vez reallzada esLa operacln al pulsar el boLn pasaremos a la pglna que muesLra
el formularlo para lnserLar un nuevo llbro. A conLlnuacln mosLramos LanLo la pglna
como su cdlgo fuenLe.
!!!"#$%&'()*(&$#+#,#"*-.
367
Cdlgo 22.11: (lormularlolnserLarLlbro.xhLml)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<htmlxmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:viewcontentType="text/html" />
<h:head>
<title>FormularioInsertarLibro</title>
</h:head>
<h:bodybgcolor="white">
<h:form>
<p>
<labelfor="isbn">ISBN:</label>
<h:inputText id="isbn" value="#{formularioLibroManagedBean.isbn}" />
</p>
<p>
<labelfor="titulo">Titulo:</label>
<h:inputText id="titulo" value="#{formularioLibroManagedBean.titulo}" />
</p>
<p><labelfor="categoria">Categoria :</label>
<h:selectOneMenu id="categoria"
value="#{formularioLibroManagedBean.categoria}">

<f:selectItemsvalue="#{formularioLibroManagedBean.listaDeCategorias}" />
</h:selectOneMenu>
</p>
<h:commandButton id="submit"
actionListener="#{formularioLibroManagedBean.insertar}" action="MostrarLibros"
value="Insertar" />
</h:form>
</h:body>
</html>

Como podemos ver, la pglna de lormularlolnserLarLlbro comparLe el mlsmo combo
con la pglna de MosLrarLlbros.xhLml y por lo LanLo lnvoca la mlsma funcln de nuesLro
managed8ean. una vez cargada esLa pglna, vamos comenLar cmo funclona la lglca
del boLn de lnserLar que se muesLra a conLlnuacln.




!"#$%&'(&$") +),)
368
Cdlgo 22.12: (lormularlolnserLarLlbro.xhLml)
<h:commandButton
id="submit"actionListener="#{formularioLibroManagedBean.insertar}"
action="MostrarLibros"value="Insertar" />

LsLe boLn lnvocar la funcln lnserLar de nuesLro managed8ean, lnserLando un nuevo
reglsLro en la Labla y volvlendo a selecclonar la llsLa de llbros. Pecho esLo, el acLlon
MosLrarLlbros" nos redlrlglr oLra vez a la llsLa. vamos a ver el cdlgo del meLodo
lnserLar
Cdlgo 22.13: (lormularlolnserLarLlbro.xhLml)
public void insertar(ActionEvent evento) {
getServicioLibros().insertarLibro(
new Libro(isbn, titulo, new Categoria(Integer
.parseInt(categoria))));
setListaDeLibros(getServicioLibros().buscarTodosLosLibros());
categoria="0";}

nuesLro meLodo se apoya en las capacldades que Llene !Sl de mapeo de eLlqueLas a
propledades de los Managed8eans y se encarga de lnserLar el reglsLro en la base daLos.
una vez hecho esLo, vuelve a selecclonar la nueva llsLa de llbros y nos redlrlge a la
paglna MosLrarLlbros.xhLml, mosLrndonos la llsLa con el nuevo llbro lnserLado.
6. Iunc|ona||dad de Ld|c|n
vamos a ver en la pglna MosLrarLlbros.xhLml cul es el cdlgo fuenLe que nos enlaza
con la funclonalldad de edlcln.
Cdlgo 22.14: (lormularlolnserLarLlbro.xhLml)
<h:column>
<h:commandLinkvalue="editar"
actionListener="#{formularioLibroManagedBean.editar}"
action="FormularioEditarLibro">
<f:attributename="isbn" value="#{libro.isbn}" />
</h:commandLink>
</h:column>


!!!"#$%&'()*(&$#+#,#"*-.
369
?a conocemos algunos aLrlbuLos a nlvel de commandLlnk, concreLamenLe el aLrlbuLo
acLlon que nos redlrlglr a la pglna lormularloLdlLarLlbro.xhLml .Ahora blen, anLes de
redlrlglrnos se e[ecuLa el evenLo acLlonLlsLener que lnvoca la funcln de edlLar. vamos a
ver el cdlgo fuenLe de esLe meLodo:
Cdlgo 22.13: (lormularloLlbroManaged8ean.[ava)
public void editar(ActionEvent evento) {
UIComponent componente = (UIComponent) evento.getComponent();
Libro libro = getServicioLibros().buscarLibroPorClave(
componente.getAttributes().get("isbn").toString());
isbn = libro.getIsbn();
titulo = libro.getTitulo();
}

Ls evldenLe que esLe meLodo carga en el managed8ean los daLos relaLlvos al Llbro que
vamos a edlLar, para ello busca por clave el llbro apoyndose en el aLrlbuLo lsbn del
commandLlnk. una vez reallzado esLo, se muesLra el formularlo de edlcln con los
daLos cargados (ver lmagen).








vamos a ver el cdlgo fuenLe de esLe flchero



!"#$%&'(&$") +),)
370
Cdlgo 22.16: (lormularloLdlLarLlbro.xhLml)
<!omitimos doctype!
<f:view contentType="text/html" />
<h:head>
<title>Hello World!</title>
</h:head>
<h:body bgcolor="white">
<h:form >
<p>
<label for="isbn">ISBN:</label>
<h:inputText id="isbn" value="#{formularioLibroManagedBean.isbn}" />
</p>
<p>
<label for="titulo">Titulo:</label>
<h:inputText id="titulo" value="#{formularioLibroManagedBean.titulo}" />
</p>
<p><label for="categoria">Categoria :</label>
<h:selectOneMenu id="categoria"
!!!!!!!!.value="#{formularioLibroManagedBean.categoria}">
<f:selectItems
!!!!!!!!value="#{formularioLibroManagedBean.listaDeCategorias}" />
</h:selectOneMenu>
</p>

<h:commandButton id="submit"
!!!!!..actionListener="#{formularioLibroManagedBean.salvar}"
!!!!!..action="MostrarLibros" value="Salvar" />
</h:form>
</h:body>
</html>

vlsLo esLo, unlcamenLe nos queda por clarlflcar cmo se encarga esLa pglna de guardar
la lnformacln .ara ello, el command8uLLon de la pglna se encarga de lnvocar al
meLodo salvar.
Cdlgo 22.17: (lormularlolnserLarLlbro.xhLml)
<h:commandButton id="submit" actionListener="#{formularioLibroManagedBean.salvar}"
action="MostrarLibros" value="Salvar" />




!!!"#$%&'()*(&$#+#,#"*-.
371
A conLlnuacln se muesLra el cdlgo fuenLe de esLe meLodo:
Cdlgo 22.18: (lormularloLlbroManaged8ean.[ava)
public void salvar(ActionEvent evento) {
getServicioLibros().salvarLibro(
new Libro(isbn, titulo, new Categoria(Integer
.parseInt(categoria))));
setListaDeLibros(getServicioLibros().buscarTodosLosLibros());
categoria="0";
}

LsLe meLodo locallza la caLegorla del Llbro y se la aslgna a un nuevo llbro que es el que
salvamos en la base de daLos. or ulLlmo nos queda lmplemenLar de forma correcLa la
funclonalldad de lllLrar.
7. I||trar por categor|as
vamos a modlflcar el combo que Lenemos consLruldo con !Sl para que permlLa reallzar
operaclones de fllLrado. vease el nuevo cdlgo fuenLe de esLe combo:
Cdlgo 22.19: (MosLrarLlbros.xhLml)
<h:selectOneMenu id="combo"
valueChangeListener="#{formularioLibroManagedBean.filtrar}"
value="#{formularioLibroManagedBean.categoria}" onchange="submit()">
<f:selectItem itemValue="0" itemLabel="seleccionar" />
<f:selectItems
value="#{formularioLibroManagedBean.listaDeCategorias}" />
</h:selectOneMenu>

Pemos vlsLo que se han apllcado varlos camblos .Ln prlmer lugar se ha anadldo un
nuevo lLem denomlnado 1odas (ver cdlgo)
Cdlgo 22.20: (MosLrarLlbros.xhLml)
<f:selectItemitemValue="0"itemLabel="Todas"/>

LsLe elemenLo permlLe que en el combo se puedan selecclonar Lodas" las caLegorlas .
8eallzada esLa operacln, se ha anadldo el aLrlbuLo valueChangeLlsLener que deflne
que funcln se e[ecuLar cuando el valor del combo camble. Ln esLe caso la funcln se
denomlna fllLrar y esL a nlvel de nuesLro Managed8ean.
!"#$%&'(&$") +),)
372
or ulLlmo, usaremos [avascrlpL para envlar los daLos del formularlo al servldor a Lraves
del meLodo onchange(). A conLlnuacln se muesLra una lmagen del fllLro en e[ecucln.


una vez hechos esLos camblos, Lenemos compleLamenLe lmplemenLada la
funclonalldad de !Sl en nuesLra apllcacln .Ls momenLo de afronLar algunas Lareas ms
orlenLadas al refacLorlng.
8. Me[oras Lxpress|on Language 2.0
Ll prlmer refacLorlng que vamos a apllcar es el hacer uso de expresln language en
nuesLra paglna !Sl 2.0 de MosLrarLlbros.xhLml. ara ello hay que reglsLrar un llsLener
especlal en el flchero faces-conflg.xml que hasLa esLe momenLo no hemos
uLlllzado.vamos a ver el codlgo de esLe:
Cdlgo 22.23: (MosLrarLlbros.xhLml)
<faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
<application>
<el-resolver>
org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver>
</application>
</faces-config>

Como hemos vlsLo en e[emplos anLerlores hay bloques de cdlgo que son dlflclles de
enLender, concreLamenLe los relaclonados con los llnks. vamos a verlo:

!!!"#$%&'()*(&$#+#,#"*-.
373
Cdlgo 22.24: (MosLrarLlbros.xhLml)
<h:column>
<h:commandLink value="borrar"
actionListener="#{formularioLibroManagedBean.borrar}" >
<f:attribute name="isbn" value="#{libro.isbn}" />
</h:commandLink>
</h:column>
<h:column>
<h:commandLink value="editar"
actionListener="#{formularioLibroManagedBean.editar}"
action="FormularioLibro">
<f:attribute name="isbn" value="#{libro.isbn}" />
</h:commandLink>
</h:column>

odemos slmpllflcar cada uno de esLos elemenLos apoyndonos en expresslonl
anguage de Lal forma que, a parLlr de ahora, esLos enlaces quedarlan deflnldos de una
forma ms sencllla ya que el expresln language permlLe a parLlr de la versln 2.0
lnvocar meLodos que reclban parmeLros. vease el nuevo bloque de cdlgo:
Cdlgo 22.23: (MosLrarLlbros.xhLml)
<h:column>
<h:commandLinkvalue="editar"
actionListener="#{formularioLibroManagedBean.editar(libro.isbn)}"
action="FormularioLibro">
</h:commandLink>
</h:column>
<h:column>
<h:commandLinkvalue="borrar"
actionListener="#{ formularioLibroManagedBean.borrar(libro.isbn)}"
action="MostrarLibro">
</h:commandLink>
</h:column>

una vez modlflcado el cdlgo, reallzamos una lnvocacln dlrecLa desde la pglna
MosLrarLlbros.xhLml a los meLodos del Managed8ean. veamos cmo quedan esLos:



!"#$%&'(&$") +),)
374
Cdlgo 22.26: (lormularloLlbrosManaged8ean.[ava)
public void borrar(String isbn) {

getServicioLibros().borrarLibro(new Libro(isbn));
setListaDeLibros(getServicioLibros().buscarTodosLosLibros());
}
public void editar(String isbn) {

Libro libro = getServicioLibros().buscarLibroPorISBN(isbn);
isbn = libro.getIsbn();
titulo = libro.getTitulo();
}

Ls evldenLe que es mucho ms senclllo Lraba[ar de esLa forma.
9. Integrac|n de Spr|ng
Culz el unlco elemenLo que no acaba de enca[ar en la lnLegracln con el framework
Sprlng y !Sl es el slgulenLe bloque de cdlgo que Lenemos a nlvel de nuesLro
managed8ean y que se encarga de enlazar !Sl y Sprlng.
Cdlgo 22.27: (lormularloLlbrosManaged8ean.[ava)
public ServicioLibros getServicioLibros() {
ApplicationContext contexto = FacesContextUtils
.getWebApplicationContext(FacesContext.getCurrentInstance());
return (ServicioLibros) contexto.getBean("servicioLibros");
}

ara slmpllflcar esLe bloque de cdlgo, es necesarlo usar la anoLaclon
[ManagedroperLy e lnyecLar el servlclo de forma dlrecLa como a conLlnuacln se
muesLra.
Cdlgo 22.28 (lormularloLlbrosManaged8ean.[ava)
@ManagedProperty("#{servicioLibros}")
private ServicioLibros servicioLibros;

LsLe es el ulLlmo paso en cuando a las modlflcaclones de !Sl se reflere y su lnLegracln
con Sprlng lramework.
!!!"#$%&'()*(&$#+#,#"*-.
375
10. ISI 2 y 8us|ness Cb[ects
una de las pocas cosas que no Lermlna de enca[ar en el e[emplo de !Sl es esLe bloque
de cdlgo.
Cdlgo 22.29 (lormularloLlbrosManaged8ean.[ava)
@PostConstruct
public void iniciar() {
listaDeLibros = getServicioLibros().buscarTodosLosLibros();
List<Categoria> categorias = getServicioLibros()
.buscarTodasLasCategorias();
listaDeCategorias = new ArrayList<SelectItem>();
for (Categoria categoria : categorias) {
listaDeCategorias.add(new SelectItem(categoria.getId(),
!!!!!!!categoria.getDescripcion()));
}
}

Ls evldenLe que serla mucho mas comodo cargar en las paglnas !Sl ob[eLos de negoclo
que una llsLa de SelecLlLems. LsLo es poslble a parLlr de la verslon de !Sl 2.0 que
permlLe deflnlr los elemenLos selecLCneMenu de la slgulenLe forma.

Cdlgo 22.30 (MosLrarLlbros.xhLml)
<h:selectOneMenu value="#{formularioLibroManagedBean.categoria}"">
<f:selectItem itemValue="0" itemLabel="seleccionar" />
<f:selectItems value="#{formularioLibroManagedBean.categorias}" var=categoria
itemLabel=#{categoria.descripcion} itemValue=#{categoria.id} />
</h:selectOneMenu>

!"#$%"&
Ln esLe caplLulo nos hemos cenLrado en lnLegrar !Sl como Lecnologla en nuesLra
apllcacln, ellmlnando la [erarqula de acclones prevla y creando un unlco
Managed8ean .LvldenLemenLe una apllcacln hablLual Lendr varlos Managed8ean
pero slempre sern muchos menos que el grupo de acclones anLes usado. or oLra
parLe, hemos abordado la lnLegracln con el framework Sprlng. Aun asl han quedado
muchas cosas fuera como el slsLema de navegacln o las anoLaclones Cul que debldo a
la exLensln del caplLulo no sern abordadas.

!"#$%&'(&$") +),)
376
!"#!"#$%&%'( *"+ ! #$%-!"






Ln el caplLulo anLerlor hemos hecho mlgrar nuesLra apllcacln a !Sl, en esLos
momenLos la apllcacln hace uso de !Sl, !A y Sprlng uLlllzando un ampllo con[unLo de
anoLaclones. Ls momenLo de cubrlr algunos Lemas complemenLarlos como es el uso de
servlclos web. Poy en dla la mayor parLe de las apllcaclones web que consLrulmos
neceslLan acceder a lnformacln remoLa de la que oLra apllcacln nos provee , o blen
neceslLa publlcar lnformacln para que oLras apllcaclones accedan a ella de forma
remoLa .una de las formas ms hablLuales de publlcar esLe Llpo de lnformacln es a
Lraves del uso de servlclos web. Ln esLe caplLulo nos cenLraremos en lnLegrar el uso de
esLa Lecnologla en nuesLra apllcaclon.
Cb[et|vos:
ubllcar a Lraves de un servlclo web lnformacln de nuesLros llbros para que
apllcaclones de Lerceros puedan acceder a ella.
Tareas:
1. lnLroduccln a la rogramacln ulsLrlbulda.
2. lnLroduccln al concepLo de Servlclo Web.
3. Creacln de un Servlclo Web 8slco usando anoLaclones.
4. ubllcacln de Servlclo Web
3. lnsLalacln de Apache Cxl.
6. Conflguracln de Apache Cxl.
7. Acceso al servlclo web.
1. Introducc|n a programac|n d|str|bu|da
!!!"#$%&'()*(&$#+#,#"*-.
377
La programacln dlsLrlbulda vlene a aporLar una solucln a un problema clslco de la
programacln orlenLada a ob[eLo: cmo comunlcar ob[eLos que se encuenLran en
ublcaclones flslcas dlsLlnLas . A conLlnuacln se muesLra un dlagrama del problema:
Como podemos ver, Lenemos dos ob[eLos A y 8 que neceslLan comunlcarse enLre ellos.
Sln embargo de enLrada esLo no es poslble ya que cada uno de ellos se encuenLra
ublcado en una mqulna dlsLlnLa y por lo LanLo unlcamenLe pueden acceder a ob[eLos
ublcados en su mlsma maqulna y proceso. ara consegulr que esLos dos ob[eLos puedan
lnLercamblar lnformacln neceslLamos un dlseno ms comple[o. LsLe dlseno se
consLruye a Lraves del uso de proxles, paLrn de dlseno que ya hemos vlsLo
anLerlormenLe .Ln esLe caso se neceslLan dos proxles : el proxy local y el proxy remoLo
que se encargan de faclllLar la comunlcacln. A conLlnuacln se expllcan
deLalladamenLe ambos concepLos.
roxy Loca|: Cb[eLo que da la sensacln de ser el ob[eLo real al que queremos acceder
de forma remoLa y que esL ublcado en la mqulna local .Se encarga de gesLlonar la
comunlcacln enLre el ob[eLo local y el servldor remoLo.
roxy kemoto: Cb[eLo que de la sensacln de ser ldenLlco al ob[eLo remoLo y se ublca
en la mqulna remoLa, gesLlonando la comunlcacln enLre el proxy local y el ob[eLo
remoLo.
!"#$%&'(&$") +),)
378
Como esLos concepLos pueden ser comple[os en un prlmer momenLo, vamos a mosLrar
un dlagrama que lncluye los ob[eLos reales y los proxles.
ue esLa forma la funclonalldad es lmplemenLada dando los slgulenLes pasos
1. un ob[eLo A lnvoca un meLodo del proxy local 8 que se encuenLra en su mlsma
mqulna.
2. una vez esLe ob[eLo reclbe la lnvocacln, lmplemenLa la funclonalldad
necesarla para converLlr esa lnvocacln en una llamada por red vla 1C/l hacla
el proxy remoLo.
3. una vez el proxy remoLo reclbe el mensa[e, lo convlerLe en una peLlcln normal
e lnvoca al ob[eLo remoLo que es el que Llene la lglca de negoclo a la cul
querlamos acceder.
4. LsLe ob[eLo remoLo nos devolver un resulLado que el proxy remoLo converLlr
en una peLlcln 1C y lo envlara al proxy local
3. Ll proxy local devolver esLa lnformacln al ob[eLo local
6. Ll ob[eLo local podr hacer uso de esLa lnformacln

A conLlnuacln se muesLra un dlagrama aclaraLorlo:



!!!"#$%&'()*(&$#+#,#"*-.
379

LsLa forma de comunlcacln esL soporLada por varlas plaLaformas a dla de hoy, enLre
las cuales desLacarlamos !AvA y .nL1 .LsLas son capaces de crear auLomLlcamenLe los
proxles necesarlos de una forma LransparenLe. Ln [ava la comunlcacln dlsLrlbulda se
reallza a Lraves de 8Ml y en .nL1 a Lraves de .nL1 8emoLlng. Ahora blen, esLe Llpo de
comunlcacln slo es vllda cuando ambas maqulnas albergan la mlsma Lecnologla
(!ava o nL1) .Ln el caso de que una maqulna use !ava y la oLra .nL1, la comunlcacln no
es poslble ya que los proLocolos son dlsLlnLos (ver lmagen).


LsLe Llpo de problema es el que los servlclos web nos ayudarn a solvenLar. A
conLlnuacln se lnLroducen sus concepLos.
!"#$%&'(&$") +),)
380
2. Introducc|n a Serv|c|os Web
Como acabamos de ver, la comunlcacln enLre .nL1 y !ava no puede ser dlrecLa . ara
consegulr que dos plaLaformas heLerogeneas se puedan comunlcar, neceslLamos usar
un esLndar que ambas enLlendan .LsLa esLndar es xML ya que LanLo .nL1 como !ava
son capaces de Lraba[ar con esLa Lecnologla (ver lmagen).


una vez que hemos decldldo usar xML como Lecnologla, Lendremos que deflnlr cul es
el proLocolo de comunlcacln enLre los dos ob[eLos .LsLe proLocolo ya exlsLe y se
denomlna SCA (Slmple Cb[ecL Access roLocol).SCA permlLlr comunlcar dos
Lecnologlas dlferenLes usando xML como sLandard a la hora de Lransferlr lnformacln
enLre los dos slsLemas. A conLlnuacln se muesLra una flgura aclaraLorla.


una vez que enLendemos que SCA es el proLocolo de comunlcacln basado en xML
que permlLe la Lransferencla de lnformacln enLre dos ob[eLos creados en Lecnologlas
dlsLlnLas, es momenLo de hablar un poco ms en profundldad de la esLrucLura de un
mensa[e SCA. un mensa[e SCA esL consLruldo con eLlqueLas xML y se compone de
dos esLrucLuras prlnclpales: cabecera y cuerpo (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
381


vamos a comenLar a grosso modo cul es la responsabllldad de cada una de esLas
parLes:
Cabecera: Se encarga de deflnlr concepLos Lransversales al mensa[e, como por
e[emplo Llpo de auLenLlcacln.
Cuerpo: Se encarga de deflnlr los meLodos que se van a lnvocar de forma
remoLa asl como los Llpos de daLos asoclados a esLos meLodos.
LvldenLemenLe a Lraves de SCA podemos reallzar clenLos de peLlclones hacla el mlsmo
ob[eLo y mlsmo meLodo. Lnvlaremos un mensa[e SCA y nos ser devuelLo oLro. Ahora
blen, a la hora de consLrulr el mensa[e, debemos usar oLra Lecnologla que se encarga de
deflnlr cul es la esLrucLura de esLos mensa[es. Ln programacln orlenLada a ob[eLo
cuando queremos consLrulr un ob[eLo, Lenemos que deflnlr prlmero una clase (ver
lmagen)

!"#$%&'(&$") +),)
382
lgualmenLe que una clase deflne cmo se consLruyen los dlsLlnLos ob[eLos de ella, los
servlclos web dlsponen de un sLandard que deflne cmo han de crearse los dlsLlnLos
mensa[es SCA para un servlclo web en concreLo. LsLe sLandard se denomlna
WSuL(Web ServlceuescrlpLlonLanguage). A conLlnuacln se muesLra una lmagen
aclaraLorla.
Asl pues a nlvel de servlclos web, el flchero WSuL hace las funclones de clase y los
mensa[es SCA hacen la funcln de ob[eLos que pasan enLre los dos slsLemas
dlsLrlbuldos deflnldos a nlvel de xML. una vez claros esLos concepLos, es momenLo de
comenzar a consLrulr un servlclo web.

3. Serv|c|o Web
una de las venLa[as de usar Lecnologla !ava a la hora de consLrulr Servlclos Web es que
permlLe consLrulr un servlclo web a parLlr de una sencllla clase !ava a Lraves del uso de
anoLaclones. LsLas anoLaclones esLn deflnldas en el esLndar !Ax-WS de !LL. una vez
anoLemos la clase ,!Ax-WS se encargar de consLrulr los proxles y el flchero WSuL de
forma auLomLlca. Ls momenLo de deflnlr que lnformacln queremos publlcar vla
servlclo web .Ln nuesLro caso el servlclo web a consLrulr nos devolver una llsLa con
Lodos los llbros lncluyendo la slgulenLe lnformacln:
lsbn
LlLulo
descrlpcln de la caLegorla
Sl nos fl[amos, nlnguna de nuesLras dos clases de negoclo que en esLe momenLo
Lenemos en nuesLra apllcacln Llbro y CaLegorla lncorpora la lnformacln necesarla. Asl
pues, vamos a consLrulr una nueva clase que reallce las funclones de conLenedor de
lnformacln y enca[e con los campos sollclLados. LsLas clases se denomlnan
hablLualmenLe u1C (uaLa 1ransfer Cb[ecLs) ya que son clases consLruldas
especlflcamenLe para la Lransmlsln de lnformacln enLre dos slsLemas.
!!!"#$%&'()*(&$#+#,#"*-.
383
Los u1C o uaLa 1ransfer Cb[ecLs son paLrones de dlseno orlenLados a programacln
dlsLrlbulda. A conLlnuacln se muesLra una lmagen aclaraLorla que hace uso de ellos.

una vez que Lenemos clara cul es la funclonalldad de esLa clase, vamos a ver su cdlgo
fuenLe.
Cdlgo 23.1: (Llbrou1C.[ava)
package com.arquitecturajava.aplicacion.serviciosexternos;

public class LibroDTO {
private String isbn;
private String titulo;
private String categoria;
public LibroDTO() {
}
public LibroDTO(String isbn, String titulo, String categoria) {
super();
this.isbn = isbn;
this.titulo = titulo;
this.categoria = categoria;
}

public String getCategoria() {
return categoria;
}
!"#$%&'(&$") +),)
384

public String getIsbn() {
return isbn;
}

public String getTitulo() {
return titulo;
}
public void setCategoria(String categoria) {
this.categoria = categoria;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}

public void setTitulo(String titulo) {
this.titulo = titulo;
}
}

ConsLrulda la clase que vamos a uLlllzar para Lransferlr la lnformacln enLre las dos
apllcaclones (Llbrou1C), es momenLo de consLrulr una clase de servlclo que Lenga un
meLodo que nos devuelva una llsLa de Llbrou1C con Loda la lnformacln referenLe a los
llbros. Al LraLarse de una clase de servlclo la denomlnaremos ServlclolnformaclonLlbros
y al meLodo que nos devuelve la llsLa de Llbrou1C le denomlnaremos
llsLalnformaclonLlbros. ara consLrulrla nos apoyaremos en el uso de lnLerfaces (ver
lmagen)
!!!"#$%&'()*(&$#+#,#"*-.
385

Como podemos ver, dlspondremos de un lnLerface ServlclolnformaclonLlbros y de una
clase que lo lmplemenLa. A conLlnuacln se muesLra una lmagen con los paqueLes y
clases que debemos anadlr al proyecLo


una vez Lenemos claro que lnLerfaces y clases vamos a consLrulr, es momenLo de
lnLroduclr un par de anoLaclones adlclonales que perLenecen al esLndar !Ax-WS y son
las encargadas de slmpllflcar la publlcacln de servlclos web en esLe Llpo de enLorno.
QWebServ|ce : AnoLacln que marca una clase como servlclo web
Q WebMethod : AnoLacln que marca un meLodo como meLodo publlco a
nlvel del servlclo web.
vamos a usar a conLlnuacln esLas anoLaclones para crear un Servlclo Web que cumpla
con los requlslLos que nosoLros neceslLamos. A conLlnuacln se muesLra el cdlgo
fuenLe de esLe.






!"#$%&'(&$") +),)
386
Cdlgo 23.2: (ServlclolnformaclonLlbrosCxl.[ava)
//omitimos imports
@Service
@WebService(endpointInterface="com.arquitecturajava.aplicacion.serviciosextern
os.ServicioInformacionLibros")
public class ServicioInformacionLibrosCXF implements ServicioInformacionLibros{
@Autowired
private ServicioLibros servicioLibros;
@WebMethod
public List<LibroDTO> listaInformacionLibros() {
List<Libro> listaLibros=servicioLibros.buscarTodosLosLibros();
List<LibroDTO> listaDestino= new ArrayList<LibroDTO>();
for(Libro libro: listaLibros) {
LibroDTO libroExterno= new LibroDTO(libro.getIsbn(),libro.getTitulo(),
!! libro.getCategoria().getDescripcion());
listaDestino.add(libroExterno);
}
return listaDestino;
}
}

Ls evldenLe que nos hemos apoyado en las anoLaclnes [AuLowlred y [Servlce para
acceder a la lnformacln de ServlcloLlbros. una vez dlsponemos de esLa lnformacln
usaremos la anoLacln [WebServlce para publlcar esLa lnformacln hacla el exLerlor
de la apllcacln (ver lmagen).

Al haber anoLado la clase con [WebServlce !Ax-WS se encargar de generar los
proxles y el flchero WSuL necesarlo para acceder al servlclo. A conLlnuacln se muesLra
una lmagen aclaraLorla.
!!!"#$%&'()*(&$#+#,#"*-.
387


Pemos Lermlnado de consLrulr nuesLro servlclo web .Sln embargo para que se generen
los proxles y el flchero wsdl deberemos dar una serle de pasos en cuanLo a 1omcaL y
Sprlng se reflere.
4. ub||cac|n de| serv|c|o web.
1omcaL 7 de por sl no lmplemenLa soporLe para el uso de servlclos web con !Ax-WS, ya
que no cumple con Lodos los esLndares de !LL : neceslLaremos uLlllzar algun
framework o llbrerla adlclonal para poder usarlo.ara ello vamos uLlllzar Apache Cxl
como framework de servlclos web, ya que se lnLegra de una forma muy naLural con
Sprlng. La slgulenLe url nos permlLe obLener esLe framework.
http://cxf.apache.org
una vez obLenldo el framework pasamos a lnsLalar sus llbrerlas denLro de nuesLra
apllcacln.

S. Insta|ac|n de Apache CkI
Apache Cxl lncorpora un grupo ampllo de llbrerlas, sln embargo las que neceslLamos
uLlllzar para nuesLro e[emplo son basLanLes menos ya que parLe nos las proporclona el
proplo framework Sprlng. Ln concreLo Lendremos que anadlr las slgulenLes a nuesLro
proyecLo:
!"#$%&'(&$") +),)
388
Cxf-2.4.0
neeLhl-3.0.0
Wsdl4[-1.6.2
xmlschema-core-2.0
6. Conf|gurac|n de| framework
Ln esLe aparLado nos vamos a encargar de conflgurar Apache Cxl sobre Sprlng. ara
ello es necesarlo reallzar el slgulenLe con[unLo de modlflcaclones:
Modlflcar el flchero web.xml y anadlr el servleL de apache Cxl que faclllLa la
lnLegraclon con nuesLra apllcaclon
Modlflcar el flchero conLexLoApllcaclon.xml y anadlr las eLlqueLas necesarlas de
apache Cxl
vamos a modlflcar el flchero web.xml y conflgurar el servleL de Apache Cxl que se
encargara de gesLlonar los dlsLlnLos servlclos web. A conLlnuaclon se muesLra el bloque
de cdlgo que debemos anadlr al web.xml.
Cdlgo 23.3: (web.xml)
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/servicios/*</url-pattern>
</servlet-mapping>

una vez hecho esLo esLamos en dlsposlcln de conflgurar la parLe relaclonada con
Sprlng lramework y dar de alLa nuesLro servlclo.Asl pues vamos a ver que elemenLos
del flchero de conflguracln de Sprlng debemos modlflcar. Ln prlmer lugar es necesarlo
anadlr un nuevo namespace a los que ya Lenemos para poder hacer uso de las
eLlqueLas [axws (ver cdlgo).
Cdlgo 23.4: (conLexLoApllcaclon.xml)
xmlns:jaxws="http://cxf.apache.org/jaxws"
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd

!!!"#$%&'()*(&$#+#,#"*-.
389
Pecho esLo, anadlremos varlos flcheros xml de Apache Cxl al flchero de Sprlng
Cdlgo 23.3: (conLexLoApllcaclon.xml)
<import resource="classpath:META-INF/cxf/cxf.xml" />
<importresource="classpath:META-INF/cxf/cxf-extensionsoap.xml" />
<importresource="classpath:META-INF/cxf/cxf-servlet.xml" />

1enemos ya lmporLados los flcheros que Apache Cxl neceslLa para Lraba[ar.
nlcamenLe neceslLamos conflgurar el servlclo web a nlvel de Sprlng, lo cul no
presenLar problemas (ver cdlgo).
Cdlgo 23.6: (conLexLoApllcaclon.xml)
<jaxws:endpoint
id="servicioInformacionLibros"
implementor="com.arquitecturajava.aplicacion.serviciosexternos.
impl.ServicioInformacionLibrosCXF"
address="servicioInformacionLibros" />
</beans>

Como podemos ver la conflguracln es sencllla: en prlmer lugar aslgnamos un ld al
servlclo que vamos a dar de alLa
Cdlgo 23.7: (conLexLoApllcaclon.xml)
id="servicioInformacionLibros"

una vez que Lenemos deflnldo el ldenLlflcador del servlclo, deflnlmos quel clase se
encarga de lmplemenLar esLe servlclo.
Cdlgo 23.8: (conLexLoApllcaclon.xml)
implementor="com.arquitecturajava.aplicacion.serviciosexternos.
impl.ServicioInformacionLibrosCXF"

or ulLlmo, aslgnamos la dlreccln (url) desde la cul accederemos al servlclo web de
nuesLra apllcacln.

!"#$%&'(&$") +),)
390
Cdlgo 23.9: (conLexLoApllcaclon.xml)
address="servicioInformacionLibros"

Con esLa conflguracln hemos Lermlnado de modlflcar el flchero de conflguracln de
Sprlng.odremos acceder al servlclo a Lraves de la slgulenLe u8L:
Cdlgo 23.10: (conLexLoApllcaclon.xml)
http://localhost:8080/Aplicacion18_1_Servicio_Web/servicios/servicioInformacionLibros?
wsdl

LsLa u8L nos devuelve el flchero WSuL que neceslLamos para consLrulr un cllenLe y
acceder al servlclo (ver lmagen).



!!!"#$%&'()*(&$#+#,#"*-.
391
!"#$%"&
Ln esLe caplLulo hemos lnLroducldo brevemenLe el framework Apache Cxl y como esLe
framework se lnLegra con Sprlng y permlLe la consLruccln de Servlclos Web de una
forma relaLlvamenLe sencllla .Adems hemos vlsLo cmo deflnlr un u1C que slrva para
Lransferlr lnformacln enLre dos slsLemas.Los u1C no son slempre necesarlos a la hora
de Lransferlr la lnformacln, depender de nuesLra slLuacln. Ln oLros momenLos
puede ser ms prcLlco slmplemenLe usar ob[eLos de negoclo.
















!"#$%&'(&$") +),)
392
!"#!"#$%$&'()*$+% - .//0&






Ln el caplLulo anLerlor hemos dlsenado un servlclo web usando Apache Cxl como
framework .no vamos a anadlr ms funclonalldad a la apllcacln : podemos
conslderarla Lermlnada.
LsLe caplLulo lnLenLa anadlr algo ms basado en mls experlenclas Lraba[ando con la
plaLaforma !LL.Muchos desarrolladores consLruyen apllcaclones en enLornos !LL sln
pensar realmenLe en los enLornos de produccln donde esLas van a ser e[ecuLadas. or
asl declrlo, Lraba[an de una forma LoLalmenLe lndependlenLe y flnalmenLe enLregan un
war ,ear eLc olvldndose del resLo. Sln embargo muchas veces los admlnlsLradores de
slsLemas Llenen algo que declr y es lmporLanLe dlsponer en nuesLra organlzacln de
experLos en !LL a nlvel de desarrollo, pero Lamblen es lgual de lmporLanLe Lener
experLos en !LL a nlvel de slsLemas ya que esLos Llenen un peso clave en los enLornos
de produccln .Ll ob[eLlvo de esLe caplLulo no es nl ms nl menos que revlsar nuesLra
apllcacln y ver como la podrlamos conflgurar de me[or forma para un admlnlsLrador
de slsLemas. ara ello nos cenLraremos en cmo gesLlonar los pools de conexlones y las
dlferenclas de vlsln enLre el equlpo de desarrollo y el de slsLemas.

Cb[et|vos
Conflguracln de la apllcacln para admlnlsLradores.



!!!"#$%&'()*(&$#+#,#"*-.
393
1areas
1. Ll framework Sprlng y pools.
2. ool de conexlones y 1omcaL.
3. Conflguracln de Sprlng vla !nul.

1. L| framework Spr|ng y oo|s
Pemos gesLlonado los pools de conexlones o uaLasource a Lraves de las capacldades de
lnyeccln de dependencla que Llene Sprlng. ConcreLamenLe sl recordamos hemos
deflnldo a nlvel de Sprlng un pool de conexlones de la slgulenLe forma:
Cdlgo 24.1: (conLexLoApllcaclon.xml)
<bean id="fuentedatos"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<propertyname="driverClassName" value="com.mysql.jdbc.Driver" />
<propertyname="url"
value="jdbc:mysql://localhost/arquitecturaJavaORM" />
<propertyname="username" value="root" />
<propertyname="password" value="java" />
</bean>

nos puede parecer en un prlmer momenLo correcLo como desarrolladores .Sln
embargo esLa conflguracln se sale de la conflguracln de nuesLro servldor de
apllcaclones : es algo compleLamenLe lndependlenLe y gesLlonado por un lramework
concreLo. or lo LanLo puede darse el caso de que el admlnlsLrador de slsLemas no esLe
al LanLo nl sepa locallzar esLos recursos (ver lmagen).







!"#$%&'(&$") +),)
394











Como la lmagen muesLra unlcamenLe el desarrollador Llene claro cmo se ha
conflgurado el pool de conexlones usando el framework Sprlng. Ln camblo el
admlnlsLrador desconoce compleLamenLe que esLe pool de conexlones exlsLa. una vez
hemos ldenLlflcado el problema , debemos reconflgurar nuesLra apllcacln para que
enca[e de forma ms naLural con el servldor de apllcaclones que esLemos usando y con
las Lareas de admlnlsLracln. Ln esLe caso nuesLro servldor es fcll de conflgurar ya que
se LraLa de 1omcaL. 1omcaL como servleL conLalner soporLa la conflguracln de
uaLasources o pools de conexlones a nlvel de admlnlsLracln. vamos a verlo en la
slgulenLe Larea.

2. oo| de conex|ones y 1omcat
ara conflgurar un pool de conexlones sobre 1omcaL debemos crear un nuevo flchero
de conflguracln que se denomlna conLexL.xml y que se enconLrar ublcado en la
carpeLa ML1A-lnl de nuesLra apllcacln web (ver lmagen).
!!!"#$%&'()*(&$#+#,#"*-.
395

Ll flchero en cuesLln almacena la conflguracln necesarla para crear un pool de
conexlones para nuesLra apllcacln a nlvel de servldor. veamos el conLenldo del
flchero:
Cdlgo 24.2: (conLexL.xml)
<Contextpath="/AplicacionFinal" docBase="AplicacionFinal"
reloadable="true" crossContext="true">
<Resourcename="jdbc/MiDataSource" auth="Container"
type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="root" password="java" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/arquitecturaJavaORM"/>
</Context>

Ll flchero deflne una eLlqueLa ConLexL en la cul se declara en nombre de la apllcacln
que va a dlsponer del pool de conexlones. una vez Lenemos deflnlda esLa parLe, la
eLlqueLa 8esource se encarga de conflgurar el pool de conexlones en cuesLln. A
conLlnuacln se expllcan las dlsLlnLas propledades aslgnadas.
name : Ruta de acceso al pool de conexiones
maxActive: Numero de conexiones activas en el pool
maxWait : Tiempo mximo de espera por una conexin definido en
milisegundos
user: Usuario de acceso para la conexin
password : Password de acceso para la conexin
driverClassName: Clase a instanciar a nivel de driver JDBC
url : Base de Datos a la que conectarnos


!"#$%&'(&$") +),)
396
una vez reallzadas esLas operaclones nuesLro servldor ya dlspone de forma publlca de
un pool de conexlones para nuesLra apllcacln (ver lmagen).

3. Conf|gurac|n de Spr|ng v|a INDI.
8eallzada esLa operacln, 1omcaL ha dado de alLa un nuevo recurso !nul a nlvel del
servldor de apllcaclones , Lendremos que modlflcar la esLrucLura de nuesLro flchero de
conflguracln de sprlng (conLexLoApllcaclon.xml) para que, en vez de crear un pool de
conexlones proplo, delegue en el pool de conexlones definido a nivel de servidor en
el rbol [ndl (ver lmagen).

!!!"#$%&'()*(&$#+#,#"*-.
397

ara conflgurar el framework Sprlng para que haga uso de !nul, debemos ellmlnar la
eLlqueLa que hace referencla a un daLasource que hemos creado con Sprlng y camblarla
por un daLasource que delega en !nul (ver lmagen).
Cdlgo 24.4: (conLexLoApllcaclon.xml)
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/MiDataSource"/>

ue esLa manera el framework sprlng delegar en los recursos !nul del servldor de
apllcaclones (ver lmagen).
!"#$%&'(&$") +),)
398

Asl pues habremos conflgurado la gesLln de pools de conexlones de una forma ms
amlgable de cara a los admlnlsLradores de slsLemas y habremos aslgnado las
responsabllldades de una manera ms correcLa (ver lmagen).









!!!"#$%&'()*(&$#+#,#"*-.
399
ara que la eLlqueLa anLerlor nos funclone correcLamenLe deberemos dar de alLa un
nuevo namespace a nlvel del flchero de conflguracln de sprlng. A conLlnuacln se
muesLra el cdlgo:
Cdlgo 24.23: (conLexLo.xml)
xmlns:jee="http://www.springframework.org/schema/jee"
http://www.springframework.org/schema/jee/spring-jee-2.0.xsd"

una vez reallzadas esLas operaclones la apllcacln funclonar correcLamenLe uLlllzando
el pool de conexlones de LomcaL.
!"#$%"&
Ln esLe caso el unlco camblo producldo en la apllcacln es la creacln de un pool de
conexlones a Lraves de los flcheros de conflguracln del servldor ,de Lal forma que la
apllcacln sea ms fcll de gesLlonar por parLe de los admlnlsLradores y las
responsabllldades esLen me[or reparLldas, algo que en los enLornos reales es
fundamenLal.


















!"#$%&'(&$") +),)
400
!"#$%&'()*+%&,*






Ln los caplLulos de esLe llbro hemos ldo paso a paso desarrollando una pequena
apllcacln !LL .ara ello hemos hecho uso de prlnclplos de lngenlerla, de frameworks y
de paLrones de dlseno dlversos .1odos ellos [unLos nos han permlLldo desarrollar una
apllcacln flexlble. Ahora qulzas una pregunLa dlflcll de responder es la slgulenLe.

jue es |o mas |mportante?
1. aLrones de ulseno
2. lrameworks
3. rlnclplos de lngenlerla

ara la mayor parLe de los desarrolladores lo ms lmporLanLe es sln nlnguna duda el
con[unLo de frameworks que ha de uLlllzar .Ml experlencla me lndlca que, aunque
evldenLemenLe esLo es clave a la hora de desarrollar una arqulLecLura, es Lodavla ms
lmporLanLe conocer y comprender los dlsLlnLos paLrones de dlseno .1odos los
frameworks esLn consLruldos apoyndose en los dlsLlnLos paLrones de dlseno y un
conoclmlenLo slldo de esLos nos permlLlr enLender de una forma ms naLural el
funclonamlenLo de los frameworks . SlmplemenLe por recordar algunos de los e[emplos
que hemos proporclonado en los dlsLlnLos caplLulos:

!!!"#$%&'()*(&$#+#,#"*-.
401
!Sl como framework se basa en un paLron MvC2
Sprlng y su lnLegracln con PlbernaLe se apoya en un paLrn 1emplaLe
y en el paLrn uAC

Sl segulmos profundlzando en esLe anllsls, pronLo nos daremos cuenLa de que Lodos
los paLrones de dlseno uLlllzados en los dlsLlnLos caplLulos aparecen a parLlr del uso de
uno de los prlnclplos de lngenlerla de sofLware. or e[emplo, el paLron MvC aparece
una vez que hemos dlvldldo las responsabllldades usando el prlnclplo S8 .or oLro lado
el paLron 1emplaLe aparece al hacer uso del prlnclplo u8? en una [erarqula de clases
concreLa. or lo LanLo lo ms lmporLanLe para los arqulLecLos es conocer esLos
prlnclplos de lngenlerla de sofLware ya que nos faclllLar sobremanera el enLender por
que un codlgo se ha de consLrulr de una manera u oLra .Pe aqul un dlagrama de la
relacln enLre los Lres concepLos:



Pemos vlsLo muchos prlnclplos duranLe los dlsLlnLos caplLulos del llbro, a conLlnuacln
los enumeramos:
u8? (uonL 8epeaL ?ourSelf)
S8 (Slmple responslblllLy rlnclple)
!"#$%&'(&$") +),)
402
lCC (lnverslon of ConLrol)
ul (uependency lnverslon rlnclple)
CCC (ConvenLlon over ConflguraLlon)
CC (Cpen Closed rlnclple)
LS (Llskov SubsLlLuLlon rlnclple)
lS (lnLerface SegregaLlon rlnclple)
un subcon[unLo de esLe grupo de prlnclplos se encuenLra unlflcado en un acrnlmo al
cul cada dla se hace ms referencla : "SCLID" o dlseno SCLlu" , que hace referencla
a un desarrollo que cumple con los slgulenLes prlnclplos.
S8
CC
LS
IS
Dl
Apoyarnos en esLos prlnclplos nos manLendr en la senda correcLa a la hora de abordar
los dlsLlnLos desarrollos : de ahl el derlva el LlLulo de esLe llbro.
1. ILL un ecos|stema
Pemos desarrollado duranLe los dlsLlnLos caplLulos una apllcacln !LL .Ls probable que
mucha genLe pueda pensar que son Sprlng, !A y !Sl los frameworks o esLndares a
uLlllzar a la hora de abordar una solucln !LL. Sln embargo hay que recordar que !LL no
es a dla de hoy LanLo una plaLaforma como un ecoslsLema donde convergen soluclones
muy dlsLlnLas , las usadas en el presenLe llbro no Llenen por que ser las ldneas para
Lodo el mundo o en Lodas las slLuaclones. SeguldamenLe vamos a comenLar algunas
que pueden subsLlLulr o ser complemenLarlas a las que hemos vlsLo:
Lnterpr|se Iava 8eans (3.0, 3.1): Ln el llbro hemos usado Sprlng como framework
prlnclpal, sln embargo los esLndares se orlenLan hacla una solucln basada en L!8 ya
que esLos han madurado mucho y son una opcln Lan vllda como Sprlng a la hora de
abordar muchos proyecLos.
Spr|ng MVC: Pemos usado !Sl en nuesLra apllcacln pero a veces los esLndares se
pueden quedar corLos o no ser lo suflclenLemenLe flexlbles para lo que neceslLamos .
Sprlng MvC puede ser a dla de hoy una alLernaLlva muy adecuada a la capa de
presenLacln y sobre Lodo muy dlsLlnLa a lo que !Sl represenLa.
!!!"#$%&'()*(&$#+#,#"*-.
403
I8oss Seam: Seams es un framework ublcado a nlvel de absLraccln por enclma de los
L!8s y complemenLa de forma sllda la deflnlcln de capa de presenLacln deflnlda por
!Sl.
Groovy y Gra||s:Croovy es un lengua[e dlnmlco basado en las ldeas de 8uby y Cralls es
la versln de 8alls para esLe lengua[e. Sl esLamos lnLeresados en desarrollos aglles y
lengua[es compacLos que aceleren el desarrollo, esLa puede ser Lamblen una buena
alLernaLlva a oLras soluclones.
Andro|d: no hemos cublerLo la parLe de movllldad en esLe llbro pero a dla de hoy es
obllgaLorlo hacer una referencla a Androld a la hora de desarrollar verslones mvlles de
nuesLras apllcaclones.
n1ML S Irameworks de mov|||dad: or ulLlmo sern cada dla ms lmporLanLes los
frameworks orlenLados a movllldad de P1ML 3 que permlLen el desarrollo de una unlca
apllcacln que funclone en varlas plaLaformas, ya que recordemos Androld solo
represenLa una parLe de esLe pasLel. L[emplos de esLos nuevos frameworks son
honeCap y !Cuery Moblle.
!"#$%"&
Pemos uLlllzado frameworks ,paLrones y prlnclplos en esLe Llbro. Los frameworks,
aunque nos parezcan lmporLanLes, Llenen un clclo de vlda unos vlenen y oLros se van .
Ln camblo los prlnclplos y paLrones nos acompanarn y nos sern uLlles duranLe la
carrera profeslonal que Lengamos. AposLemos de una forma mas sllda por conocerlos.
ara Lermlnar, sl algo he aprendldo esLos anos de las plaLaformas !2LL y !LL, es a no
ser dogmLlco y a esLar ablerLo a ldeas y soluclones nuevas que van llegando. uede
ser que el prxlmo Sprlng lramework o el prxlmo Androld esLen a la vuelLa de la
esqulna : es necesarlo Lener la menLe ablerLa para acepLar esLas evoluclones.





!"#$%&'(&$") +),)
404
!"#$"%&'()*(
DCM Scr|pt|ng: Web Des|gnw|th IavaScr|pt and the Document Cb[ect Mode| by
!eremy kelLh and !effrey Sambells (aperback - uec 27, 2010)
nead I|rst Serv|ets and IS: ass|ng the Sun Cert|f|ed Web Component Deve|oper
Lxam by 8ryan 8asham, kaLhy Slerra and 8erL 8aLes(aperback - Apr 1, 2008)
Iava ers|stence w|th n|bernate by Chr|st|an 8auer and Gav|n k|ng (aperback - nov
24, 2006)
Spr|ng |n Act|on by Cralg Walls(aperback - !un 29, 2011)
Core I2LL atterns: 8est ract|ces and Des|gn Strateg|es (2nd LdlLlon) by ueepak Alur,
uan Malks and !ohn Crupl(Pardcover - May 10, 2003)
Apache CkI Web Serv|ceDeve|opment
Murach's Iava Serv|ets and IS, 2nd Ld|t|on by Andrea SLeelman and !oel
Murach(aperback - !an 21, 2008)
Dependency In[ect|on by uhan[l 8. rasanna(aperback - Sep 4, 2009)
Des|gnatterns: L|ements of keusab|e Cb[ect-Cr|ented Software by Lrlch Camma,
8lchard Pelm, 8alph !ohnson and !ohn vllssldes(Pardcover - nov 10, 1994)
Core Iava Server Iaces (3rd LdlLlon)by uavld Ceary and Cay S. PorsLmann(aperback -
!un 6, 2010)
Aspect[ |n Act|on: LnLerprlse AC wlLh Sprlng AppllcaLlons by 8amnlvasLaddad and 8od
!ohnson(aperback - CcL 3, 2009)
1he ragmat|c rogrammer: Irom Iourney to MasterbyAndrew PunL and uavld
1homas(aperback - CcL 30, 1999)
atterns of Lnterpr|se App||cat|onArch|tecture by MarLln lowler(Pardcover - nov 13,
2002)


!!!"#$%&'()*(&$#+#,#"*-.
405

Vous aimerez peut-être aussi