Você está na página 1de 44

c c


 
    
 




 

 
 

  

!!

!
" 
 #$%
 


& 
 #


' 





 


HTTP es el protocolo usado por la WWW para transimir información (generalmente mediante TCP). Mas
formalmente, HTTP es un protocolo de red cliente-servidor. El cliente (generalmente un browser) abre
una conexión y genera un requerimiento al servidor HTTP. El servidor procesa el requerimiento, envia el
resultado al cliente y cierra la conexión (es por eso que HTTP es un protocolo stateless).

()
#

Un requerimiento consta de 3 partes: una linea de requerimiento, un conjunto de headers y un cuerpo de


mensaje opcional. La linea de requerimiento a su vez consta de 3 partes: El método HTTP, un puntero al
recurso seleccionado y el protocolo empleado.

*)


El requerimiento GET es el más común de los requerimientos y sirve para pedirle un recurso al servidor
HTTP. El formato de GET es el siguiente:

 GET <URL> <PROTOCOL> (ejemplo: GET /path/to/file/index.html HTTP/1.0)


 <HEADERS>*
 Una linea en blanco
 El mensaje

* Una manera de ver (Existe gente que necesita ver para creer!!) el requerimiento que estamos enviando
desde el browser al servidor web es instalando un Personal Proxy. Yo instalé uno llamado WebScarab. La
instalación es sumamente sencilla: basicamente, tenemos que apuntar nuestro browser al listener del
personal proxy (que por default es 127.0.0.1:8008). Interceptando el requerimiento a
http://www.google.com puedo ver lo siguiente:

O 

    
  
 

  

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

  
 23-  ! 4   !5 
- 6! . 78'9800,/:;*:8/<<(0",8/<<(0",&8;)=

Aqui, excepto la primera linea, todos las demás son headers.

El formato de la respuesta solo varía en la primera.

<HTTP version> <status code> <comentarios>

Esta es la respuesta que se recibe del primer requerimiento (después recibi otras, que no voy a pegarlas
aquí):

HTTP/1.0 200 OK
Cache-Control: private
Content-Type: text/html; charset=UTF-8
Server: GWS/2.1
Date: Fri, 25 Aug 2006 21:00:00 GMT
Connection: Close

<html><head>...etc!!!
**Nota: Otra forma de ver los resultados del servidor web es abrir una sesión de telnet contra el servidor
web.

Cuales son los triggers en el web browser para un requerimiento de este tipo?

1. El navegante tipea una dirección en la barra de direcciones del explorador + Enter.

2. El navegante hace click en un link

3. El navegante hace el submit de un form, cuyo método es GET.



Un requerimiento POST sirve para enviar información al servidor, para que éste la procese de alguna
manera y retorne un resultado (es decir que el requerimiento POST busca modificar - Insert/Delete/update
- algo en el servidor). La gran diferencia con el requerimiento GET es que en el cuerpo del mensaje se
envia información. El uso mas común de POST es para enviar un formulario, y es por eso que elegimos
esto para el ejemplo. La URL de este sencillo ejemplo es:

http://www.w3schools.com/html/tryit.asp?filename=tryhtml_input

Y esto es lo que intercepto webscarab:

POST http://www.w3schools.com:80/html/tryit_view.asp HTTP/1.0


Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash,
application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: http://www.w3schools.com/html/tryit.asp?filename=tryhtml_input
Accept-Language: en-us
Content-Type: application/x-www-form-urlencoded
Proxy-Connection: Keep-Alive
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Host: www.w3schools.com
Content-length: 330
Pragma: no-cache
Cookie: ASPSESSIONIDCSQRBTRS=GKJELMNDNILBEKEIOKGCPMCO

submit=Edit+the+text+and+click+me&code=%3Chtml%3E%0D%0A%3Cbody%3E%0D%0A%0D%0A
%3Cform%3E%0D%0AFirst+name%3A+%0D%0A%3Cinput+type%3D%22text%22+name%3D%22fir
stname%22%3E%0D%0A%3Cbr%3E%0D%0ALast+name%3A+%0D%0A%3Cinput+type%3D%22text
%22+name%3D%22lastname%22%3E%0D%0A%3C%2Fform%3E%0D%0A%0D%0A%3C%2Fbody
%3E%0D%0A%3C%2Fhtml%3E%0D%0A%0D%0A

** Cual es la diferencia más importante entre GET y PUT? El requerimiento GET envia los parametros
apendeados en la URL. Este tiene 2 consecuencias: la primera es que la cantidad de caracteres que se
envian es limitada y la segunda es que los parametros son más visibles.



El requerimiento HEAD es igual al GET, pero solo devuelve los headers. Esto sirve para chequear la
información del URI sin tener que traer todo el contenido. Un uso de esto puede ser en un browser o en
una aplicación que manejan un cache. El header retorna la fecha en la que el recurso fue modificado y de
acuerdo a eso trae o no el recurso.

 +,

El requerimiento OPTIONS sirve para identificar cuales son los requerimientos que la URL acepta.
(

El requerimiento PUT sirve para subir un archivo a la URL indicada. Es exactamente lo mismo que hacer
un FTP. Si el recurso en el servidor fue reemplazado, el servidor retorna un código de estado 200
mientras que si el recurso fue creado, el servidor retorna 201.

- 

El requerimiento DELETE hace exactamente lo contrario a PUT, osea borra el recurso indicado en la
URL.

*"

Este requerimiento sirve para ver como se modificaron los headers desde el momento que partió el
requerimiento hasta que llego a la máquina final.

. )'
 %/

El web browser envia estos requerimientos al clikear un link, enviar un formulario, enviar un archivo, etc.
En síntesis, cualquier cosa que haga en el browser provocará que el web server invoque a uno de estos
métodos en el servlet (si es que el URI apunta a un servlet obviamente).

"
 %'
)
'/

Para cada uno de estos métodos, existe un método en javax.servlet.http.HttpServlet.

GET - doGet()

POST - doPost()

HEAD - doHead()

OPTIONS - doOptions()

PUT - doPut()

DELETE - doDelete()

Nosotros, como programadores de servlets vamos a extender javax.servlet.http.HttpServlet,


sobreescribiendo los métodos en los que estamos interesados.

c 0(!


' 
*)

 %


' - 
 

)

' )
 

'1 
)

Cuando llega un requerimiento del cliente, el web server invoca al método service() de HttpServlet con 2
objetos: un HttpServletRequest y un HttpServletResponse. El objeto HttpServletRequest sirve para
obtener toda la información concerniente con el requerimiento, es decir los parámetros enviados, los
headers, los cookies, etc. Como toda la especificación esta pensada para que no solo sirva para el
protocolo HTTP, HttpServletRequest y HttpServletResponse son derivadas de ServletRequest y
ServletResponse. Esto hace que el estudio para el SCWCD se complique un poquito, porque tenemos que
aprender que métodos pertenecen a ServletRequest y que métodos pertenecen a HttpServletRequest - es
decir que métodos son especificos para el protocolo HTTP - .Pensandolo un poquito, nos podremos dar
cuenta que los headers y las cookies son objetos que pertenecen especificamente al mundo de HTTP, por
lo que pertenecen a HttpServletRequest. Los parámetros, aunque yo personalmente no conozca otros
protocolos, pertenecen a la clase general, es decir a ServletRequest.

Los siguientes métodos son usados para obtener la información de los parámetros (Los métodos para
obtener parametros se encuentran en ServletRequest, no en HttpServletRequest!!). Una de las cosas que
es importante recordar con los parámetros es que un parámetro puede contener más de un valor. Es decir
que para el parámetro nombre, puede tener valores Jose, Carlos, etc. Esto determina un poco la semántica
de los diferentes métodos. El segundo a punto a recordar es que los parámetros pueden venir en la URL
(cuando se utilizó el método GET) o en el body (cuando se utilizó el método POST):

 El primer método es getParameter que retornará el primer parámetro. La síntaxis es la siguiente:

>5 
&!
getParameter#>5 
&!
 1
Returns the value of a request parameter as a &!
, or  if the parameter
does not exist.

 Puede haber más de un valor para un parámetro. El método anterior retornará solamente el
'primer' parámetro. Para obtener todos los valores, se utiliza la función getParameterValues que
retorna un array de String con todos los parámetros. La síntaxis es la siguiente:

>5 
&!
?@ getParameterValues#>5 
&!
 1
Returns an array of &!
objects containing all of the values the given
request parameter has, or  if the parameter does not exist.

 Podemos obtener todos los parámetros recibidos, juntamente con todos sus valores en un Map
(donde cada MapEntry es [parámetro --> Array of String]) a través de la función
getParameterMap. La síntaxis es la siguiente:

>5 !  getParameterMap#1


Returns a java.util.Map of the parameters of this request.

 Finalmente, si queremos obtener todos los nombres de los parámetros recibidos, utilizamos el
método getParameterNames. La síntaxis es la siguiente:

>5 !  !  getParameterNames#1


Returns an  !  of &!
objects containing the names of the
parameters contained in this request.

Si el contenido del parámetro es binario, por ejemplo cuando se manda un archivo de esta manera:

A; ! 8B3!& 5 B  *8BC&BD 


A!3 8B;! B 8B $ BD 
A!3 8B$!B5  8BC&BD 
A; D

Tenemos 2 métodos para recuperar el parámetro:

& 5 '&  getInputStream#1


Retrieves the body of the request as binary data using a
& 5 '& .
>5 ! E;;  *. *  getReader#1
Retrieves the body of the request as character data using a
E;;  *. * .

Los siguientes métodos son usados para obtener los headers(** Los headers son un mecanismo de HTTP,
por lo que están definidos en HttpServletRequest). Para los headers, como para los parámetros la cantidad
de valores puede ser más de una.

 Para obtener el primer header, usamos un método que sigue el pattern de getParameter llamado
getHeader. La síntaxis es la siguiente:

>5 
&!
getHeader#>5 
&!
 1
Returns the value of the specified request header as a &!
.

 Para obtener todos los valores, utilizamos el método getHeaders. Notar que el pattern es
completamente diferente al caso de los parámetros, tanto en el nombre del método como en el
tipo retornado que en este caso es una Enumeration. La síntaxis es la siguiente:

>5 !  !  getHeaders#>5 


&!
 1
Returns all the values of the specified request header as an  ! 
of &!
objects.

 Si queremos obtener los nombres de todos los headers recibidos, utilizamos la función
getHeaderNames. Es importante notar que si no existe ningún header (cosa muy poco probable),
retorna una Enumeration vacia (no null). La síntaxis es la siguiente:

>5 !  !  getHeaderNames#1


Returns an enumeration of all the header names this request contains.

Este método retorna los nombres de todos los headers recibidos.

 Finalmente, tenemos a nuestra disposición 2 helpers methods que podemos usar cuando sabemos
que el resultado es un entero o una fecha.

 
getDateHeader#>5 
&!
 1
Returns the value of the specified request header as a 
value that represents a 9
object.
! getIntHeader#>5 
&!
 1
Returns the value of the specified request header as an !.

Obtención de los cookies

 Para obtener las cookies, utilizamos el método getCookies(** este método tambien se encuentra
en HttpServletRequest)

- 6! ?@ getCookies#1
Returns an array containing all of the - 6! objects the client sent with this request.
c 2(!


' 
*
 %


 





# 
)
3

 
)#
 


 )


(*-1



A través de HttpServletResponse podemos setear los diferentes headers que serán enviados en la
respuesta. Como ejemplos de lo que se puede configurar a través de los headers, esta el 'Age' si fue
retornado del cache, la ubicación si se quiere hacer un redirect, información del web server, el método de
autenticación, etc.

Para agregar headers, tenemos 4 métodos. Los primeros 2 son generales:

 El primero de los métodos agrega un valor al header

5 !* addHeader#>5 
&!
 F>5 
&!
5  1
Adds a response header with the given name and value.

 Este método reemplaza el valor del header por otro (si existiera más de un valor para el header,
la API no especifica nada por lo que supongo que no debería ser usado)

5 !* setHeader#>5 
&!
 F>5 
&!
5  1
Sets a response header with the given name and value.

 Los otros 2 métodos se correponden directamente con los del request y son usados cuando los
valores son un entero o una fecha:

5 !* addIntHeader#>5 
&!
 F!5  1
Adds a response header with the given name and integer value.
5 !* addDateHeader#>5 
&!
 F 
* 1
Adds a response header with the given name and date-value.


 


#
04

1. Seteando el header que corresponde:

HttpServletResponse.setHeader("Content-Type","text/html");

2. Utilizando el método setContentType de ServletResponse:

5 !* setContentType#>5 
&!
3 1
Sets the content type of the response being sent to the client, if the response has not been
committed yet.

El parámetro type debe contener alguno de los tipos MIME reconocidos por el browser.


3
  

 5 !
6
!
$

' 
*4

>5 ! !)!  getWriter#1


Returns a !)!  object that can send character text to the client.
El texto debe ser HTML bien formado (si, es medio incomodo producirlo desde aquí, y esta es una de las
razones del nacimiento de los JSPs). Todo el texto que vayamos enviando se va a almacenar en un buffer,
hasta que este se llene y el web server haga el commit hacia el cli ente.


  

 5 6
!




' 
*4

& 5 C&  getOutputStream#1


Returns a & 5 C&  suitable for writing binary data in the
response.

** No se pueden obtener writers de los 2 tipos para enviar una respuesta mezclada al cliente (como hacer
esto es descripto en la API de ServletResponse).

  

 5 6
*


' 
*4

Recuerde que la redirección actúa de esta manera: el servidor le envia al cliente un status code (que indica
al cliente que se debe hacer una redirección) y una nueva URL. El cliente, al recibir estas instrucciones
realiza un nuevo request a la nueva dirección. Esta es la sintaxis del método:

5 !* sendRedirect#>5 
&!
 ! 1
Sends a temporary redirect response to the client using the specified redirect location URL.

 
!!1 

 5 6
"1

' 
*4

5 !* addCookie#- 6!  6! 1
Adds the specified cookie to the response.

** Cookie tiene un solo constructor de la forma:

"

#
Cookie#>5 
&!
 F>5 
&!
5  1
Constructs a cookie with a specified name and value.

c 7
'
) 
' 
  # 4c' 
  !0
' 



2 


7 
'
8 
#



Básicamente, el ciclo de vida de un servlet esta dado en la numeración de este objetivo:

(1) y (2) Obviamente el/los classloades deben encontrar la clase que define el servlet, cargarla e
instanciarla antes que el servlet pueda servir algun requerimiento.

(3) Todo el código de inicialización debería ser escrito en este método, ya que se asegura que será
invocado una sola vez antes que el servlet comienze a servir requerimientos. Además, este método debe
concluir exitosamente para que el servlet comienze a servir requerimientos.

** En realidad el webserver no invoca el método init() sino que invoca a init(ServletConfig) que se
encuentra definido en GenericServlet. Este método invoca a init() - el método de su servlet será invocado
polimorficamente -.
(4) El método service() es invocado por cada uno de los requerimientos que el cliente realiza. Si existiera
más d eun requerimiento, el web server crea un thread diferente para cada uno de estos.

(5) El método destroy() es llamado cuando el servlet va a ser sacado de circulación. Para que este método
sea llamado se deben cumplir 2 condiciones:

1. El método init() debe haber concluido exitosamente.

2. Todos los threads sirviendo requerimientos deben haber concluido.

0 c"


  
#

 $ 


#





9 !' 
 
 #


! 9*
 9'   &%


    

Los web servers tienen una ubicación por default, donde se van a instalar las aplicaciones. En TOMCAT,
este directorio es <TOMCAT INSTALLATION DIRECTORY>/webapps, pero puede ser modificado a
donde se necesite. Dentro de este directorio, cada aplicación tendrá un directorio. A este directorio se lo
llama 'Context Root' e identifica el home directory de la aplicación.

Inmediatamente debajo del Context Root, se pueden ubicar un conjunto de recurso, tales como páginas
web (html, htm), JSPs, imagenes(gif, jpg), hojas de estilo(css), etc. Estos recursos pueden es tar tambien
en directorios. Todo lo que esta aquí es accesible para cualquier usuario de la aplicación.

Debajo del 'Context Root' además se encuentra un directorio sumamente importante, llamado :$;<
+,:. Este directorio no es accesible directamente por el usuario (es decir que si el usuario intenta acceder
directamente, recibe un error 404). En este directorio encontramos un archivo, llamado 'Deployment
Descriptor' (web.xml) que 'define' muchisimos aspectos de la aplicación.

** Si este directorio no existe, los archivos estaticos que se deployeen en el context root pueden ser
accedidos. Sin embargo, si solo ponemos el contexto root en la URL no se buscará automaticamente el
index.html. Con solo poner el archivito web.xml con lo mínimo (<web -app></web-app>) ya se buscará el
archivo index.html como default.

Además, en este directorio encontramos los siguientes directorios:

- =$;<+,= : servlets o POJOs se encuentran en este directorio, gralmente. siguiendo la


estructura de paquetes estandar de Java (aunque pueden estar directamente abajo, si pertencen al paquete
estandar).

- =$;<+,= : Archivos JAR que soportan la aplicación (por ejemplo, el driver de la BD).

* El classloader carga primero las clases del directorio 'classes' y despues las del director io 'lib'.

0 0

 
 #



El deployment descriptor es un archivito xml que define la estructura de la aplicación web. Entre los
puntos que se definen estan: los archivos de bienvenida, los servlets, la página de error, etc.
0 2"





 
 #



Todo archivo xml necesita un root. Para el caso del deployment descriptor, el root es <web-app></web-
app>. Este es el único elemento mandatorio en el deployment descriptor. Debajo de este elemento,
pueden haber 27 tags, todos ellos opcionales. Ahora vamos a estudiar los elemenos más importantes del
primer nivel.

 
>' 
?

Todos los servlets que construyamos, necesitan una entrada en el deployment descriptor. Esta entrada
define el nombre, como se mapea en el context root, cual es la clase que lo implementa, etc...

Estos son los subelementos más importantes de <servlet>

>' 
<? - El nombre del servlet es usado por el mecanismo de accesso a controlado a WEB-INF
(a través del tag servlet-mapping). Ademas, puede ser accedido desde la clase que lo implementa (2
servlets - osea 2 nombres diferentes - pueden ser implementados por la misma clase. A través de este
método se puede averiguar de cual de las instancias estamos hablando)

>' 
< ? - El nombre completo de la clase que implementa el servlet. Esta clase obviamente tiene
que ser descendiente de GenericServlet o HttpServlet.

>@<  ? - Este tag sirve para acceder jsp's que estan bajo el directorio WEB-INF.

>
<? - Este tag sirve para incluir parametros que serán enviados al servlet. El formato es el
siguiente:

<init-param>
<description>blah blah blah</description>
<param-name>Nombre</param-name>
<param-value>Jose</param-value>
</init-param>

** Dentro del servlet, podremos recuperar estos valores utilizando estos 2 métodos:

>5 
&!
getInitParameter#>5 
&!
 1

. &!
 !!
 5   ;  *!!! ! ! 
  F  !;   *   2!

>5 !  !  getInitParameterNames#1


Returns the names of the servlet's initialization parameters as an  ! 
of &!
objects, or an empty  !  if the servlet has no initialization
parameters.

> <<

? - Este tag sirve para especificar un order de carga para el servlet. Un servlet con un
número positivo mayor que otro se carga primero (si es negativo o no existe, no podemos asegurar un
order de carga - generalmente se carga cuando es accedido - )

 
>' 
<!?

Este tag nos permite mapear un servlet lógico con una URL. El formato es el siguiente:

A 5 !
D
A 5  D!& 5 A 5   D
A  D! 5 A  D
A 5  !
D
En general, el url-pattern se pone como el ejemplo, es decir identificando una URL única. Sin embargo,
podemos ponerlo tbn. de otras formas:

Poniendo el camino: /path/morepath/* - path/morepath/yetanothepath/index.html

Poniendo todos los archivos que tengan la extension: *.jsp - index.jsp

** Primero busca los que coinciden perferctamente, despues por el path, después por la extensión y
finalmente el default (/).


 


>% <  < 


? - sirve para especificar una lista de URLs, que serán apendeados a la URL recibida
en el request y en caso de hacer matching, retornadas al solicitante.

El formato es el siguiente:

A   ;!  !D
A   ;! D!* 2  A   ;! D
A   ;! D!* 2 >A   ;! D
A   ;!  !D

><!? - es posible especificar páginas de error por default, que serán devueltas y mostradas al
usuario(el browser no mostrará la clásica página de error 404 por ejemplo) cuando el recurso solicitado
no existe o cuando el servlet arroja una excepción.

A  
D
A   * D""A    * D
A ! D!
!*    A ! D 
A  
D

or

A  
D
A 2 !  3 D>52  5  & 5  2 ! A 2 !  3 D
A ! D   
 A ! D 
A  
D

><!? - este tag sirve para asociar en el descriptor una extension con un mime type (para que
el requester sepa que hacer con el archivo)

A! !
D
A 2 ! D2A 2 ! D
A! 3 D 2 !A! 3 D
A! !
D

Î  
      


     
 
 

ã   


            
        
               
      ã          
                !"#$%
&'(      !$'&("#!(" )       
   *    )   
2 c
' 
"
3

 5

4%
' 


 5

&


 #

 
  !
 5



ServletContext es una interfase que el web container se encargará de inicializar con información
relacionada con la aplicación web. Este objeto será usado por los servlets para obtener información de la
aplicación, de otros servlets o para transferir información a otros servlets.

El tag <context-param> que puede encontrarse 0,1 o mas veces debajo de <web-app> sirve para
especificar un parametro de aplicación. El formato es el siguiente (igual al de los parametros de servlet):

A  2D
A D+ $ A  D
A5  DG  A 5  D
A  2 D

Desde cualquier servlet, se puede obtener una referencia al ServletContext mediante el método:
getServletContext(). Este método esta implementado en la clase GenericServlet (ya que GenericServlet
implementa la interfase ServletConfig), de la cual se deriva nuestro servlet. Los métodos para obtener los
parametros son exactamente iguales a los métodos para obtener los parametros de inicialización de un
servlet.

- getInitParameter()

- getInitParameters()

2 0
 
 ' 



) 

3
4%
' 


'
'


&!'!
 #
 


&
 #
 <
!

%


Los atributos representan información que se puede agregar o sacar de cualquiera de los 3 scopes. Un
atributo siempre esta representado por un map:

String --> Objeto

Los métodos son los siguientes, cualquiera sea el scope:

 '




!@
'  - para setear un atributo.

 @
!




! - para obtener el atributo.

** Es importante recordar que cuando obtenemos un atributo de esta manera, es necesario castearlo. Por
ejemplo, si quisieramos obtener un String, esta sería la sintaxis:

(String)req.getSession.getAttribute("atributoEnCuestion")

 
!



, - para obtener una Enumeration de todos los atributos.

 ''



! - para remover un atributo.



)
: Este scope empieza cuando se hace un request y termina cuando es enviada la respuesta. En el
medio pueden haber llamadas a POJOs o forwardear el requerimiento a otro servlet. Muchas veces,
cuando se forwardea el requerimiento se agregan atributos al objeto HttpServletRequest, que serán usados
por el servlet receptor.
: El web container crea una sesión (un objeto de tipo HttpSession) cuando un browser manda el
primer requerimiento y lo conserva hasta que esa ventana del browser es cerrada (En realidad una sesión
pasa por 2 estados: el primer requerimiento crea una sesión y la pone en estado 'nueva'. Cuando el cliente
demuestra que es capaz de unirse a la sesión, esta queda 'establecida'. Es común agregar atributos a la
sesión para poder establecer comunicaciones más largas entre el usuario y la aplicación (el carrito de
compras es el ejemplo más común).


3
: Este scope dura lo que dura la aplicación.



!

- Los atributos del RequestServlet son thread-safe

- Los atributos de un HttpSession no son thread-safe

- Los atributos del ServletContext no son thread-safe

- Las variables locales son thread-safe

- Las variables de instancia no son thread-safe

- Las variables estaticas no son thread-safe

2 2
$
)
!  &%
 ! 
&
)

%&!'! %
 # 
%

Los filtros se pueden ejecutar antes y/o después de los servlets para agregar procesamiento que
seguramente no tiene que ver con el proposito principal del servlet (osea, no agrega a la lógica de
negocios del servlet, por ejemplo autorización, logging, etc.).

Para crear un filtro, creamos una clase que implementa la interfase 


, que tiene 3 métodos:



" ! !: Este método se ejecuta cuando se instancia el filtro. El FilterConfig puede ser
guardado como una variable de instancia del filtro, para poder acceder al nombre del filtro -
getFilterName() -, a los paramétros de inicialización - getInitParameter(String nombre) - o al
ServletContext - getServletContext() -.


' 
*)
)
' 
*
": Aca se realiza todo
el procesamiento necesario y se invoca (o no) al método doFilter() del objeto chain para seguir con el
procesamiento en el recurso requerido.


#: Este método se invoca cuando el filtro va a ser dealocado y sirve para liberar recursos.

!  #





A;!  D
A;!   DA;!    D
A;!   DA;!   D
A;!  D

A;!  !
D
A;!   DA;!    D
A  DA  D A 5   DA 5   D
A;!  !
D
La idea es exactamente la misma que para los servlets. También se puede especificar directamente el
nombre del servlet. un 3er tag que se puede agregar en el mapping es <dispatcher>, con valores
REQUEST, FORWARD, INCLUDE, ERROR. A través de este tag, se puede especificar si queremos
ejecutar el filtro cuando se hace un request de un servlet (valor por default), cuando se hace un forward o
include interno o cuando el servlet va a ser ejecutado por una condición de error.

** Se puede agregar más de un filtro para un servlet. En ese caso, el orden en que se agregan en el
deployment descriptor define que filtro se ejecutará primero.

$

Este mecanismo emula el design patter 'decorator', que envuelve a un objeto con nueva funcionalidad (o
modifica la existenete sobreescribiendo algun método). El objeto wrapper se instancia en el filtro y se
pasa al servlet. Para implementar estas clases wrappers, 4 clases son provistas

 javax.servlet.ServletRequestWrapper

 javax.servlet.ServletResponseWrapper

 javax.servlet.http.HttpServletRequestWrapper

 javax.servlet.http.HttpServletResponseWrapper

Nosotros debemos extender alguna de estas clases para crear nuestros filtros.

2 7
$
  # '
  )
% 
&
 !

    # &
 ! 


 
 &!'
 #




 



 Los listeners son objetos que son llamados por el web container cuando ciertos eventos suceden. Para
crear un listener, básicamente hay que:

1. Programar una clase que implement el listener

2. Poner una entrada con este listener en el deployment descriptor.

A nivel de request, tenemos 2 listeners

' 
*)
-
 - Esta interface posee 2 métodos.

- requestInitialized(ServletRequestEvent) es llamado cuando se recibe el requerimiento. Recibe un


parametro de tipo ServletRequestEvent. Este evento nos sirve para obtener el request -getServletRequest()
- o el contexto - getServletContext().

- requestDestroyed(ServletRequestEvent) es llamado cuando termina el método service().

' 
*)



-
 - Esta interface posee 3 métodos

- attributeAdded(ServletRequestAttributeEvent) - es llamado cuando se agrega un atributo al


requerimiento. A través de los métodos getName() y getValue() se pueden obtener los valores del
atributo.

- attributeReplaced(ServletRequestAttributeEvent) - es llamado cuando se reemplaza un atributo.


getValue() retorna el nuevo objeto!
- attributeRemoved(ServletRequestAttributeEvent) - es llamado cuando se borra un atributo. getValue()
retorna el objeto removido.

** ServletRequestAttributeEvent extiende a ServletRequestEvent, por lo que estos eventos se pueden


utilizar para obtener el request y el context.

A nivel de context, los patterns son los mismos:

' 
"
3
-


ContextInitialized(ServletContextEvent)

ContextDestroyed(ServletContextEvent)

** Cuando la aplicación es distribuida (osea que existe más de una JVM) se crea un listener para cada una
de las JVMs. En consecuencia, los 2 eventos son llamados en los 2 listeners.

 ' 
"
3



-
- Los métodos son los mismos, pero son llamados cuando atributos
son insertados, reemplazados o borrados del contexto.

Dentro del deployment descriptor, todos los listeners se definen de esta manera:

A !  D

A !   DA !    D

A !  D

** Que pasa si existe más de un listener (para el mismo environment) ? Los listeners son registrados en el
web container en el orden que se encuentran en el deployment descriptor (osea, sus métodos de
inicialización serán llamados en ese orden). Para el caso de la destrucción, los llamados van a ser inversos
(osea se va a empezar por el último hasta terminar por el primero).

** Ahora que ya se han repasado Servlets, Filters y listeners sería bueno definir cual es el orden de
instanciación de estos elementos:

1. Los listeners son instanciados.

2. Si alguno de los listeners implementa ContextListener, el método contextInitialized() es llamado.

3. Los filtros son instanciados.

4. Los servlets que en el deployment descriptor tengan <load-on-startup> son instanciados.

2 8
*)

&%
' 


)

&%
' 


% 

!
&
 # 

 )
<


'#





!


El mecánismo de RequestDispatcher nos permite forwardear un request a otro servlet/JSP o incluso


HTML (Este mecanismo es el usado en los frameworks MVC para reenviar el requerimiento a un servlet
y luego para reenviarlo a la capa de presentación). El mecanismo consiste en obtener un objeto
RequestDispatcher que apunte a la nueva URI. Tenemos 3 formas de obtener este objeto:
1. A través del ' 
*)
con el método !
*)


!
: el path puede ser
absoluto, desde el context root o relativo, desde la URL original (el 2do se verá afectado si se afectan los
mappings).

2. A través del ' 


"
3
con el método !
*)


!
: La diferencia con el
anterior es que solamente pueden incluirse paths absolutos.

3. A través del ' 


"
3
con el método !
,

!: El nombre se
refiere al nombre de un servlet o de un JSP (Este método puede ser usado cuando no existe una entrada en
<servlet-mapping> para el servlet en cuestión.

** los 3 métodos retornan NULL en caso de no matchear ninguna URL en la app.

Una vez que obtuvimos el RequestDispatcher, podemos utilizar 2 métodos, forward() e include().

% - La sintaxis es la siguiente:

5 !* morward#& 5 . H  H F& 5 .      1


Forwards a request from a servlet to another resource (servlet, JSP file, or HTML file) on the
server.

La especificación dice que este método puede llamarse solamente si no se ha enviado nada a la salida. Sin
embargo, si se ha enviado pero todavía esta en el response buffer, esta es deshechada y la invocación se
puede realizar. Si ya se hizo un commit, una IllegalStateException es arrojada.  

' '' 
Cuando usamos cualquiera de los 2 métodos (forward o include),
podemos obtener toda la información del servlet original a través de los siguientes atributos del
ServletRequest.

v  
   
 %     +  +&
     

v  
 


%       *,     

v  
  

%       ,     

v  
 
 %     ,&      

v  
  
 %     -      

+  - La sintaxis es la siguiente:

5 !* include#& 5 . H  H F& 5 .      1


Includes the content of a resource (servlet, JSP page, HTML file) in the response.

Este método incluye toda la salida del servlet incluida en la respuesta. Este método también tiene los 5
métodos anteriores, pero esta vez es el significado es completamente inverso. Los atributos, cuando son
obtenidos desde el servlet incluido devuelven los valores correspondientes a ese servlet. Por el contrario,
las funciones devuelven los valores correspondientes al servlet desde el cual se incluyo este servlet.

7 c$
' 


@

@

' @
 @


** Quizás este objetivo debería ser estudiado cronologicamente después del objetivo 4.2, es decir después
de saber como obtener una sesión desde un servlet.
Una vez obtenida la sesión, podemos asociar objetos a ella de la misma manera que asociabamos objetos
a los otros scopes, es decir utilizando el método setAttribute().

5 !* setAttribute#>5 
&!
 F>5 
C$> 5  1
Binds an object to this session, using the name specified.

Para obtener los atributos, utilizamos las funciones getAttribute(String) y getAttributeNames() que
retorna una enumeration.

>5 
C$>  getAttribute#>5 
&!
 1
Returns the object bound with the specified name in this session, or  if no
object is bound under the name.

** Recordá que este método retorn un object, por lo que debes castearlo al objeto que necesitas!

>5 !  !  getAttributeNames#1


Returns an  !  of &!
objects containing the names of all
the objects bound to this session.

Para borrar un atributo de la sesión utilizamos el método removeAttribute().

7 0'
 +

@
3 %
@
 %




#
@
%
%
#

HTTP es un protocolo stateless, es decir que no mantiene ningun estado de los diferentes requerimientos
que hace un cliente. Muchas veces sin embargo, surge el requerimiento de guardar cierta información a
través de un un conjunto de requerimientos. Para lidiar con esto, la especificación de servlets provee las
sesiones, a través del objeto HttpSession (Notar que las sesiones tienen que ver con HTTP, por lo que no
existe un objeto Session).
Para mantener una sesión, debemos hacer 2 llamadas a getHttpSession. La primera será hecha en el
servlet desde donde se desea mantener la sesión (osea en el punto que se desea 'crear' la sesión). Para ello,
se hace la siguiente llamada:

HttpSession session = request.getSession();

Este método creará una sesion en estado 'new'. En el próximo requerimiento desde el mismo browser o
desde un browser abierto desde el browser original (y que probablemente sea a otro servlet), la llamada a
este método retornará el mismo objeto sesión.

El método getSession esta sobrecargado

getSession()
getSession(boolean session)

En la segunda versión, el parámetro identifica si se quiere crear o no una nueva sesión (osea que si el
parametro es false, la sesión no se creará).




Cual es el efecto de una aplicación distribuida sobre las sesiones? Las sesiones deberían estar replicadas
en las 2 instancias. Osea que si una de las aplicaciones falla, el failover server debería tene r toda la
información de las sesiones replicadas. Esto agrega la necesidad que los atributos de las sesiones sean
serializables.

"A
Podes matarla utilizando el método invalidate() exprofeso o se puede acabar el tiempo disponible para la
sesión. El tiempo que se le da a la sesión puede venir de 3 lugares:
1. Los web containers asignan un valor por default.
2. Se asigna un valor de el deployment descriptor (en minutos):
<web-app>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
3. Utilizando el método setMaxInterval(int segundos) de HttpSession. En este caso, el parametro va en
segundos (para confundir un poco más)

** Un valor negativo en 2) o 3) determina que la sesión no vence nunca.


** Un valor de 0 en 2) determina que la sesión no vence nunca, pero en el método directamente la mata.

7 2(! 
%


'
%@

%

 

'
 %@
!
 B



Las sesiones tienen 2 listeners que siguen el mismo pattern que para los scopes de request y context:

-
 - sin embargo, el primero de los métodos no sigue el pattern para el nombre

- sessionCreated(HttpSessionEvent) - Este método se llama justo después de crear una sesión.

- sessionDestroyed(HttpSessionEvent) - Este método es llamado cuando se llama a


HttpSession.invalidate(), pero antes que la sesión sea invalidada.

** Si el web container decide dealocar la aplicación, entonces estos listeners serán invocados antes que
los listeners de aplicación.




-


- Esta interface tiene los 3 métodos de los otros scopes, pero el evento que recibe es

;!'
, que es un evento que sigue el patrón de

;!-
, que
es otro listener que existe solamente en este scope.

Además de estos 2 listeners, el scope de sesión tiene 2 listeners más, que se diferencian de los anteriores
porque no tienen que ser declarados en el deployment descriptor.

;!-
 - Los objetos que implementan esta interface serán llamados por el web
container cuando sean ligados o desligados de una sesión. Los métodos que tiene son los siguientes:

- valueBound(HttpSessionBindingEvent) - es llamado ANTES de asociar este valor a un atributo en una


sesión.

- valueUnbound(HttpSessionBindingEvent) - es llamado DESPUES de remover el atributo de la sesion.

** Si también tengo asociado un HttpSessionAttributeListener, se llama primero a valueBound()


'
-
- Esta interface sirve para objetos que serán asociados a sesiones
distribuidas. Los métodos que tiene serán llamados antes de migrar a otra JVM y cuando son recuperados.

- sessionWillPassivate(HttpSessionEvent) - Este método es llamado justo antes de serializarse, para ser


transportado a otra JVM
- sessionDidActivate(HttpSessionEvent) - Este método es llamado en la otra JVM justo después de la
deserialización.

7 7' %!

$
  #%1!


!%(*-%
!!

!%
' 

 (*-
%
!

ã ./  )        

0$/  1 

.$/ +ã 

 1   /  )       "    


 1     2"&3'&4     " 
             1  )       
          

$/ +ã  )         1
 )5  5 +ã    6

677    7 7 *8   90.:;

$    * /     6

 
    !"#$6" /    +ã  +ã      
   " /             1     <  
)     1   

 
      
!"#$%" /      +  


† &'  
 
 
   


   
   %#$



 #$
(
  #$


 #$ 






: El proceso de autenticación es el encargado de determinar que el interesado en acceder
los recursos es realmente quien dice que es. Lo más comun es hacer que el usuario/aplicación envie un
password que lo identifica.


5
: Es el proceso por el cual se restringe el acceso a ciertos recursos a un conjunto de clientes.
En realidad, lo que se define es un conjunto de roles que pueden acceder a ciertos recursos y se asocia
cada usuario a uno o mas roles.



!
#: Es el proceso que 'asegura' que los datos que se reciben (tanto el cliente como el servidor)
no han sido corrompidos. Generalmente se usan algoritmos de encriptación para lograr esto.

 
 
#: Es el proceso que intenta asegurar que solamente los clientes autorizados reciban la
información. La manera de lograr esto puede ser a través del uso de claves públicas/privadas.

† Î) 
 
 
    
 

    

 
 


   
    


Este punto describe los mecanismos de seguridad que se pueden establecer 'declarativamente', es decir
desde el deployment descriptor.
 
>
#<

? - Este elemento sirve para limitar el acceso a un conjunto de recursos.
Se limitan los métodos que lo pueden acceder, los roles y como se enviarán los datos al cliente. El
formato es el siguiente:

A !3  !D

A $    ! DAI  * ;!  $  
 !F   3 J *  D

A* !! D

A $    DAI  * $   ! D

A  D

A  *DAI  J *  !


!#O FF  1 D

A $    ! D

A !D

 A  DAI 


5! !*!H   !

 H!  !  F  !    *  *   * ;!!*  
*  3 * !  &! F    KA  DFH * $ 
* ;!!* $>  A !3 DD

A * !D

A  
3DAI '+ O.*  H  * $ 

 !
!***  *  -C+7'9 +'H  * $ 

 ;!* ! !***  *  D

A !3  !D

 
> !< !? - cuando ponemos este tag, el servidor envia al browser un código de retorno
que indica que tenemos que loguearnos para acceder a la aplicación. El browser entiende este código y
muestra una ventanita para que introduzcamos el usuario y password.

A
! ;!
D

A  *DE&'-A   *D

A
! ;!
D

A
! ;!
D

A  *D7C.A   *D

A   D *  !!LA    D

A; 
! ;!
D

 A; 


!
D !!  !!  >A ; 

!
D
 A; 
!  D !!  !!  >A;  

!  D

A
! ;!
D

** Aunque parezca raro, ninguno de los 3 elementos es mandatorio.

 
>
#< ? - podemos poner estos elementos por cada uno de los usuarios habilitados
para entrar en la aplicación. El formato es el siguiente (pueden existir todas las entradas que sean
necesarias):

A !3  D

A  DA  D

A !3  D

 
>
#< < ?- Este elemento permite relacionar un role-name definido
programaticamente (en el servlet) con uno que existe en el deployment descriptor. El formato es el
siguiente:

A !3   ;D

A  DA  D

A  !6DA  !6D

A !3   ;D

** Este elemento se encuentra dentro del elemento <servlet> del deployment descriptor.

8 2"






#;+"+ *"-+, <"* &%

#
%1&!' 


#

;+"*B c0 8 c: Este es el método mas simple, pero el más inseguro. Cuando usamos este tipo de
autenticación, se abre una ventana en el browser del cliente para que este ingrese el usuario y el password.
El password se envia al servidor codificado a través de un proceso llamando Base64.

+ *B c0 8 0: La autenticación también es hecha utilizando usuario y password, pero el
password es enviado encriptado de una forma mucho más segura (por ejemplo, utilizando HTTPS client
authentication)

**B c0 8 2: Este método es similar a BASIC, pero utiliza un form provisto por el programador.
Este form tiene que cumplir los siguiente requisitos:

1. El action debe ser j_security_check

2. El campo de usuario debe llamarse j_username

3. el nombre del password debe llamarse j_password

** El método Base64 es como si fuera plain text. No es considerado un método de encriptación (porque
existen programitas en la web que podemos bajar para decodificar el contenido).
"-+, <"* *B c0 8 7: en este método se usan certificados digitales. El browser debe tener
instalado el certificado para que la comunicación se pueda establecer.

C c+
 #%

9  
  %! 
4
 

3

! 

 

' 


3


3 !! 


C c  

3
: Es todo el HTML o XML que ponemos en la pagina JSP. Cuando se traduzca en un
servlet, todo esto se traducira en sentencia out.write.

C 0 
! 


 
: Son trozos de codigo java embebidos en el JSP que se traducen en codigo en el metodo
jspService() del servlet. Las sentencias deben ser terminadas con ; como siempre en Java. Podemos poner
tbn. comentarios Java (// o /* */). sintaxis: <% %>

 
: Son trozos de codigo java embebidos fuera de jspService. Podemos declarar variables
estaticas o metodos enteros. Incluso podemos sobreescribir los metodos jspInit() y jspDestroy(). Sintaxis:
<%! %>

3: Las expresiones se evaluan y se imprime el contenido en la pagina HTML resultante. Las
expresiones deben ser expresiones de java validas. No debemos poner ;, ya que el contenido de la
evaluacion sera volcado al contenido de out.write(). Se pueden poner expresiones que se evaluen a
primitivas. <%= %>

"
:Podemos poner 2 tipos de comentarios:

a. Comentarios JSP - estos comentarios no se emiten en la pagina web resultante. <%- -%>

b. Comentarios HTML - <!- -> - Estos comentarios si son enviados al cliente (pero no son mostrados en
el browser obviamente)

** Un punto a tener en cuenta cuando buscamos errores en un JSP es que los Scriplets llevan ; después de
cada sentecia, mientras que las expresiones no.

C 0$
9 



'4: !:%



:
::::

#::-+!:
: ::
! :

Las directivas son procesadas en tiempo de compilación (esta es la mayor diferencia con los elementos
descriptos en el punto anterior.

!: Sintaxis <%@ page [atributo = "valor"]1o+ %>

p   : con este atributo podemos importar clases/librerias

EJ: <%@ page import="java.util.List" %> esto es traduce en el servlet como import java.util.List;

** Si queremos importar más de una libreria, separamos las librerias con "," o ponemos varias directivas.

- <%@ page import="java.util.List,java.text.*" %>

- <%@ page import="java.util.List" %><%@ page import="java.text.*" %>

p  
 : por default, este valor es true. Si lo ponemos en false, evitamos obtener la sesion
(optimizando un poco la performance)Ej. <%@ page session="false" %>
** No cometas el error de escribir la constante booleana false, en vez de "false". Los atributos siempre
van entre comillas.

p   

: este atributo nos permite setear el contentType (igual que el método
setContentType del ServletResponse.

p    


: este atributo nos permite setear si el Lenguaje de Expresión esta habilitado o no.
Si estamos bajo la versión 2.4, por default es true. Anterior a esta, por default is false. Aún estando en la
versión 2.4, podemos querer deshabilitar EL y para ello usamos este atributo.

 : Sintaxis <%@ include file="file" %>

El archivo es incluido en tiempo de compilación, por lo que se su contenido debe resultar en un jsp
válido. El "file" puede contener un camino relativo (al jsp que lo incluye) o uno absoluto (desde el context
root).


! : Sintaxis <%@ taglib prefix="ejemplo" uri="aPath/file" %>

Cada libreria de tags que incluimos debe ser definida mediante esta directiva. Los 2 atributos definen cual
va a ser el préfijo que se va a usar para identificar los tags de la libreria incluida y uri para indicar donde
se encuentra la libreria (cápitulo 9 contiene una descripción mas completa).

C 2$
9 
D- <




#
3

Un documento JSP es un JSP que obedece las reglas de sintaxis de XML. La siguiente tabla aclara como
traducir de sintaxis JSP a un documento JSP:

Elementos
Sintaxis JSP Documento JSP
scriplets
Scriplets <%..%> <jsp:scriplet>...</jsp:scriplet>
Expresiones <%=..%> <jsp:expresion>...</jsp:expresion>
Declaraciones <%!..%> <jsp:declaration>...</jsp:declaration>
Directivas
<jsp:directive.page>
page <@ page attr="value"%>
attr="value"</jsp:directive.page>
<jsp:directive.include> file="URL"
include <@ include file="URL"%>
</jsp:directive.include>
<@ taglib prefix="jsp"
taglib xmlns:jsp="value"
uri="http://java.sun.com/JSPs" %>
Comentarios
comentario JSP <%- -%> <!- -%>
comentario
<!- -%> &lt;!- -&gt;
HTML

El container tiene 3 maneras de darse cuenta que es un documento JSP. Las 2 primeras solo son válidas
para la versión 2.4:

1. La extensión del archivo es .jspx

2. <jsp-config>
<jsp-property-group>

<url-pattern> ... </url-pattern>

<is-xml> ... </is-xml>

</jsp-property-group>

</jsp-config>

3. Que el elemento root del documento JSP sea <jsp-root>

** Cuando estamos escribiendo código Java dentro de una acción en un documento JSP, debemos tener
cuidado de escapar los caracteres no válidos en XML, por ejemplo "<".

** Una página no puede contener sintaxis de JSP clásico y de documentos JSP mezclados.

C 7
 '
) 
9 !  # 4c9 !
 
09 ! 

2  7

8 
@+

C 
E@'
F 
@
 #



Los JSPs son creados para simplificar el proceso de desarrollo. La creación de HTML a través de los
servlets es muy incomoda para los programadores y directamente inaccesible para los diseñadores. Los
JSPs son páginas web especiales, en las cuales se puede embeber pedazos de código Java que producen la
parte dinámica. Si bien, en los comienzos se embebia el código Java directamente en el JSP, ahora es
mucho más común usar tags (provistos o custom) y de esa forma dejar el JSP lo más limpio posible de
código.

(1) JSP page translation: Se refiere a la traducción de la página JSP en una clase java. Con Tomcat, esta
clase va a ser una extensión de org.apache.jasper.runtime.HttpJspBase (clase que implementa la interface
javax.servlet.jsp.HttpJspPage. Si bien, algunos plugins de Eclipse per miten que se muestre como va a ser
la clase de implementación, no se si esto se puede saber con certeza, ya que el container va a ser el
encargado de generarlo.

(2) JSP page compilation: La compilación de la clase de implementación creada a partir del JSP, genera
una clase (archivo .class) que es un servlet que va a ser usado como los servlets tradicionales.

** Los puntos (1) y (2) pueden ser hechos tán pronto como los JSPs son deployados en el container hasta
justo antes de ser requeridos por algun cliente.

(3) Desde este punto en adelante, seguimos el módelo de Servlets. Es decir, cuando se hace un
requerimiento el classloader carga la clase en el container inicializando todos los datos estáticos.

(4) Luego se crea una instancia del servlet. Si no se introdujo ninguna entrada en el deployment
descriptor, entonces el container va a crear solamenta 1 instancia. Si se introducen entradas en
deployment descriptor, se crearán 1 instancia por cada entrada.

(5) Luego se llama al método jspInit() del jsp servlet.

(6) Luego se llama 1 o más veces al jspService(). Se creará un thread por cada uno de los requerimientos.

(7) Cuando ya no se van a registrar más requerimientos, se llama a jspDestroy() para liberar todos los
recursos ocupados ordenadamente.
C 8'!! %
9 !

 
@
4)


 !  
!!!"
3
3


(a) y (b) request y response son objetos de tipo javax.servlet.http.HttpServletRequest y


javax.servlet.http.HttpServletResponse.

(c) out es un objeto de tipo JspWriter. La mayor diferencia con el objeto obtenido a partir de get
PrintWriter del response es que éste utiliza un buffer mientras que el otro hace el commit i nmediatamente.

(d) session: es el objeto HttpSession disponible por default.

(e) y (g) config y page son 2 objetos que no son muy usados. config es de tipo ServletConfig y sirve para
obtener los parametros seteados en el deployment descriptor. page es un objeto que representa la instancia
del servlet resultante.

(h) pageContext representa un objeto madre a través del cual se pueden acceder atributos en todas los
otros scopes. Ademas, a este objeto se le pueden atachar atributos por lo que define un scope (que es el
más limitado de todos). Los métodos para obtener/setear/borrar atributos en otros scopes tienen los
mismos nombres, pero incluyen un parámetro nuevo de tipo entero que define el scope. Para no usar
números, la clase PageContext tiene definida constantes: PAGE_SCOPE, REQUEST_SCOPE,
SESSION_SCOPE Y CONTEXT_SCOPE.

(i) exception es un objeto que puede ser accedido en las páginas de error, osea aquellas páginas que
tengan una directiva <%@ page isErrorPage="true" %>.

C F' !!   !9 !



!%

9 





 
 
'
@4 



La diferencia más importante entre la directiva <@ include file="URL"> y < jsp:include page="URL"/>
es que la primera se procesa en tiempo de compilación del JSP, mientras que la segunda se procesa en
tiempo de ejecución. Una implicancia de esto que en la acción se pueden usar expresiones para indicar la
página a incluir (la página a incluir puede no existir cuando se deployea la aplicación y ser generada
dinámicamente).

F c'%
-


  %! 
'  !!)

 
 B B 1

!"
3

EL es un lenguaje que sirve para simplificar la creación de páginas jsp, ya que permite acceder facilmente
a todas los scopes, a atributos en todos ellos (pero no a variables locales del _jspService()), crear
expresiones lógicas y aritméticas, etc. No hay nada que no se pueda hacer sin EL, pero definitivamente
hace todo mucho más fácil.

EL trabaja con booleanos, enteros, reales, String y tbn. tiene el literal null.

Para construir una EL, ubicamos la expresión entre ${ .. }

El objetivo 7.1 del exámen aborda las diferentes variables implicitas de EL. Las 4 primeras ( !,
)
,  y  
). tienen que ver con el acceso a los diferentes scopes.
Estas variables son equivalentes a las ya conocidas page, request, session and application pero no retornan
un objeto de tipo HttpServlet, HttpSession, etc sino que retornan mapas con los atributos de cada
scope. De esta maneram el acceso a los elementos muy sencillo.

 y B  son 2 variables implicitas que permiten acceder los parametros del JSP. param
retorna un map de los parametros y los primeros valores de cada parametro. paramValues retorna un map
con los parametros y todos los valores de cada uno de los parámetrosde un arreglo de String.
 y B sigue el mismo patrón.

1 retorna un map de cookies


 un map de parámetros del servlet.

!"
3
representa el objeto PageContext, a través del cual s puede acceder a los objetos
'ServletContext', 'HttpSession', 'HttpRequest'.

F 0'%
-


  %!
4
#
 
 


GH


Un atributo de un javabean puede ser accedido utilizando tanto el operador . como el operador [].

entonces, ${miatributo.mipropiedad} es igual a ${miatributo["mipropiedad"]} //en java:


javaBean.getMipropiedad()

En el caso de los mapas, se puede utilizar las keys como si fueran un atributo de un javaBean y por
consiguiente, la síntaxis para acceder a un elemento es igual:

${mimapa.key} es igual a ${mimapa["key"]} //en java: mimapa.get("key")

El operador [] también sirve para acceder arrays, pero el indice no tiene que ser estrictamente un entero
como en Java, sino que puede ser cualquier elemento que pueda ser transformado en un entero (un string,
un Integer, etc.).

${miarray[5]} es igual a ${miarray["5"]} // en java: miarray[5]

** Si el subindice no puede ser transformado al entero, arroja una excepción (ELException), pero si el
elemento no es un indice válido (overflow) la expresión no devuelve nada (no arroja error).

Las listas pueden ser accedidas de la misma manera que un arreglo:

${milista[5]} es igual a ${milista["5"]} // en java: milista.get(5)

F 2'%
-


  %!
4


 
 
 ! 




6
4 (+, -, *, /, %).

** Las divisiones son siempre reales y no arrojan excepciones cuando se divide por 0, sino que devuelve
Infinity.

 A!4 (> o gt, < o lt, <= o ge, >= o le, == o eq, != o ne) La forma alternativa permite
bypassear el problema de < y > dentro de un XML.

 A!: (&& o and, || o or, ! o not).

Opeador empty: ${ empty obj} retorna true cuando el objeto es null o es un array vacio, un string sin
caracteres o un Map sin elementos.
F 7'%
-

 
&%
 - 
& !
- 


! # 




Los pasos para usar una función EL son exactamente los mismos que para usar un custom tag:

c   

La única condición para que un método escrito en cualquier clase pueda ser usado como una función EL
es que sea estático y publico.

0    A !-#





La definición de la función en el TLD tiene la siguiente sintaxis:

<function>
<description></description>
<name></name>
<function-class></function-class>
<function-signature></function-signature>
</function>

Donde <name> define el nombre de la función tal cual va a ser usada en los JSPs, <function-class> da la
clase que lo implementa (nombre completo de la clase, incluyendo los paquetes) y <function-signature>
define la signature. En la signature no hacen falta poner los calificadores. De los parametros, solo hace
falta poner los tipos (de nuevo, nombres completos!).

2 '
  A 
% 3

La manera de declarar el TLD en web.xml y definir el jsp que se va a usar ese tag es la misma que para
custom tags.

<jsp-config>

<taglib id="..." >

<taglib-uri>....</taglib-uri>

<taglib-location>....</taglib-location>

</taglib>

</jsp-config>

7   
 '@

Esta parte, también es igual para los custom tags:

<%@ tagib prefix="mitag" uri="..." %>

Finalmente, el uso de las funciones es una mezca entre EL y custom tags.

${mitag:aMayu("hola") }
ü c'!! 

 !
  %!

4@4;%



4::::
:
#:: :@4!

#@4

#%
 





Las acciones son componentes de negocios con un nombre que pueden ser embebidos en la página web.
La idea es poder sacar la lógica de los JSPs (de los scriplets, declaraciones, etc) y ponerlas en una clase
que podrá ser incluida en el JSP. Existen 2 clases de acciones: Estandar (previstas en la especificación) y
custom (hechas especificamente para algo). Las 3 acciones de este punto son estandares.

>@4;IJ@ J IJ


% @ J
#IJ
% 
 J
IJ!JJ)
JJJJ
3
J?

-  va a ser el nombre del javabean (dentro del método es una variable global. Fuera de él, es el nombre
de un atributo)

-  es el nombre completo de la clase (paquete + nombre de clase). Esta clase tiene que estar dentro de
WEB-INF/classes o en WEB-INF/lib.

-
# puede ser usado para declarar la variable del javabean como un tipo compatible (gralmente no el
mismo). Por ejemplo, puede ser un supertipo o una interface que la clase implemente.

-  define el scope del javabean.

>@4

#IJ@ J
#IJ 5J' IJ  J
IJE EJ?

Esta acción permite setear una propiedad del javabean.

-  define el nombre del javabean.

- 
# define el valor de la propiedad a ser seteada (en realidad es el nombre del setter).

- '  es el valor a setear. Aquí podemos usar una expresión (<%= %>). Podemos poner  + el
nombre de uno de los parametros recibidos en el 'request'. Si el nombre del parametro coincide con el
nombre de alguna propiedad del bean, entonces se asignara el valor recibido. Si en vez de poner los
atributos value/param, ponemos solamente un atributo llamado - 
#="*" - esto asignará a todas las
propiedades (que concuerden) los valores recibidos en los parametros.

>@4!

#IJ@ J
#IJ 5J?

Esta es la más fácil. Solamente tenemos que poner el 'name' del java bean y la 'property' que queremos.

** Es importante acordarse que dentro de useBean se utiliza el atributo 'id' para identificar el java bean.
Sin embargo, en setProperty y getProperty se utiliza el atributo 'name'.

ü 0'!! 

!
  %!

4@4 @4 %@4 

>@4 ?

Esta acción estandar permite incluir la salida de otro archivo en la salida. La sintaxis es la siguiente:

>@4 !IJ

@J IJ
K  J?

Es muy similar a RequestDispatcher.include(). La diferencia clave con la directiva <@ include> es que la
directiva incluye el contenido en tiempo de compilación, mientras que la acción lo incluye en tiempo de
ejecución. Esto tiene las siguientes consecuencias:

1. Se pueden usar una expresión para especificar el archivo (osea que es mucho más flexible). Ejemplo>
<jsp:include page='<%=request.getParameter("nombre") %>'>

2. El archivo que se incluye puede no existir (osea puede ser generado en tiempo de ejecución)



>@4 %?

Esta acción estandar forwardea la responsabilidad de la creación de la respuesta a otro recurso. Todo el
contenido por el jsp original es completamente ignorado (osea que si ya se ha hecho un commit del
buffer, se arrojará un IllegalStateException.

La sintaxis es la siguiente:

,<jsp:forward page="lalala.jsp' />

>@4?

Esta acción puede ser embebida en <jsp:include> y <jsp:forward> para agregar paramétros al request.
Por ejemplo:

,<jsp:forward page="lalala.jsp' >

<jsp:param name="nombre" value="Carlos">

</jsp:forward>

Los paramétros viven en el recurso forwardeado o incluido y dps. desaparecen.

L c

! # #  ! 

:
! : 
' 9 !

Los custom tags son elementos/componentes que encapsulan un comportamiento. La idea que subyace
detras de los custom tags es que se elimine el código Java en la página JSP. El diseñador podrá usar estos
custom tags sin saber como están programados. Los programadores seremos los encargados de proveer
estos componentes para que sean usados. Esto implica que el código Java estará en clases, por lo que el
diseño será mucho mas limpio.

Para hacer disponibles un conjunto de tags en un JSP, primero debemos declararlo en el JSP. La sintaxis
es la siguiente:

<@ taglib prefix="..." [tagdir=/WEB-INF/tags/dir | uri=" ... " ]

El prefijo se usara en todos los tags que se quieran utilizar en el JSP. Debe ser un prefijo unico en todas
las páginas donde esta declarado (1. no pueden usarse prefijos estandar como: java, javax, sun, sunw, etc.
2. Tenemos que tener en cuenta las paginas incluidas, ya que el espacio de nombres es unico)

Como se puede ver en la sintaxis, el segundo atributo puede ser uri o tagdir. 'uri' se usa cuando el tag ha
sido definido en un tag handler, osea en una clase java.

Ejemplo de la libreria core de JSTL:

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>


El uri declara un nombre único, que sera usado en % 3 para definir la ubicación de la libreria de tags
de esta manera:

<jsp-config>

<taglib id="..." >

<taglib-uri>....</taglib-uri>

<taglib-location>....</taglib-location>

</taglib>

</jsp-config>

** el atributo "id" serviría para identificar los diferentes mapeos ( ver dtd)

Si no especificamos explicitamente la ubicación de la libreria de tags con las entradas anteriores, el


container buscar dentro de los jars que deben estar empaquetados de una manera especial.

Finalmente, lo único que resta definir es el TLD ( DTD).

<taglib + una serie de atributos>

<tlib-version></tlib-version>

<jsp-version></jsp-version>

<short-name></short-name>

<tag>

<name></name>

<tag-class></tag-class>

<body-content></body-content>

<attribute>

<name></name>

<required></required>

<rtexpvalue></rtexprvalue>

</attribute>

</tag>

</taglib>

Donde:

- name es el nombre del tag.


- tag-class es el tag handler

- body-content define el contenido del tag: empty, scriptless (sin código Java), tagdependent (el container
no evalúa el contenido, sino que el custom tag lo hace) y JSP (el más permisivo de todos).

- dentro de los atributos, tenemos el 'name' de nuevo y luego 'required' que determina si es obligatorio y
'rtexpvalue' que determina si se pueden usar EL para el valor del atributo.

Si la libreria de tags esta definida usando tag files, usamos el atributo


!='/WEB-INF/tags/dir' (los tag
files son estudiados con más profundidad en 10.5).

L 0'!! 



!

 9 !



!

La sintaxis de los custom tags es la siguiente:

<prefix:tag attr1="..." ... attrN="..." />

<prefix:tag attr1="..." ... attrN="..." >

body

<prefix:tag />

Por ejemplo:

<ejemplo:mayusculas>federico</ejemplo:mayusculas>

L 2'!! 
9 
 !-#9 -'c c
! 
JJ
! #

Struts fue el primer framework que provee un conjunto de tags con funcionalidad comun a muchas
pàginas JSP (iteradores, condicionales, acceso a recursos URL, formateo, internacionalización, etc) pero
no fue el único. Muchos frameworks desarrollaron conjuntos de tags. JSTL nace como un proyecto open
source de Apache (http://jakarta.apache.org/taglibs/) para estandarizar esto. SUN luego lo incorpora a la
especificación en especificiones posteriores.

La libreria estandar de taglibs ofrece tags en las siguientes areas (tabla obtenida del J2EE tutorial 1.4)
La segunda table muestra mas en detalle los Core tags


' 

à 
El tag set sirve para setear una variable EL o una propiedad de una variable EL en cualquiera de los
scopes. Si la variable no existe, entonces es creada (la semantica es la misma que useBean. El valor se
puede especificar en el atributo "value" o en el cuerpo del tag:

<c:set value="test" var="foo" />

<c:set var="foo">test</set>

El valor puede ser constante o puede ser calculado mediante una EL, como en el siguiente ejemplo:

<c:set value="${valor1 + valor2}" var="valor_final" />

Para especificar el scope, debemos incluir el atributo scope.

<c:set value="${valor1 + valor2}" var="valor_final" scope="session" />

**Si no lo incluimos, toma por default page (como siempre).

Si quisieramos setear una propiedad de una variable EL, debemos reemplazar var por target + property de
la siguiente manera:

<c:set value="50" target=${pageContext.session} property="maxInactiveInterval" />

à  

Si queremos borrar una variable EL, utilizamos el tag remove especificando ' y :

<c:remove var="test" scope="session" />

"
  @

à 

Este tag permite la ejecución del cuerpo de acuerdo al resultado de la evaluación de una expresión
definida en el atributo test:

<c:if test="${!empty param.nombre]"> ... </if>

También se puede guardar el resultado de la evaluación en una variable, para poder usarlo más adelante
(si hacemos esto, el cuerpo del tag será vacio)

<c:if test="${!empty param.nombre]" var="es_nom_vacio" scope="session" />

à    




Estos 3 tags emulan la sentencia switch de java. La diferencia es que solamente se ejecuta el cuerpo de la
primera condición verdadera. Si ninguna de las condiciones es verdadera, entonces el cuerpo de default se
ejecuta. Por ejemplo:

<c:choose>

<c:when test="${edad eq 10}">Tiene 10 años</c:when>


<c:when test="${edad eq 20}">Tiene 20 años</c:when>

<c:otherwise>no tiene ni 10 ni 20 años</c:otherwise>

</c:choose>

à    à

Este tag nos permite iterar sobre diferentes tipos de Collection. La col lection se especifica en el atributo
items, mientras que el elemento corriente de la iteración se especifica a través del atributo var.

El siguiente ejemplo nos permite mostrar los primeros elementos de todas las cabeceras:

<c:forEach var="hdr" items="${headerValues}">

<tr><td>${hdr.key}</td><td>${hdr.value[0]}</td>

<c:forEach>

Este tag soporta todos los tipos de colecciones y Maps. Si es un map, ' se va a instanciar con un objeto
de tipo Entry. También soporta arrays de primitivas, aunque el valor actual se va a wrappear
automaticamente. También soporta String, pero en este caso existe la condición de que los diferentes
tokens esten separados por una coma.

Para iterar sobre un conjunto de tokens separados por otro elemento, utilizamos el tag
<c:forTokens>. Este tag como se pueden imaginar permite especificar el delimitador, utilizando el
atributo "delims".

@(*-

à 


<jsp:include> nos permite incluir un recurso en tiempo de ejecución. Sin embargo, tiene 2 problemas: 1.
no nos permite incluir recursos que esten fuera de la aplicación web. 2. Provoca un buffering innecesario
cuando la salida es usada por otro elemento del JSP. El tag import soluciona estos dos problemas.

Entonces, si queremos importar un recurso de otro contexto, lo hacemos de esta manera:

<c:import url="ejemplo1" context="/ejemplo1" />

o directamente incluimos una URL externa

<c:import url=http://www.ejemplo.com/recurso.jsp/>

Si queremos almacenar el recurso incluido, simplemente especificamos la variable y el scope medianle


los atributos '=B* y . VarReader importa el contenido directamente en un reader.

à 

Este tag nos permite crear y almacenar una URL para luego ser usada en la JSP.

<c:url value="/lala.jsp" context="/ejemplo1" var="m_link" />

La ventaja que nos brinda este tag con respecto a incluirlo directamente es que escribe el jsessionid en
caso que el cliente deshabilite el mecanismo de cookies.
Otra manera de incluir los parámetros es a través de la action c:param de esta manera:

<c:url value="/lala.jsp">

<c:param name="userid" value="fede">

</c:url>

à 
 

Este tag representa exactamente el método HttpServletResponse.redirect(). El atributo obligatorio es url,


que puede contener una URL completa (con método y nombre de servidor) o relativa a la URL actual.

<c:redirect url="http://www.clarin.com/espectaculos.asp" />

También se puede incluir una url relativa y el context:

<c:redirect url="ejemplo1.jsp" context="/ejemplo1" />

à   

Este atributo nos permite añadir parametros a cada uno de los tags anteriores

<c:url value="/lala.jsp" context="/ejemplo1" var="m_link" >

<c:param name="nombre" value="Fede" />

<c:param name="apellido" value="Zuppa" />

</c:url>

 

à 

El tag out evalua una expresión y manda el resultado a un JspWriter. La sintaxis es la siguiente:

<c:out value=" ... " [escapeXml="{true|false}"] [default="dafaultValue"] />

Si escapeXml=true, el tag transformará las caracteres de XML inválidos en las entidades que
corresponden. Por otra parte el atributo default nos permite especificar un valor por default, que será
enviado al JspWriter cuando la expresión se evalúa a null.

à  

Este tag nos permite interceptar errores para que no sean propagados. Este tag se ubica rodenado todo el
código que pueda arrojar un error.

<c:catch>
<jsp:scriptlet>out.write(6/0);</jsp:scriptlet>
</c:catch>

Se puede especificar un atributo "var" con el nombre de la excepción para luego ser accedido más
adelante.
cM c

 
J" J

!'
 %'




!
;# !3
3 %


'  
'

&%

!  

Como ya hemos visto, los tags que usamos en un JSP estan 'respaldados' por una clase Java que define su
comportamiento (dicho de otra manera, para hacer un custom tag debemos definir el rotulo que se va a
usar en la página JSP y escribir el comportamiento, es decir que va a ocurrir cuando el container llegue a
ese tag en el JSP, en una clase Java. A esta clase Java la llamamos tag handler y debe implementar una
interface que define el comportamiento.

Mas precisamente, debemos implementar una de las 3 interfases provistas o heredar nuestra clase de una
de las 2 clases de soporte:

  


Implementaremos esta interface para desarrollar los tags más sencillos, aquellos que no requieran ni iterar
ni manipular el contenido. Estos métodos serán invocados por el web container, cuando se llegue al tag en
cuestión en el JSP. Los métodos, enumerados en el orden que son invocados por el web container son los
siguientes:

1. setPageContext(PageContext)

2. setParent(Tag)

3. setAttributes....

4. doStartTag()

5. doEndTag()

6. release()

 Los 2 métodos principales son:




*#$ - que será invocado cuando se encuentré el tag de comienzo. Este método debe retornar un
valor entero, definido por 2 constantes:

EVAL_BODY_INCLUDE: El body debe ser evaluado.

SKIP_BODY: Salta directamente al doEndTag, salteando el body.

 *#$ - que será invocado cuando se encuentre el tag de fin. Este método tambien retorna un
entero, definido por otras 2 constantes:

EVAL_PAGE: indica que se continue evaluando la página.

SKIP_PAGE: indica que se aborte el procesamiento del resto de la página.

** Si al evalúar el cuerpo del tag se produce una exception, doEndTag() no será evaluado (un workaround
puede ser user try-catch-finally)

 Antes de invocar el método doStartTag(), el container invocará los siguientes métodos:


+ ,

#+ ,

$ - Este método es invocado por el container con el objeto
pageContext. A través del pageContext se gana acceso a todas las propiedades del JSP, incluyendo
atributos, sesiones, etc. Además, con el pageContext podemos escribir a la salida utilizando OUT que es
de tipo JspWriter.


+
#*$ - Este método permite setear el tag que contiene al tag actual. Es llamado por el
container solamente en el caso que el tag tenga un parent.

Además, el container setea todos los atributos del tag con los valores provist os en el JSP.

Finalmente, cuando el container decide sacar de servicio al tag handler, se invoca el método release() para
liberar recursos.

 A 
! !-#


Una vez que hicimos la parte más dificil, que es escribir la lógica del tag en el tag handler, tenemos que
definir el tag en un tag library descriptor y por último declarar la libreria de tags en el JSP donde se quiera
utilizar. A continuación veremos como se define un tag en un tld.

A
D

A DA D

A
 DA
 D

A$ *3  DA$ *3   D

A!$ D

A DA D

A H! *DA H! *D

A 25  DA 25  D

A!$ D
A
D

 es el nombre del tag

!<  define el tag handler

#<

determina que contenido puede tener el body del tag:


#: no puede tener body


: no se puede usar código Java, osea que no pueden ir scriplets, expresiones, declaraciones,
etc. Si puede ir EL.


!
: todo lo que vaya en el cuerpo, va a ser interpretado como template text por el container.
Es el tag el que le da el sentido.

9 : es el más permisivo. Puede ir cualquier cosa.



: todos los parámetros del tag se definen aquí. name es el nombre del parámetro, required
determina si el parametro es obligatorio y rtexprvalue determina si el valor se puede calcular en tiempo de
ejecución.

 


Esta interface, que extiene a la interface Tag y por lo tanto hereda todos sus métodos tiene 1 método
nuevo y una constante nueva.El método nuevo es doAfterBody() y será invocado entre doStartTag() y
doEndTag():

1. setPageContext(PageContext)

2. setParent(Tag)

3. setAttributes....

4. doStartTag()

5. doAfterBody()

5. doEndTag()

6. release()

La constante nueva es utilizada justamente cuando queremos evaluar el cuerpo nuevamente. Su nombre es
EVAL_BODY_AGAIN. Cuando doAfterBody() retorne este constante, el web container evaluará
nuevamente el cuerpo y luego invocará a doAfterBody nuevamente. Cuando queremos terminar con la
iteración, se devuelve SKIP_BODY.

 


Con las 2 interfaces anteriores se puede insertar contenido antes o después del cuerpo del tag, pero no se
puede modificar el cuerpo del tag. La interface BodyTag permite justamente esto: modificar el contenido
del tag. Para ello, agrega 2 métodos nuevos:

1. setPageContext(PageContext)
2. setParent(Tag)

3. setAttributes....

4. setBodyContent(BodyContent)

5. doInitBody

6. doStartTag()

7. doAfterBody()

8. doEndTag()

9. release()

BodyContent extiende a JspWriter, pero almacena todo el contenido producido en un buffer. Para que
setBodyContent sea invocado por el container, doStartTag debe devolver una constante no estudiada
hasta el momento: EVAL_BODY_BUFFERED.

** si doStartTag no devuelve EVAL_BODY_BUFFERED, el método setBodyContent no es invocado.

Una vez que hemos almacenado el objeto BodyContent, el container llama la método doInitBody. Este
método nos permite modificar el BodyContent antes de que sea evaluado. Por ejemplo, si queremos
insertar algo al comienzo del cuerpo, lo hacemos de esta manera:

bodyContent.print("en doInitBody");

Al retornar de doInitBody, el bodyContent es evaluado por el container y almacenado en un


buffer. Entonces, cuando se invoque doAfterBody o doEndTag debemos escribir todo el contenido del
buffer en el JspWriter que lo contiene. Para esto, BodyContent provee 2 métodos:

- writeOut: apendea el contenido del buffer al JspWriter.

- getEnclosingWriter: devuelve el JspWriter del tag que contiene el cuerpo.

bodyContent.writeOut(bodyContent.getEnclosingWriter());

Otra manera es a través del método TagSupport.getPreviousOut()

bodyContent.writeOut(getPreviousOut());

cM 0(!
 !"
3
 +%

! 

9  
' 
% 





El objeto PageContext es el puente para acceder a todas las variables implicitas del JSP (request,
response, session, config, application, etc.). Como ya sabemos, este objeto se pasa al tag handler antes de
llamar a cualquiera de los otros métodos. Nosotros no tenemos más que guardarla en una variable de
instancia privada. Los métodos para obtener los objetos son los siguientes:

- ServletRequest getRequest()
- ServletResponse getResponse()

- getOut()

- HttpSession getSession()

- ServletConfig getServletConfig()

- ServletContext getServletContext()

- Object getPage() - cuidado que retorna un Object, no un Servlet

- Exception getException() - solo funciona si el JSP es una página de error

** Una buena regla memotécnica: Todos los getter se corresponden con la variable implicita de JSP,
excepto getServletConfig y getServletContext que se corresponden con las interfaces.

cM 2'%

! 



!
#
!


El método para setar el parent en el modelo clásico es:

setParent(Tag)

por lo que el método para obtenerlo en TagSupport obviamente devuelve un Tag.

Mientras que en el módelo Simple es:

setParent(JspTag)

por lo que el método getParent en SimpleTagSupport devuelve un JspTag

Tanto Tag como SimpleTag son heredados de JspTag:

Los 4 casos que podemos obtener son:

Simple --> Simple

Classic --> Classic


Classic --> Simple

Simple --> Classic

Los 2 primeros casos no tienen ningun tipo de complejidad, ya que getParent() retornara un objeto del
mismo tipo.

En el 3er caso, tenemos que dentro de un classic custom tag tenemos un Simple custom tag. Cuando se
llame al método setParent(JspTag) no habrá ningun problema, porque Tag es de tipo JspTag. Por lo tanto
acceder al padre no ocasianará ningun tipo de problemas. El 4to caso es el más complicado. Cuando un
Simple Custom Tag contiene un Classic Custom Tag. Si lo pensamos un poquito, nos daremos cuenta que
setParent(Tag) no funcionaría porque SimpleTag no es de tipo Tag. El patrón de diseño Adapter viene a
nuestro rescate (Adapter Design Pattern) El JSP container (solito!) se da cuenta de esta situación y llama a
setParent utilizando un objeto de tipo TagAdapter que tiene como adaptee un JspTag que representa al
SimpleTag padre.

** El método findAncestorWithClass utilizará el adaptee para hacer las comparaciones.

cM 7

 
J J

!'
 %
'


 !3
&%

!  &3 



9 


%


!

Las 3 interfaces del modelo clásico son reemplazadas por una: SimpleTag. Utilizando esta interface
se puede hacer todo lo que se hace con las 3 anteriores, y sin necesidad de conocer todos los detalles de
los códigos de retorno. Los métodos que el container llamará son los siguientes:

1. setJspContext(JspContext jsp)

2. setParent(JspTag tag)

3. setAttributes

4. setJspBody(JspFragment fragment)

5. void doTag

Dentro de doTag se puede manipular el body del custom tag para hacer lo que se quiera (imprimirlo
muchas veces, cambiar los valores, etc.). Esto es porque el cuerpo del tag es recibido en un objeto de tipo
JspFragment(es decir el contenido es encapsulado en uno de estos objetos). Es importante remarcar que el
cuerpo, para este tipo de tags no puede ser JSP (es decir no pueden haber scripting elements). Cuando
simplemente se quiere imprimir el contenido del cuerpo al output stream, se invoca al método '1 con
null como parámetro (es decir, se utiliza el JspWriter asociado al JspContext).

public void doTag() throws JspException, IOException {


getJspBody().invoke(null);
}
Al igual que en los classic custom tags, existe una clase que podemos extender para evitar implementar
todos los métodos de esta interface (también tiene helper métodos útiles como getJspContext()) llamada
SimpleTagSupport.

cM 8

 
 !  &
% 


 
!
 &%

!  &3 



9 


# 

!
La idea de los tags files es que podamos escribir custom tags sin tener que escribir una sola linea de
código java. El tag file será escrito como un JSP. Cuando el web container encuentre un tag escrito de
esta manera, generará una clase de tipo SimpleTag y la compilará pudiendo así invocar el método que
corresponda. Otra simplificación del modelo de tag files es que no es necesario definir un TLD. El
nombre del tag file que lo define será el nombre del tag en el JSP. Además, dentro del tag file se prodrán
definir los atributos que sean necesarios.

Para crear un tag file, creamos un archivo .tag dentro de /WEB-INF/tags. El nombre del archivo será el
nombre del tag. Osea que si quiero crear un tag que se llame table_test, el archivo se llamará

 E


!. Aquí va aun ejemplo:

<%@tag description="test" pageEncoding="UTF-8"%>

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>


<%@ attribute name="num" %>

<table>
<tr><td>Numero</td><td>Cuadrado</td></tr>
<c:forEach begin="1" end="10" step="1">
<tr><td>${num}</td><td>${num*num}</td></tr>
<c:set var="num" value="${num+1}"/>
</c:forEach>
</table>

Se puede ver que la sintaxis es JSP (HTML + JSTL + EL). Tiene algunas cosas nuevas, como la directiva
'tag' que solamente se usa en tag files y que sirve para definir ciertas propiedades del tag que para los
classic custom tags se definen en el TLD (como bodycontent) y en la entrada jsp-property-group de jsp-
config (EL-ignored). La directiva 'attribute' sirve para definir atributos (esto tbn. se define en el TLD en
los classic custom tags).

Dentro del JSP, primero se hace disponible este tag file, pero esta vez se reemplaza el parametro 'uri' por
'tagdir'. Para el ejemplo, la declaración será la siguiente:

<%@ taglib prefix="test" tagdir="/WEB-INF/tags/" %>

Luego, solamente nos resta usarlo:

<test:table_test num="1"/>

Un punto que es importante estudiar es cuales son las directivas válidas para Tag Files. Solo son 5, de las
cuales 3 pertenecen solamente al mundo de los Tag Files

! - se puede decir que es similar a page en JSP


 - sirve para definir atributos del tag. En classic custom tag o simple tags, los atr ibutos se
definen en el .TLD

'  - sirve para definir una variable EL que será transmitida al JSP que use el tag.

Estas son las 3 nuevas... Las otras dos son


!  e   (su comportamiento es exactamente el mismo,
excepto que si el contenido incluido no es apto para Tag Files, se producirá un error en tiempo de
compilación)

cc c'
%
 
  




%  '
 
 
 

#
1%4+

!
 <B%<"
 

"
 '-
; !
  @

cc 0
!

%



!

  


 

 


 # 
  %!

4+

!
 <B%<"
 

"
 '-
; !
  @

+

!


Este pattern esta relacionado con todas esas tareas que a veces tenemos que hacer que no estan
relacionadas con la lógica de negocios de nuestra aplicación, tales como logging, debugging, seguridad,
validación de sesiones, etc. Poner el código para hacer estas tareas en los servlets conlleva muchimas
desventajas:

1. El código se repite en todos los servlets (problemas copy-paste!)

2. Coupling entre el código de pre-procesamiento, el de post-procesamiento y la lógica de negocios.

Este patrón indica que estas tareas deben ser hechas a traves de filtros que se concatenan tanto en el
preprocesamiento como en el post-procesamiento. Un filter manager combina estos filtros (loosely
coupled) delegando el control al filtro apropiado. De esta manera se pueden agregar, remover o combinar
los diferentes filtros de muchas maneras, sin alterar la lógica de negocios.

Este pattern esta contemplado en la especificación de Servlets 2.3 a través de los 'Filters'

Entonces, para sintetizar:

Escenario: tenemos que agregar una tarea común a todos los servlets, que no esta relacionado con la
lógica de negocios.

Beneficios: 1. Eliminar duplicación de código. 2. Los componentes son debilmente acoplados.

[Core J2EE Patterns]


"
 

Este pattern nace de la necesidad de tener un punto de acceso único a la aplicación, que facilite el manejo
de System Services, obtención de contenidos, manejo de vistas, etc. Si nos situamos dentro del pattern
MVC, el 'Front Controller' es el componente que recibe los requerimientos, los forwardea a los elementos
encargados de procesar la lógica y luego lo forwardea nuevamente a la vista (esta vez incluyendo los
datos obtenidos). Si no tuvieramos un punto de acceso único, tendríamos los siguientes problemas:

1. Código duplicado (nuevamente)

2. Manejo no centralizado de vistas

El ejemplo más conocido de un Servlet que implementa este pattern es el ActionServlet de Struts. Este
servlet se 'configura' mediante un archivo llamado servlet-config.xml que determina cuales son los
'Actions' que van a procesar el requerimiento y cuales son las vistas que serán mostradas luego de ser
procesado.

**No conozco otro uso que no sea en MVC.

 <B%<"
 

Este pattern es una pattern de más alto nivel que los 2 anteriores. La idea de este pattern es separar
completamente la lógica de negocios y la vista, uniendolos solamente a través de un Controller. Esta
separación permite por ejemplo que en la vista trabajen diseñadores gráficos, mientras que la lógica
esta hecha por programadores o poder cambiar la vista (de JSPs a XSLT) sin que esto conlleve ningun
cambio en la lógica, es decir en el modelo.

En este pattern tenemos 3 componentes:

El modelo: Formado por los objetos de negocios (POJOS o EJBs)

La vista: Es la encargada de mostrar los datos (primero de los forms iniciales y luego de los re sultados
obtenidos)(JSPs, XSLT, etc.)

El Controller: es el encargado de determinar en base al requerimiento cuales son los objetos que
procesarán el requerimiento y luego de forwardear a la vista que corresponda los resultados
(generalmente es un servlet, configurado a través de un XML o de un property file)

Este pattern se utiliza en todas las aplicaciones desde medianamente complejas hacia adelante (por un par
de páginas, el overhead es demasiado)

La clásica imagen del tutorial de J2EE

; !


La idea de este patrón es intentar disminuir la complejidad que tiene acceder a componentes de negocios
remotos. Los problemas que surgen son de 3 tipos:

1. La interfase del componente puede cambiar, por lo que el cliente también deberá hacerlo (esto reduce
la flexibilidad)

2. Cuando un cliente interactúa directamente con un componente de negocios remoto, esto puede requerir
muchas invocaciones. Si a esto le sumamos que las invocaciones son remotas, los problemas son muchos
mayores.
3. El 3er problema es toda la infraestructura con la que el cliente tiene que lidiar para acceder
directamente a componentes remotos (JNDI, lidiar con los errores, etc.)

El 'business delegate' es una abstracción de la capa de negocios en el cliente que esconde los detalles
'sucios' de la interacción con objetos remotos, es decir se encarga de obtener los EJBs mediante JNDI, se
encarga de instanciarlos, se encarga de lidiar con las excepciones remotas que para el cliente no tienen
sentido transformandolas en excepciones de aplicación, se encarga de tratar nuevamente en el caso que
esto ayude y hasta puede actuar como un cache (para no tener que obtener el EJB handle nuevamente por
ejemplo)

** El cliente puede estar en el web container y llama a un objeto del EJB container (dent ro de la misma
JVM) o puede ser un cliente remoto realmente. El pattern se aplica en ambos casos.

'-


La idea de este patrón es encapsular toda la lógica requerida para hacer lookups en servicios remotos
(JNDI) en un componente. Además, este componente puede ser usado como un caché de las referencias
remotas obtenidas (ya que el mecanismo de lookup puede ser bastante caro).

 @

La idea de este patrón es evitar 'muchos' llamados remotos (chatty calls) agrupando todos los datos que se
quieren obtener en un JavaBean (el transfer object). Luego el cliente podrá obtener todos los datos que
necesite haciendo llamadas a getters locales. El beneficio de este patrón es que se elimina el overhead
dado por las multiples llamada a través de la red, reduciendola a 1 llamada (que obviamente mandará un
objeto mucho más grande). Obviamente, este javabean debe ser serializable (para poder ser mandado
remotamente).

Você também pode gostar