Construir los Componentes del Modelo
Introducción
Muchos documentos de requerimientos usados para construir aplicaciones Web se enfocan en la Vista. Sin embargo, deberíamos asegurarnos que también está claramente definido el procesamiento requerido por cada solicitud enviada desde la perspectiva del Modelo. En general, el desarrollador de componentes del Modelo se enfocará en la creación de clases JavaBeans que soporten todos los requerimientos de funcionalidad. La natural precisión de los beans requeridos por una aplicación particular variará mucho dependiendo de esos requerimientos, pero generalmente pueden clasificarse en varias categorías descritas abajo. Sin embargo, primero es útil una breve revisión del concepto de "ámbito" en relación con los beans y JSP.
Los JavaBeans y el Ámbito
Dentro de una aplicación basada en web, los Javabeans pueden almacenarse en (y ser accedidos desde) varias colecciones de "atributos" diferentes. Cada colección tiene diferentes reglas para el tiempo de vida de esa colección, y la visibilidad de los Beans almacenados en ella. Juntos, las reglas que definen el tiempo de vida y la visiblidad se llama el ámbito de esos beans. La especificación JavaServer Pages (JSP) define las elecciones de ámbito usando los siguientes términos (con el concepto del API Servlet equivalente entre paréntesis):
- page - Beans que son visibles dentro de una sóla página JSP, para el tiempo de vida de la solicitud actual (Variables locales del método service() )
- request - Beans que son visibles dentro de una sóla página JSP, así como EN cualquier página o servlet que esté incluido en esta página, o reenviado por esta página. (Atributos Request).
- session - Beans que son visibles para todas las páginas JSP y los servlets que participan en una sesión de usuario particular, a través de una o más solicitudes. (Atributos Session).
- application - Beans que son visibles para todas las páginas JSP y los servlets que forman parte de una aplicación Web. (Atributos de contexto Servlet).
Es importante recordar que las páginas JSP y los servlets, al igual que las aplicaciones Web comparten los mismos conjuntos de colecciones de beans. Por ejemplo, un Bean almacenado como un atributo request en un servlet como este:
MyCart mycart = new MyCart(...);
request.setAttribute("cart", mycart);
es inmediatamente visible a una página JSP a la que se reenvíe este servlet, usando una etiqueta de acción estándard como esta:
<jsp:useBean id="cart" scope="request"
class="com.mycompany.MyApp.MyCart"/>
Beans ActionForm
Nota: los beans ActionForm están realmente más cercanos a la Vista que al Modelo.
El marco de trabajo Struts generalmente asume que hemos definido un bean ActionForm (es decir, una clase Java que extiende la clase ActionForm) por cada formulario de entrada necesario en nuEstra aplicación. Los beans ActionForm algunas veces son sólo llamados "beans formuLario". Si declaramos dichos beans en nuestro fichero de configuración ActionMapping (ver "Construir los Componentes del Controlador"), el servlet controlador Struts realiza automáticamente los siguientes servicios por nosotros, antes de llamar al método Action apropiado:
- Chequea en la sesión de usuario si hay un ejemplar de un bean de la clase apropiada, bajo la clave apropiada.
- Si no está disponible dicho bean en el ámbio de la sesión, se crea uno nuevo automáticamente y se añade a la sesión de usuario.
- Por cada parámetro de la solicitud cuyo nombre corresponda con el nombre de una propiedad del bean, se llamará al correspondiente método set(). Esto opera de una forma similar a la acción JSP estándard <jsp:setProperty> cuando usamos el comodín asterisco para seleccionar todas las propiedades.
- El bean ActionForm actualizado será pasado al método perform() de la clase Action cuando es llamado, haciendo que esos valores estén disponibles inmediatamente.
Cuando codifiquemos nuestros beans ActionForm, debemos tener en mente los siguientes principios:
- La propia clase ActionForm no requiere que se implemente ningún método específico. Se usa para identificar el rol que esos beans particulares juegan en la arquitectura general. Normalmente, un bean ActionForm sólo tendrá metodos setxxx() y getxxx(), sin lógica de negocio.
- El objeto ActionForm también ofrece un mecanismo de validación estándard. Si sobreescribimos un método "stub", y proporcionamos mensajes de error en el recurso de aplicación estándard, Struts validará automáticamente la entrada del formualrio (usando nuestro método). Ver Validación del Formulario para más detalles. Por supuesto, también podemos ignorar la validación de ActionForm y proporcionar nuestro propio objeto Action.
- Definir una propiedad (asociada con métodos getXxx() y setXxx()) para cada campo que esté presente en el formulario. El nombre del campo y el nombre de la propiedad deben corresponder de acuerdo a las convenciones usuales de los JavaBeans. Por ejemplo, un campo de entrada llamado username hará que se llame al método setUsername().
- Debemos pensar en nuestros beans ActionForm como firewall ente HTTP y el objeto Action. Usamos el método validate para asegurarnos de que están presentes todas las propiedades requeridas, y que contienen valores razonables. Un ActionForm que falla en la validación incluso ni será presentado para el manejo del Action.
- También podríamos situar un ejemplar bean en nuestro formulario, y usar referencias a propieades anidadas. Por ejemplo, podríamos tener un bean "customer" en nuestro Action Form, y luego referirnos a la propiedad "customer.name" en nuestra vista JSP. Esto correspondería con los métodos customer.getName() y customer.setName(string Name) de nuestro bean customer.
- Cuidado: si anidamos ejemplares de beans existentes en nuestro formulario, debemos pensar en las propiedades que exponemos. Cualquier propiedad pública en un ActionForm que acepta un simple valor String puede seleccionarse con un string de consulta. Podría ser muy útil situar dichos beans dentro de una fina "envoltura" que exponga sólo las propiedades requeridas. Esta envoltura también puede proporcionar un filtro para asegurarnos en tiempo de ejecución de que las propiedades no se seleccionan con valores inapropiados.
Deberías haber observado que un "formulario", en el sentido discutido aquí, no corresponde necesariamente con una sóla página JSP en el interface de usuario. Es común en muchas aplicaciones tener un "formulario" (desde la perspectiva del usuario) que se extienda sobre múltiples páginas. Piensa por ejemplo, en un interface de usuario al estilo de los wizard que se utilizan comunmente cuando instalamos nuevas aplicaciones. Struts nos aconseja definir un sólo ActionForm que contenga las propiedades de todos los campos, sin importar que página de campo se está mostrando actualmente. De igual forma, las distintas páginas del mismo formulario deberían ser reenvidas a la misma clase Action. Si seguimos estas sugerencias, los diseñadores de páginas podrán reordenar los campos entre varias páginas, frecuentemente sin requerir que cambiemos la lógica de procesamiento.
Beans de Estado del Sistema
El estado real de un sistema normalmente está representado por un conjunto de una o mas clases JavaBeans, cuyas propiedades definen el estado actual. Un sistema de tarjeta de compra, por ejemplo, incluirá un bean que represente la tarjeta que está siendo mantenida por cada comprador individual, e incluirá (entre otras cosas) un conjunto de ítems que el comprador ha seleccionado. Separadamente, el sistema también incluirá diferentes beans para la información del perfil del usuario (incluyendo su tarjeta de crédito y su dirección de envío), así como el catalogo de ítems disponibles y sus niveles de inventario actuales.
Para sistemas de pequeña escala, o para información de estado que no necesita guardarse durante mucho tiempo, un conjunto de beans de estado del sistema podría contener todos los conocimientos que el sistema tiene sobre esos detalles particulares. O, como es el caso más frecuente, los beans de estado del sistema representarán información que está almacenada permanentemente en alguna base de datos externa (como un objeto CustomerBean que responde a una fila de la tabla CUSTOMERS), y son creados o eliminados de la memoria del servidor cuando se necesita. Los JavaBeans Enterprise de Entidad también se usan para esto en aplicaciones de gran escala.
Beans de Lógica de Negocio
Deberíamos encapsular la lógica funcional de nuestra aplicación como llamadas a métodos en JavaBeans diseñados para este propósito. Estos métodos pueden ser parte de las mismas clases usadas para los beans de estado del sistema, o podrían estar en clases separadas dedicadas a realizar la lógica. En el último caso, normalmente necesitaremos pasarle los beans de estado del sistema para que sean manipulados por estos métodos como argumentos.
Para una reutilización máxima del código, los beans de la lógica del negocio deberían ser diseñados e implementados para que no sepan que están siendo ejecutados en un entorno de aplicación Web. Si nos encontramos que tenemos que importar una clase javax.servlet.* en nuestro bean, estamos ligando ésta lógica de negocio al entorno de una aplicación Web. Debemos considerar reordenar las cosas para que nuestras clases Action (parte del rol del Controlador, según se describe abajo) traduzcan toda la información requerida desde la solicitud HTTP que está siendo procesada en llamadas a métodos setXxx() de propiedades de nuestros beans de lógica de negocio, después de que se pueda hacer una llamada a un método execute(). Dicha clase de lógica de negocio podría reutilizarse en entornos distintos al de la aplicación Web para el que fue construida en un principio.
Dependieno de la complejidad y del ámbito de nuestra aplicación, los beans de lógica de negocio podrían ser JavaBeans ordinarios que interactúan con beans de estado del sistema que son pasados como argumentos, o JavaBeans ordinarios que aceden a una base de datos usando llamadas JDBC. Para grandes aplicaciones, estos beans frecuentemente ofrecerán JavaBeans Enterprise (EJBs) con o sin estado en su lugar.
Acceder a Bases de Datos Relacionales
Struts puede definir las fuentes de datos para una aplicación desde dentro de un fichero de configuración estándard. También se proporciona un simple almacen de conexiones JDBC.
Después de definir la fuente de datos, aquí tenemos un ejemplo de cómo establecer una conexión desde dentro del método perform de la clase Action:
public ActionForward
perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
{
try {
javax.sql.DataSource dataSource =
servlet.findDataSource(null);
java.sql.Connection myConnection =
dataSource.getConnection();
//do what you wish with myConnection
} catch (SQLException sqle) {
getServlet().log("Connection.process", sqle);
} finally {
//enclose this in a finally block to make
//sure the connection is closed
try {
myConnection.close();
} catch (SQLException e) {
getServlet().log("Connection.close", e);
}
}
}
Observa que el almacen de conexiones Struts genérico es un componente opcional. Muchas aplicaciones Struts usan otros almacenes de conexiones para un mejor rendimiento, especialmente con sistemas de producción de alto volumen.