Top Banner
1.1 For each of the HTTP Methods (such as GET, POST, HEAD, and so on) describe the purpose of the method and the technical characteristics of the HTTP Method protocol, list triggers that might cause a Client (usually a Web browser) to use the method; and identify the HttpServlet method that corresponds to the HTTP Method. 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 request y un response HTTP 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. Requerimiento GET 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: GET http://www.google.com.ar:80/ HTTP/1.0 Accept: */* Accept-Language: en-us Pragma: no-cache User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322) Host: www.google.com.ar Proxy-Connection: Keep-Alive Cookie: PREF=ID=ca22a5a801390fd9:TM=1130776245:LM=1130776245:S=fW_ Aqui, excepto la primera linea, todos las demás son headers.
57
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Cert

1.1 For each of the HTTP Methods (such as GET, POST, HEAD, and so on) describe the purpose of the method and the technical characteristics of the HTTP Method protocol, list triggers that might cause a Client (usually a Web browser) to use the method; and identify the HttpServlet method that corresponds to the HTTP Method.

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 request y un response HTTP

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. 

Requerimiento GET

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:

GET http://www.google.com.ar:80/ HTTP/1.0Accept: */*Accept-Language: en-usPragma: no-cacheUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)Host: www.google.com.arProxy-Connection: Keep-AliveCookie: PREF=ID=ca22a5a801390fd9:TM=1130776245:LM=1130776245:S=fW_

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 OKCache-Control: privateContent-Type: text/html; charset=UTF-8Server: GWS/2.1Date: Fri, 25 Aug 2006 21:00:00 GMTConnection: Close

<html><head>...etc!!!

Page 2: Cert

**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. 

POST

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.0Accept: 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_inputAccept-Language: en-usContent-Type: application/x-www-form-urlencodedProxy-Connection: Keep-AliveUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)Host: www.w3schools.comContent-length: 330Pragma: no-cacheCookie: 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%22firstname%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.

HEAD

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.

OPTIONS

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

Page 3: Cert

PUT

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.

DELETE

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

TRACE

 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.

Que es lo que provoca esto en el browser ?

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).

Como traduce el web server estos requerimientos en invocaciones?

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.

1.2 Using the HttpServletRequest interface, write code to retrieve HTML form parameters from the request, retrieve HTTP request header information, or retrieve cookies from the request.

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

Page 4: Cert

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:

 java.lang.String getParameter(java.lang.String name)           Returns the value of a request parameter as a String, or null 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:

java.lang.String[] getParameterValues(java.lang.String name)           Returns an array of String objects containing all of the values the given request parameter has, or null 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:

java.util.Map getParameterMap()           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:

java.util.Enumeration getParameterNames()           Returns an Enumeration of String 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:

<form action="/myapp/MiServlet" method="POST">    <input type="file" name="nombre">    <input type="submit" value="POST"></form>

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

 ServletInputStream getInputStream()           Retrieves the body of the request as binary data using a ServletInputStream.

Page 5: Cert

 

java.io.BufferedReadergetReader()           Retrieves the body of the request as character data using a BufferedReader.

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:

java.lang.String getHeader(java.lang.String name)           Returns the value of the specified request header as a String.

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:

java.util.Enumeration getHeaders(java.lang.String name)           Returns all the values of the specified request header as an Enumeration of String 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:

java.util.Enumeration getHeaderNames()           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.

 long getDateHeader(java.lang.String name)           Returns the value of the specified request header as a long value that represents a Date object.

 int getIntHeader(java.lang.String name)           Returns the value of the specified request header as an int.

Obtención de los cookies

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

 Cookie[] getCookies()           Returns an array containing all of the Cookie objects the client sent with this request.

Page 6: Cert

1.3 Using the HttpServletResponse interface, write code to set an HTTP response header, set the content type of the response, acquire a text stream for the response, acquire a binary stream for the response, redirect an HTTP request to another URL, or add cookies to the response.

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

 void addHeader(java.lang.String name, java.lang.String value)           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)

 void setHeader(java.lang.String name, java.lang.String value)           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:

 void addIntHeader(java.lang.String name, int value)           Adds a response header with the given name and integer value.

 void addDateHeader(java.lang.String name, long date)           Adds a response header with the given name and date-value.

 

Para setear el content type, tenemos 2 maneras:

1. Seteando el header que corresponde:

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

2. Utilizando el método setContentType de ServletResponse:

void setContentType(java.lang.String type)           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.

 

Para mandar texto al cliente, utilizamos el seguramente conocido método getWriter() de ServletResponse:

Page 7: Cert

java.io.PrintWriter getWriter()           Returns a PrintWriter 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 cliente.

Para mandar contenido binario al cliente, utilizamos el método getOutputStream() de ServletResponse:

 ServletOutputStream getOutputStream()           Returns a ServletOutputStream 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).

Para redireccionar al cliente, utilizamos el método sendRedirect() de HttpServletResponse:

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:

void sendRedirect(java.lang.String location)           Sends a temporary redirect response to the client using the specified redirect location URL.

Finalmente, para agregar cookies a la respuesta utilizamos el método addCookie de HttpServletResponse:

 void addCookie(Cookie cookie)           Adds the specified cookie to the response.

** Cookie tiene un solo constructor de la forma:

Constructor SummaryCookie(java.lang.String name, java.lang.String value)           Constructs a cookie with a specified name and value.

1.4 Describe the purpose and event sequence of the servlet life cycle: (1) servlet class loading, (2) servlet instantiation, (3) call the init method, (4) call the service method, and (5) call destroy method.

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.

Page 8: Cert

** 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.  

2.1 Construct the file and directory structure of a Web Application that may contain (a) static content, (b) JSP pages, (c) servlet classes, (d) the deployment descriptor, (e) tag libraries, (d) JAR files, and (e) Java class files; and describe how to protect resource files from HTTP access.

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 estar 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 'WEB-INF'. 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:

- /WEB-INF/classes: 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).

- /WEB-INF/lib: 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 directorio 'lib'.

2.2 Describe the purpose and semantics of the deployment descriptor

Page 9: Cert

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. 

2.3 Construct the correct structure of the deployment descriptor

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.

Elemento <servlet>

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>

<servlet-name> - 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)

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

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

<init-param> - 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:

java.lang.String getInitParameter(java.lang.String name)

Returns a String containing the value of the named initialization parameter, or null if the parameter does not exist.

java.util.Enumeration getInitParameterNames() Returns the names of the servlet's initialization parameters as an Enumeration of String objects, or an empty Enumeration if the servlet has no initialization parameters.

<load-on-startup> - 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 - )

Elemento <servlet-mapping>

Page 10: Cert

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

<servlet-mapping>   <servlet-name>MiServlet</servlet-name>   <url-pattern>/miservlet</url-pattern></servlet-mapping>

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 (/).

Otros elementos

<welcome-file-list> - 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:

<welcome-file-list>     <welcome-file>index.html</welcome-file>     <welcome-file>index.jsp</welcome-file></welcome-file-list>

<error-page> - 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.

<error-page>   <error-code>404</error-code>   <location>/MiPaginadeerror.html</location></error-page>

or

<error-page>   <exception-type>javax.servlet.ServletException</exception-type>   <location>/customErrorPage.html</location></error-page>

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

<mime-mapping> <extension>txt</extension> <mime-type>text/plain</mime-type> <mime-mapping>

2.4 Explain the purpose of a WAR file and describe the contents of a WAR file, how one may be constructed.

Page 11: Cert

Los archivos .war (web archive) son un mecanismo provisto para hacer el deployment de la aplicación mas facil. Cuando copiamos un archivo a war al webapps de tomcat, automaticamente tomcat lo descomprime. Un archivo war es gralmente. un archivo .zip, que puede ser visto por winzip. La herramienta provista por Sun para crear el archivo war es jar. Cuando creamos el archivo war usando esta herramienta, se crea un directorio llamado META-INF, que contiene un archivo llamado MANIFEST.MF. El uso más importante de este archivo es especificar jars externos a la aplicación que serán necesitados.

3.1 For the ServletContext initialization parameters: write servlet code to access initialization parameters; and create the deployment descriptor elements for declaring initialization parameters.

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):

<context-param>   <param-name>Nombre</param-name>   <param-value>Jose</param-value></context-param>

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()

3.2 For the fundamental servlet attribute scopes (request, session, and context): write servlet code to add, retrieve, and remove attributes; given a usage scenario, identify the proper scope for an attribute; and identify multi-threading issues associated with each scope.

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:

public void setAttribute (String name,Object value) - para setear un atributo.

public Object getAttribute (String name) - 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")

public Enumeration getAttribute Names() - para obtener una Enumeration de todos los atributos.

Page 12: Cert

public void remove Attribute (String name) - para remover un atributo.

Scopes

request: 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.

session: 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).

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

Multithreading

- 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

3.3 Describe the Web container request processing model; write and configure a filter; create a request or response wrapper; and given a design problem, describe how to apply a filter or a wrapper.

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 Filter, que tiene 3 métodos:

init(FilterConfig config): 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() -.

doFilter(ServletRequest request, ServletResponse response, FilterChain chain): 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.

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

Tags en el deployment descriptor

Page 13: Cert

<filter>   <filter-name></filter-name>   <filter-class></filter-class> </filter>

<filter-mapping>   <filter-name></filter-name>   <url-pattern></url-pattern> o <servlet-name></servlet-name></filter-mapping>

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.

Wrappers

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.

3.4 Describe the Web container life cycle event model for requests, sessions, and web applications;create and configure listener classes for each scope life cycle; create and configure scope attribute listener classes; and given a scenario, identify the proper attribute listener to use.

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

ServletRequestListener - 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().

Page 14: Cert

ServletRequestAttributeListener - 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:

ServletContextListener

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.

ServletContextAttributeListener - 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:

<listener>

   <listener-class></listener-class>

<listener>

** 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. 

Page 15: Cert

3.5 Describe the RequestDispatcher mechanism; write servlet code to create a request dispatcher; write servlet code to forward or include the target resource; and identify and describe the additional request-scoped attributes provided by the container to the target resource.

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 ServletRequest con el método getRequestDispatcher(String path): 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 ServletContext con el método getRequestDispatcher(String path): La diferencia con el anterior es que solamente pueden incluirse paths absolutos.

3. A través del ServletContext con el método getNamedDispatcher(String nombre): 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().

forward() - La sintaxis es la siguiente:

void forward(ServletRequest request, ServletResponse response)           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. Toda la respuesta es enviada desde el nuevo servlet. 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.

javax.servlet.forward.request_uri - corresponde a getRequestURI() en el servlet original

javax.servlet.forward.context_path - corresponde a getContextPath en el servlet original

javax.servlet.forward.servlet_path - corresponde a getServletPath en el servlet original

javax.servlet.forward.path_info - corresponder a getPathInfo en el servlet original

javax.servlet.forward.query_string - corresponde a getQueryString en el servlet original

Include() - La sintaxis es la siguiente:

void include(ServletRequest request, ServletResponse response)           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.

Page 16: Cert

4.1 Write servlet code to store objects into a session object and retrieve objects from a session object.

** 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().

 void setAttribute(java.lang.String name, java.lang.Object value)           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.

java.lang.Object getAttribute(java.lang.String name)           Returns the object bound with the specified name in this session, or null 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!

java.util.Enumeration getAttributeNames()           Returns an Enumeration of String 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().

4.2 Given a scenario describe the APIs used to access the session object, explain when the session object was created, and describe the mechanisms used to destroy the session object, and when it was destroyed.

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á).

Sesiones Distribuidas

Page 17: Cert

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 tener toda la información de las sesiones replicadas. Esto agrega la necesidad que los atributos de las sesiones sean serializables.

Cuando muere una sesión

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.

4.3 Using session listeners, write code to respond to an event when an object is added to a session, and write code to respond to an event when a session object migrates from one VM to another.

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

HttpSessionListener - 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.

HttpSessionAttributeListener

- Esta interface tiene los 3 métodos de los otros scopes, pero el evento que recibe es HttpSessionBindingEvent, que es un evento que sigue el patrón de HttpSessionBindingListener, 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.

HttpSessionBindingListener -  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()

Page 18: Cert

HttpSessionActivationListener - 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.

4.4 Given a scenario, describe which session management mechanism the Web container could employ, how cookies might be used to manage sessions, how URL rewriting might be used to manage sessions, and write servlet code to perform URL rewriting.

Los 2 métodos más comunes para mantener las sesiones son

1. A través de Cookies

2. A través de URL rewriting

Utilizar cookies es el método más usado, cuando el browser las acepta. El web container envia una cookie, con nombre JSESSIONID y un string que representa la sesión. En los subsecuentes requerimientos del cliente, esta cookie será enviado y permitira que del lado del servidor se identifique a esta conversación con la sesión.

A través de URL rewriting es más complicado para el programador, ya que todos los links deberán incluir un 'parametro' en la URL de la siguiente manera:

http://www.myserver.com/catalog/index.html;jsessionid=1234

Afortunadamente existen métodos que facilitan nuestra tarea:

HttpServletResponse.encodeURL(): Este método recibe una URL y devuelva la misma URL, pero con el parametro de sesión incluido. Este método no agrega el parametro de sesión si se estan utilizando cookies, por lo que sería buena práctica de programación incluir todos los links de esta manera.

HttpServletResponse.encodeRedirectURL(): Este método es usado en sendRedirect().

5.1 Based on the servlet specification, compare and contrast the following security mechanisms: (a) authentication, (b) authorization, (c) data integrity, and (d) confidentiality.

authentication: 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.

authorization: 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.

data integrity: 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.

confidentiality: 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.

Page 19: Cert

5.2 In the deployment descriptor, declare a security constraint, a Web resource, the transport guarantee, the login configuration, and a security role.

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

Elemento <security-constraint> - 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:

<security-constraint>

   <web-resource-collection> <!-- Aca se define un nombre para el constraint, los recursos y los métodos http -->

       <description>

       <web-resource-name> <!-- se le da un nombre al constraint -->

       <url-pattern>

       <http-method> <!--el método a restringir (GET, PUT, etc.) -->

   </web-resource-collection>

   <auth-constraint>

          <role-name><!-- El tag vacio indica que se restringe a cualquier cliente, * permite el acceso de todos los roles definidos en el deployment descriptor. Sino, ponemos 1 o más <role-name>, que deben estar definidos mas abajo en <security-role> -->

    <user-data-constraint>

         <transport-garanty> <!-- INTEGRAL declara que se debe asegurar la integridad de los datos  CONFIDENTIAL que se debe asegurar la confidencialidad de los datos -->

</security-constraint>

Elemento <login-config> - 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.

<login-config>

    <auth-method>BASIC</auth-method>

</login-config>

o

<login-config>

    <auth-method>FORM</auth-method>

Page 20: Cert

    <realm-name>Area de autenticación</realm-name>

    <form-login-config>

          <form-login-page>/autenticacion/autenticacion.jsp</form-login-page>

          <form-login-error>/autenticacion/autenticacion.jsp</form-login-error>

</login-config>

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

Elemento <security-role> - 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):

<security-role>

     <role-name></role-name>

</security-role>

Elemento <security-role-ref> - 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:

<security-role-ref>

     <role-name></role-name>

     <role-link></role-link>

</security-role-ref>

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

5.3 Compare and contrast the authentication types (BASIC, DIGEST, FORM, and CLIENT-CERT); describe how the type works; and given a scenario, select an appropriate type.

BASIC (SRV.12.5.1): 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.

DIGEST (SRV.12.5.2): 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)

FORM (SRV.12.5.3): 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

Page 21: Cert

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).

CLIENT-CERT (SRV.12.5.4): en este método se usan certificados digitales. El browser debe tener instalado el certificado para que la comunicación se pueda establecer. 

6.1 Identify, describe, or write the JSP code for the following elements: (a) template text, (b) scripting elements (comments, directives, declarations, scriptlets, and expressions), (c) standard and custom actions, and (d) expression language elements.

6.1 Template text: 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.

6.2 Scripting elements

Scriplets: 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: <% %>

Declarations: 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: <%! %>

Expressions: 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. <%= %>

Comments: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.

6.2 Write JSP code that uses the directives: (a) 'page' (with attributes 'import', 'session', 'contentType', and 'isELIgnored'), (b) 'include', and (c) 'taglib'.

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

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

   atributo import: 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 22: Cert

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

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

   atributo session: 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.

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

   atributo isELIgnored: 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.

(b) include: 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).

(c) taglib: 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).

6.3 Write a JSP Document (XML-based document) that uses the correct syntax.

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 scriplets

Sintaxis JSP Documento JSP

Scriplets <%..%> <jsp:scriplet>...</jsp:scriplet>

Expresiones <%=..%> <jsp:expresion>...</jsp:expresion>

Declaraciones <%!..%> <jsp:declaration>...</jsp:declaration>

Directivas

page <@ page attr="value"%><jsp:directive.page> attr="value"</jsp:directive.page>

include <@ include file="URL"%><jsp:directive.include> file="URL" </jsp:directive.include>

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

xmlns:jsp="value"

Comentarios

comentario JSP <%- -%> <!- -%>

comentario HTML

<!- -%> &lt;!- -&gt;

Page 23: Cert

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.     

6.4 Describe the purpose and event sequence of the JSP page life cycle: (1) JSP page translation, (2) JSP page compilation, (3) load class, (4) create instance, (5) call the jspInit method, (6) call the _jspService method, and (7) call the jspDestroy method.

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 permiten 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.

Page 24: Cert

(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.

6.5 Given a design goal, write JSP code using the appropriate implicit objects: (a) request, (b) response, (c) out, (d) session, (e) config, (f) application, (g) page, (h) pageContext, and (i) exception.

(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 inmediatamente.

(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" %>.

6.7 Given a specific design goal for including a JSP segment in another page, write the JSP code that uses the most appropriate inclusion mechanism (the include directive or the jsp:include standard action).

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).

7.1 Given a scenario, write EL code that accesses the following implicit variables including pageScope, requestScope, sessionScope, and applicationScope, param and paramValues, header and headerValues, cookie, initParam and pageContext.

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 ${ .. }

Page 25: Cert

El objetivo 7.1 del exámen aborda las diferentes variables implicitas de EL. Las 4 primeras (pageScope, requestScope, sessionScope y applicationScope). 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.

param y paramValues 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.

header y headerValues sigue el mismo patrón.

cookie retorna un map de cookies

initParam un map de parámetros del servlet.

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

7.2 Given a scenario, write EL code that uses the following operators: property access (the . operator), collection access (the [] operator).

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)

7.3 Given a scenario, write EL code that uses the following operators: aritmetic operators, relational operators, and logical operators.

Operadores aritméticos: (+, -, *, /, %).

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

Page 26: Cert

Operadores lógicos: (> 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.

Operadores lógicos: (&& 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.

7.4 Given a scenario, write EL code that uses a function; write code for an EL function; and configure the EL function in a tag library descriptor.

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

1. Se escribe la clase

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.

2. Se define la función en un Tag Library Descriptor (.tld)

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!).

3. Se proveen detalles de la ubicación del descriptor en web.xml

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>

4. Se referencia el .tld en el archivo jsp.

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

Page 27: Cert

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

 

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

${mitag:aMayu("hola") } 

8.1 Given a design goal, create a code snippet using the following standard actions: jsp:useBean (with attributes: 'id', 'scope', 'type', and 'class'), jsp:getProperty, and jsp:setProperty (with all attribute combinations).

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.

<jsp:useBean id="ejemplo" class="net.scwcd.ejemplo" o type="net.scwcd.interface" scope="page" o "request" o "session" o "context" >

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

- class 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.

- type 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.

- scope define el scope del javabean.

<jsp:setProperty name="ejemplo" property="beleza" value="blabla" o param="nombre_del_param">

Esta acción permite setear una propiedad del javabean. 

- name define el nombre del javabean.

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

- value es el valor a setear. Aquí podemos usar una expresión (<%= %>). Podemos poner param + 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 - property="*" - esto asignará a todas las propiedades (que concuerden) los valores  recibidos en los parametros.

<jsp:getProperty name="ejemplo" property="beleza">

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'.

8.2 Given a design goal, create a code snippet using the following standard actions: jsp:include, jsp:forward, and jsp:param

<jsp:include>

Page 28: Cert

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

<jsp:include page="test.jsp" flush="true|false">  

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)

 

<jsp:forward>

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' />

<jsp:param>

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. 

9.1 For a custom tag library or a library of Tag Files, create the 'taglib' directive for a JSP page.

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=" ... " ]

Page 29: Cert

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 web.xml 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>

Page 30: Cert

         <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 tagdir='/WEB-INF/tags/dir' (los tag files son estudiados con más profundidad en 10.5).

9.2 Given a design goal, create the custom tag structure in a JSP page to support that goal.

La sintaxis de los custom tags es la siguiente:

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

o

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

     body

<prefix:tag />

Por ejemplo:

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

9.3 Given a design goal, use an appropriate JSP Standard Tag Library (JSTL v1.1) tag from the "core" tag library.

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)

Page 31: Cert

La segunda table muestra mas en detalle los Core tags

Soporte de variables

Tag set

Page 32: Cert

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" />

o

<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" />

Tag remove

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

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

Control de flujo

Tag if

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" />

Tag choose, when y otherwise

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>

Page 33: Cert

   <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> 

Tag forEach, forTokens

Este tag nos permite iterar sobre diferentes tipos de Collection. La collection 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, var 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".

Manejo de URLs

Tag import

<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 var/VarReader y scope. VarReader importa el contenido directamente en un reader.

Tag url

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.

Page 34: Cert

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>

Tag redirect

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" /> 

Tag param

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>

Miscelaneos

Tag out

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.

Tag catch

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. 

Page 35: Cert

10.1 Describe the semantics of the "Classic" custom tag event model when each event method (doStartTag, doAfterBody, and doEndTag) is executed, and explain what the return value for each event method means; and write a tag handler class.

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:

Interface Tag (API)

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:

Page 36: Cert

doStartTag() - 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.

doEndTag() - 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:

setPageContext(PageContext) - 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.

setParent(Tag) - 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 provistos en el JSP.

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

Definición del tag en un Tag Library Descriptor

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.

<tag>

   <name></name>

   <tag-class></tag-class>

   <body-content></body-content>

   <attribute>

      <name></name>

      <required></required>

      <rtexprvalue></rtexprvalue>

   </attribute>

Page 37: Cert

</tag> 

name es el nombre del tag

tag-class define el tag handler

body-content determina que contenido puede tener el body del tag:

   empty: no puede tener body

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

   tagdependant: 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.

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

atribute: 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.

 

Interface IteratorTag(API)

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.

Interface BodyTag(API)

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)

Page 38: Cert

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());

 

10.2 Using the PageContext API, write tag handler code to access the JSP implicit variables and access web application attributes.

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()

Page 39: Cert

- 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.

10.3 Given a scenario, write tag handler code to access the parent tag and an arbitrary tag ancestor.

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

Page 40: Cert

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. 

10.4 Describe the semantics of the "Simple" custom tag event model when the event method (doTag) is executed; write a tag handler class; and explain the constraints on the JSP content within the tag.

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 invoke 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.  

10.5 Describe the semantics of the Tag File model; describe the web application structure for tag files; write a tag file; and explain the constraints on the JSP content in the body of the tag.

Page 41: Cert

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á table_test.tag. 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

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

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

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

Estas son las 3 nuevas... Las otras dos son taglib e include (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)

11.1 Given a scenario description with a list of issues, select a pattern that would solve the issues. The list of patterns you must know are: Intercepting Filter, Model-View-Controller, Front Controller, Service Locator, Business Delegate, and Transfer Object.

Page 42: Cert

11.2 Match design patterns with statements describing potential benefits that accrue from the use of the pattern, for any of the following patterns: Intercepting Filter, Model-View-Controller, Front Controller, Service Locator, Business Delegate, and Transfer Object.

Intercepting Filter

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]

Front Controller

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. 

Model-View-Controller

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

Page 43: Cert

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 resultados 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

 

Business Delegate

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.

Page 44: Cert

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 (dentro de la misma JVM) o puede ser un cliente remoto realmente. El pattern se aplica en ambos casos.

Service Locator

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).

Transfer Object

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).