PFC “Gestor de listas de distribución mediante Struts, JavaMail y

Transcripción

PFC “Gestor de listas de distribución mediante Struts, JavaMail y
PFC “Gestor de listas de distribución mediante Struts,
JavaMail y MySQL”
David Cuberes, [email protected]
ETSE-ETIG, septiembre 2004.
Tutor: Dr. Sergio Gómez.
1. OBJETIVOS
6
2. ESPECIFICACIONES
8
2.0 INTRODUCCIÓN
2.1 DESCRIPCIÓN FUNCIONAL
PÁGINA DE INICIO
LISTADO DE MENSAJES DE UNA LISTA DE DISTRIBUCIÓN
LISTADO DE ARCHIVOS DE UNA LISTA DE DISTRIBUCIÓN
MENSAJES
CREACIÓN DE LISTAS
CONSULTA DE LOS DATOS DE LA LISTA:
MODIFICACIÓN DE LOS DATOS DE LA LISTA:
EXPULSIÓN / READMISIÓN USUARIOS
ALTA DE USUARIOS
MODIFICACIÓN USUARIOS:
REGISTRO EN LISTAS
LOGIN
SESIÓN
ACCESO
APLICACIÓN
2.2 ASIGNACIÓN
HARDWARE DEL SERVIDOR
SOFWARE DEL SERVIDOR
HARDWARE Y SOFTWARE CLIENTE
2.3 DIAGRAMA DE CASOS DE USO
2.4 DIAGRAMA DE CLASES DE LOS CASOS DE USO
CDU 1. BAJAR REGULARMENTE CORREO
CDU 2. REENVÍO MENSAJES
CDU 3. INICIAR SESIÓN
CDU 4. CONSULTA DATOS LISTA
CDU 5. ACCESO MENSAJES DE LISTAS PÚBLICAS
CDU 6. ACCESO ARCHIVOS DE LISTAS PÚBLICAS
CDU 7. ALTA USUARIO
CDU 8. IDENTIFICARSE
CDU 9. CREAR LISTA
CDU 10. CONSULTA DATOS USUARIO
CDU 11. MODIFICAR DATOS USUARIO
CDU 12. REGISTRARSE A LISTA
CDU 13. CONSULTA LISTAS REGISTRADO
CDU 14. DESREGISTRARSE DE LISTA
CDU 15. RECIBIR O NO MAILS LISTA POR CORREO
CDU 16. ACCESO MENSAJES DE LISTA PRIVADAS
CDU 17. ACCESO ARCHIVOS DE LISTAS PRIVADAS
CDU 18. ENVIAR MENSAJE DESDE WEB
CDU 19. ENVIAR MENSAJE POR CORREO
CDU 20. CONSULTAR LISTAS CREADAS
CDU 21. MODIFICAR DATOS LISTA
CDU 22. EXPULSAR USUARIO LISTA
2
8
8
8
8
9
9
10
11
11
11
12
12
13
13
13
13
14
14
14
15
15
15
17
19
19
20
20
21
22
23
23
24
25
26
26
27
27
28
28
28
29
29
29
30
30
CDU 23. READMITIR USUARIO LISTA
2.5 RELACIÓN DE CLASES
CLASES FRONTERA
CLASES DE ACCIÓN
CLASES DE CONTROL
CLASES DE ENTIDAD
BEANS DE FORMULARIO
31
31
31
32
32
32
32
3. DISEÑO
33
3.1 RELACIÓN COMPLETA DE LAS CLASES DEL PROYECTO
3.2 INTERFAZ GRÁFICA
3.3 STRUTS
3.4 LÓGICA DE NEGOCIO
DIAGRAMA ESTÁTICO DE CLASES
ATTACHMENT.JAVA
COLASINCRONIZADA.JAVA
COMUNASMTP.JAVA
COMUNPOPREPLIES.JAVA
FILALISTADO.JAVA
GESTIONACCESO.JAVA
GESTIONBANEADOS.JAVA
GESTIONLISTAS.JAVA
GESTIONUSUARIOS.JAVA
LISTADISTRIBUCION.JAVA
LISTADO.JAVA
LISTADOATTACHMENTS.JAVA
LISTADOMAILS.JAVA
MYAPPLICATION.JAVA
MYLINKEDLIST.JAVA
MYLOGIN.JAVA
MYMESSAGE.JAVA
MYSESSION.JAVA
NUEVOMAIL.JAVA
PATTERNSPOOL.JAVA
PATTERNSREPLY.JAVA
THREADPOP.JAVA
THREADREPLIES.JAVA
THREADSMTP.JAVA
3.5 BASE DE DATOS
DIAGRAMA
TIPOS DE DATOS PRESENTES EN LAS TABLAS
TABLAS
SCRIPT DE LA BASE DE DATOS
33
35
38
40
41
42
42
42
43
43
43
44
44
45
46
47
49
49
49
50
50
50
51
52
52
53
53
55
56
57
57
57
58
63
4. DESARROLLO
65
CDU 1. BAJAR REGULARMENTE CORREO
CDU 2. REENVÍO MENSAJES
CDU 3. INICIAR SESIÓN
CDU 4. CONSULTA DATOS LISTA
65
67
68
69
3
CDU 5. ACCESO MENSAJES LISTA PÚBLICA
CDU 6. ACCESO ARCHIVOS DE LISTAS PÚBLICAS
CDU 7. ALTA USUARIO
CDU 8. IDENTIFICARSE
CDU 9. CREAR LISTA
CDU 10. CONSULTA DATOS USUARIO
CDU 11. MODIFICAR DATOS USUARIO
CDU 12. REGISTRARSE EN LISTA
CDU 13. CONSULTA LISTAS REGISTRADO
CDU 14. DESREGISTRARSE EN LISTA
CDU 15. RECIBIR O NO MAILS POR CORREO
CDU 16. ACCESO MENSAJES LISTA PRIVADA
CDU 17. ACCESO ARCHIVOS LISTAS PRIVADA
CDU 18. ENVIAR MENSAJE POR WEB
CDU 19. ENVIAR MENSAJE POR CORREO
CDU 20. CONSULTAR LISTAS CREADAS
CDU 21. MODIFICAR DATOS LISTA
CDU 22. EXPULSAR USUARIO DE LISTA
CDU 23. READMITIR USUARIO A LISTA
71
74
74
75
76
77
78
79
79
80
80
80
80
80
81
82
82
83
84
5. EVALUACIÓN PRUEBAS
85
CDU 1. BAJAR REGULARMENTE CORREO
CDU 2. REENVÍO MENSAJES
CDU 3. INICIAR SESIÓN
CDU 4. CONSULTA DATOS LISTA
CDU 5. ACCESO MENSAJES DE LISTAS PÚBLICAS
CDU 6. ACCESO ARCHIVOS DE LISTAS PÚBLICAS
CDU 7. ALTA USUARIO
CDU 8. IDENTIFICARSE
CDU 9. CREAR LISTA
CDU 10. CONSULTA DATOS USUARIO
CDU 11. MODIFICAR DATOS USUARIO
CDU 12. REGISTRARSE A LISTA
CDU 13. CONSULTA LISTAS REGISTRADO
CDU 14. DESREGISTRARSE DE LISTA
CDU 15. RECIBIR O NO MAILS LISTA POR CORREO
CDU 16. ACCESO MENSAJES DE LISTA PRIVADAS
CDU 17. ACCESO ARCHIVOS DE LISTAS PRIVADAS
CDU 18. ENVIAR MENSAJE DESDE WEB
CDU 19. ENVIAR MENSAJE POR CORREO
CDU 20. CONSULTAR LISTAS CREADAS
CDU 21. MODIFICAR DATOS LISTA
CDU 22. EXPULSAR USUARIO LISTA
CDU 23. READMITIR USUARIO LISTA
85
86
86
87
87
89
89
90
90
91
91
91
92
92
92
92
93
93
93
93
93
94
94
6. CONCLUSIONES
95
7. RECURSOS UTILITZADOS
96
BIBLIOGRAFÍA
96
4
PÁGINAS WEB
SOFTWARE
HARDWARE
96
99
100
8. MANUALES
101
8.1 INSTALACIÓN
8.2 MANUAL DE USUARIO
LOGIN
ALTA USUARIO
MODIFICACIÓN USUARIO DATOS PERSONALES
REGISTRO EN LISTAS
CREACIÓN DE LISTAS
EXPULSIÓN, READMISIÓN DE USUARIOS
LISTA DE MENSAJES
MENSAJE
LISTADO ARCHIVOS
101
103
104
105
106
107
108
112
115
119
122
9. IMPLEMENTACIÓN EN SOPORTE FÍSICO
123
5
1. OBJETIVOS
Desarrollo de una aplicación WEB que gestione listas de distribución asociadas a cuentas de correo
POP mediante Struts, JavaMail y una base de datos MySQL.
Con arreglo a las características esenciales que la mayoría de las listas suelen poseer, se identifican
tres ejes a desarrollar:
•
•
•
listas:
o
creación. Existen sitios web con un número de listas invariable únicamente
modificable por el administrador, y otros en los que a los usuarios registrados se les
permite crear sus propias listas. Nosotros nos decantaremos por esta segunda
posibilidad.
o
mostrar sus propiedades: fecha de creación, moderador, número de mensajes, tema a
discutir, ...
o
tener conocimiento de los usuarios registrados en la misma.
o
diferenciar entre listas públicas, de acceso universal, y listas privadas, restringidas a
usuarios dados de alta en ella.
o
un moderador encargado de llevar el control, con potestad de impedir la entrada a
visitantes no gratos.
usuarios:
o
alta, consulta y modificación de los datos personales de un usuario registrado.
o
decidir las listas a las que uno desea formar parte.
o
posibilidad de crear una nueva lista.
mensajes:
o visualización atendiendo a diversos criterios de búsqueda y de filtrado de un listado de
mensajes, así como la relación entre mensajes pertenecientes a un mismo thread.
o muchas listas no aceptan el envío de archivos. En nuestro caso, sí los aceptamos, y
también un listado es recuperable según varias reglas, como en el anterior punto.
o mecanismo automatizado de recepción de mensajes llegados por correo y reenvío a
quienes lo soliciten.
En el universo del software libre ya disponemos de un número razonable de implementaciones
completas con las que montar listas o foros de discusión, en especial con PHP, y que cuentan con
gran aceptación por parte de internautas y webmasters.
Cabe señalar que no he encontrado ninguna solución en la que se empleara JSP o Struts. De todas
formas, no ha sido mi ánimo cubrir ningún “nicho” en el desarrollo de software, ni mejorar algo ya
existente o aportar una solución innovadora. Encontrar un proyecto con el cual pudiera comprender el
funcionamiento de una aplicación web, aplicando tecnologías muy demandadas como JSP o Struts ha
sido mi principal motivación.
6
De hecho la elaboración del proyecto ha implicado un conocimiento de:
•
correo electrónico: envío y recepción, attachments, tipos MIME, multipart, JavaMail.
•
HTML para la creación de la interfaz gráfica, y de CSS para mantener un estilo coherente.
•
JavaScript: verificación de datos de formulario del lado del cliente y aspecto dinámico de las
páginas.
•
Contenedores de servlets, en especial Tomcat.
•
Bases de datos: JDBC, SQL, concurrencias, y connection pooling.
•
Struts, modelo-vista-controlador.
•
JSP.
•
expresiones regulares con Java y JavaScript para validaciones o búsqueda de patrones en
cadenas.
•
threads: sincronismos, wait/notify.
•
beans.
•
etcétera.
Este proyecto se inició hasta estar bien avanzado empleando el Modelo 1 de JSP. Decidí desestimar
los scriptlets dentro del JSP a favor de la claridad y separación en capas que ofrece Struts. A medida
que crece una aplicación web que se vale de ASP, JSP, o PHP puede llegar a hacerse un tanto confusa e
ingobernable.
7
2. ESPECIFICACIONES
2.0 INTRODUCCIÓN
Detallaremos los requisitos a cumplir en respuesta a qué debe hacer, en qué consiste el proyecto, y
cuáles son a priori los recursos necesarios de hardware y software. Es una fase de recogida y análisis
de información centrada en definir el problema, cuyas observaciones constituirán los cimientos del
posterior diseño, el cual es el encargado de encontrar la solución.
2.1 DESCRIPCIÓN FUNCIONAL
Página de inicio
Entrada en la cual:
•
aparezca el estado del usuario: invitado o registrado. Los invitados únicamente pueden leer
las listas públicas. Los registrados disponen de una serie de ventajas que iremos viendo en las
siguientes funciones.
•
se muestre una fila por cada lista de distribución existente en el sitio web. Deben aparecer
para cada una, el número de mensajes , de usuarios, la fecha del último mensaje o bien su
hora si ha sido recibido durante el mismo día, y si es una lista pública o privada. En la
segunda, el acceso está limitado a los usuarios que se hayan dado de alta en ella. En cada fila
unos enlaces dirigirán al listado de mensajes o a la página de información de la lista.
•
haya enlaces a páginas de registro de usuarios, de identificación para usuarios ya registrados
y de consulta del perfil de un usuario logineado.
Listado de mensajes de una lista de distribución
Por cada mensaje expondremos:
•
indicador de si el mensaje incluye un adjunto.
•
remitente.
•
asunto, con un enlace para leer el mensaje.
•
hora o fecha, según si la llegada se produce el día de la consulta o no.
•
tamaño en bytes.
Los mensajes se ordenan por defecto del último mensaje recibido al primero, mostrándose en
páginas de n filas.
Otras opciones pasan por la visualización del total o de un conjunto de mensajes conforme a:
•
listado normal o relacionado, en la cual conocer mensajes vinculados en una conversación
común, en niveles con arreglo a su orden de precedencia.
8
•
orden por remitente, asunto, fecha o tamaño, ya sea en ascendente o descendente.
•
filtrado de mensajes por:
o
un rango de fechas o de tamaños.
o
palabra contenida en el remitente o en el asunto.
Existirá la posibilidad de redactar nuevos mensajes para los usuarios que además de registrados
pertenezcan a la lista consultada.
Listado de archivos de una lista de distribución
De apariencia similar al anterior, devolverá el total de archivos que han sido adjuntados en los
mensajes, con el siguiente aspecto por fila:
•
nombre del archivo, con un enlace para la descarga desde la misma página.
•
tamaño en bytes.
•
hora o fecha, según si la llegada se produce el día de la consulta o no.
•
remitente del mensaje que adjuntaba el archivo, con enlace para lectura del mensaje.
Los criteris de búsqueda o filtrado posibles:
•
orden por nombre del fichero, remitente, tamaño o fecha en ascedente o descendente.
•
búsqueda de mensajes:
o
por un rango de fechas o tamaños
o
por palabra contenida en el nombre del fichero o en el remitente
Mensajes
Si estamos leyendo un mensaje de la lista debe incorporar la información siguiente:
•
identificador numérico del mensaje único en toda la aplicación, servirá para hacer una
referencia rápida al mismo.
•
remitente.
•
asunto.
•
fecha y hora de creación.
•
tamaño.
•
una línea por adjunto que incluya:
o
nombre.
9
o
tamaño en bytes.
o
botón de descarga.
•
texto del mensaje.
•
enlaces para la navegación entre mensajes, de respuesta del mensaje si estamos registrados en
la lista de distribución, o de vuelta a la página desde donde enlazamos antes (listado de
mensajes, listado de archivos...). La navegación mantendrá los mensajes en el mismo orden
en que aparecían en el listado, y a la vuelta al listado nos posicionará en la página del último
mensaje visualizado.
•
de pertenecer el mensaje a un hilo de conversación, se mostrará al final de su página, todos
los mensajes con los cuales está relacionado, permitiendo el acceso directo a cualquiera de
ellos, la navegación entre todos los mensajes que forman el hilo uno por uno o la visualización
de todos los mensajes en una sola página web.
Si estamos redactando un mensaje nuevo o respondiendo a uno, mostrará:
•
remitente, el nick con el cual nos hemos identificado, introducido automáticamente.
•
destinatario (nombre de la lista más su dirección de correo electrónico), introducido
automáticamente.
•
campo para introducir path del adjunto, si se desea incluir uno.
•
área de texto donde redactar el mensaje. Si el mensaje responde a otro anterior, éste tendrá
cada línea precedida por un “>”.
•
botón de envío y link para volver sin enviar el mensaje comenzado.
No se permitirá adjuntar archivos que superen un tamaño máximo.
Creación de listas
Con anterioridad a la página de entrada de datos para una nueva lista debe haberse verificado que
existe la posibilidad de crearla. En nuestro proyecto cada lista irá asociada una dirección de correo a
la que se liga en el momento de su creación. Podemos tener contratadas con nuestro proveedor de
servicios de Internet un número determinado de direcciones de correo electrónico y llegar a agotarse
todas. En tal caso, avisaremos de la imposibilidad de crear nuevas listas.
Entradas:
• nombre lista que la identifique ante los usuarios.
• identificador creado automáticamente que lo identifique internamente en la aplicación.
• descripción breve que pueda mostrarse en un listado.
• comentario de una mayor extensión al campo anterior, a mostrar en la página de datos de la
lista.
10
• nick del fundador de la lista1.
• fecha de creación.
• email asociado a la lista, que será empleado tanto por la aplicación a la hora de bajar los
mensajes de correo como por los usuarios que deseen participar en la lista por ese medio.
• tipo lista si pública o privada.
De estas entradas, la fecha, el e-mail y el fundador son asignadas automáticamente y no se pueden
cambiar.
Las entradas “nombre lista” y “descripción breve” deben cumplimentarse o bien cancelar el proceso.
Consulta de los datos de la lista:
Muestra todos los datos que se introdujeron a la hora de crear la lista. Esta consulta está permitida
para cualquier usuario, esté o no registrado en la lista o siquiera en la web. Son datos necesariamente
públicos, porque han de permitir al no registrado en dicha lista conocer las propiedades de la misma y
así decidir si darse de alta en ella o no.
También se muestran una lista de los usuarios registrados en esa lista, pues una condición de las listas
es conocer quiénes son los que reciben tus mensajes y poderte dirigir directamente a ellos.
Modificación de los datos de la lista:
El fundador dispone de un permiso extendido respecto al resto de usuarios en lo que concierne a las
listas que haya creado él. Al entrar en la consulta de los datos, podrá también modificar lo que
considere oportuno con excepción de:
•
idLista, identificador de la lista, que permanece oculto y se emplea para relaciones entre
tablas.
•
nick del fundador, y fecha de creación: una lista no tiene más que un fundador y una fecha y
no tiene sentido cambiarlos.
•
e-mail de la lista: si en el futuro se cambia de proveedor, es el administrador de la aplicación
quien ha de encargarse de cambiar las direcciones de correo y no el fundador.
En cuanto a la lista de usuarios registrados, el fundador en su condición inherente de moderador
tiene control sobre quien accede a las listas.
Expulsión / readmisión usuarios
El creador de una lista es libre de impedir la entrada a quien no respete las normas de
comportamiento y educación exigibles en cualquier lugar.
1
En el proyecto hemos simplificado los roles de gestión de listas: el creador también será el moderador.
11
De llegar a ese extremo, deberá cumplimentar en el formulario de expulsión el motivo que le lleva a
tomar tal decisión, el cual se le expondrá al afectado junto con la fecha en que se hizo efectiva la
expulsión.
En el futuro el usuario puede ser readmitido, siempre bajo criterio del mismo fundador.
Cabe indicar que el ámbito de expulsión es la lista misma. Por lo tanto, un usuario sin acceso a una
lista puede seguir entrando en otras en las que esté aceptado.
Alta de usuarios
Entradas:
•
nombre
•
primer apellido
•
segundo apellido
•
e-mail
•
login
•
password
•
otros campos: que nos pueda interesar en nuestra web a efectos estadísticos o comerciales y
que no tendremos en cuenta en este proyecto.
De todos los campos, son imprescindibles el login, el password y el e-mail. Sin cumplimentarlos no
se dará de alta el usuario.
El login es necesario porque es como será conocido tanto por usuarios como por las relaciones que
realice el ordenador a nivel interno. El e-mail al margen que en una lista de correo serviría para
notificaciones o publicidad, es necesario para que pueda recibir las listas por correo, si lo pide.
Modificación usuarios:
Es posible modificar cualquier campo, salvo el de login que lo identifica para siempre2. Si modifica
el correo electrónico, la lista de mensajes le será enviado a la nueva dirección desde el mismo
momento del cambio.
Dentro de este estado, se pueden modificar también otros dos aspectos al margen de los datos
personales como son:
2
•
gestión listas donde estoy registrado.
•
gestión listas de las que soy fundador.
al igual que sucede en cualquier sitio web, donde el login de acceso no se suele poder cambiar.
12
Registro en listas
Los usuarios escogerán las listas a las que desean darse de alta de entre todas las posibles, decidiendo
a su vez si desean recibir los mensajes de la lista por correo electrónico. Esta opción puede activarse
o desactivarse cuando se desee, al igual que el darse de baja de una lista.
Login
Entradas:
•
login.
•
password.
La tarea es identificar al usuario. Desde la página de login podrá también darse de alta el usuario
que no esté registrado en la web. Un usuario no identificado permanece con el estado “invitado”, lo
cual representa que sólo pueden leerse las listas públicas.
El usuario sólo necesita loginearse una vez, y ya queda identificado para todas las ocasiones en que
se requiera conocer la identidad del visitante, como podría ser el acceso a cada lista. Por esta razón,
el “login” y el “acceso” están separados.
Sesión
Mantendrá el login y el email del usuario registrado desde el momento en que se loginee y hasta que
caduque su sesión. En el primer momento de acceso a la página de inicio estos dos atributos estarán
a nulo.
Acceso
Controlará quién entra a cada lista según los permisos del usuario y la característica de la misma.
Casos posibles:
•
•
lista pública:
o
lectura de mensajes para todos los usuarios.
o
escritura de mensajes para los registrados en la lista (salvo expulsados).
o
si un usuario está expulsado se le mostrará una página con la fecha y el motivo de la
expulsión, se le informará que no puede escribir mensajes en la web ni enviar o recibir
por correo, aunque sí puede entrar como invitado3.
lista privada:
o
lectura y escritura de mensajes sólo para usuarios registrados en la lista (salvo
expulsados)
3 Nadie puede evitar que un usuario expulsado de una lista pública entre como invitado (sin loginearse) y lea
los mensajes, pero al menos no interferirá en el desarrollo de la lista.
13
o
un usuario no registrado encontrará una página donde se le informará de la necesidad
de registrarse si quiere entrar en la lista.
o
un usuario expulsado encontrará también una página con fecha y motivo de la
expulsión y tampoco podrá acceder ni vía web ni vía correo electrónico.
Los correos recibidos en el buzón de entrada serán desestimados si el usuario no pertenece a la lista o
bien ha sido expulsado de ella. En estos casos, el remitente recibirá un correo informándole del
motivo po el que su mensaje no ha sido aceptado.
Aplicación
Componente encargado del arranque del sistema y el mantenimiento en memoria de las estructuras
necesarias.
Deberá iniciar las listas de distribución que se encarguen por sí mismas de recoger periódicamente
los mensajes depositados en sus cuentas de correo y de reenviar a todos los usuarios registrados de la
lista que así lo soliciten.
2.2 ASIGNACIÓN
Descripción de componentes hardware y software.
Hardware del servidor 4
Precisaremos de un ordenador con capacidad de albergar una base de datos, un servidor web con
capacidad de procesamiento de JSP y conexión a red de banda ancha.
Para una carga media de listas/mensajes/usuarios será necesario que la RAM sea alta, cuanta más
mejor, por los siguientes motivos:
•
se mantendrán en memoria estructuras para no acceder constantemente a la base de datos.
•
en las ocasiones en que deba recuperarse registros de la base de datos una memoria mayor a la
habitual nos permitiría aumentar el número posible de conexiones a la base de datos y su
caché, reduciendo el tiempo de espera 5.
•
Las aplicaciones java requieren cargar en memoria la Máquina Virtual de Java, que consume
muchos recursos.
Si el sistema operativo es Windows XP, ya de por sí muy exigente, se estima que los requisitos
mínimos serían los de un ordenador de 1 GHz con 512 MB.
estos supuestos son únicamente si la aplicación fuera a explotarse realmente. En nuestro caso, los requisitos
son mucho menores, habida cuenta del número de usuarios y listas que probaremos y que se especificarán en el
apartado de la evaluación de las pruebas.
4
5
no se ha estudiado el tuning de la base de datos en este proyecto.
14
La arquitectura de hardware es indiferente. La aplicación será multiplataforma, por estar escritos en
Java tanto el contenedor de servlets como el proyecto. MySQL también se encuentra disponible en
la mayoría de las arquitecturas existentes.
Sofware del servidor
El sistema operativo puede ser cualquiera de los existentes en el mercado. Por los mismos motivos
expuestos al mencionar la arquitectura.
El servidor requiere Jakarta-Tomcat u otro contenedor de servlets compatible con las mismas
especificaciones, un servidor de bases de datos MySQL, y el JSDK de Java. No basta con el JRE,
puesto que Tomcat requiere llamar al JSDK para compilar los JSP.
Hardware y software cliente
Un navegador cualquiera sin importar ni la plataforma ni el sistema operativo. Si la antigüedad del
ordenador y del software no es superior a los 5 años debería funcionar sin ningún problema.
Incluso un ordenador más antiguo que pueda utilizar una versión reciente de un navegador tampoco
hallaría problemas, ya que el ordenador cliente sólo se emplea para mostrar los resultados.
Navegadores obsoletos podrían tener inconvenientes a la hora de interpretar etiquetas HTML, CSS
o javascript.
El acceso a Internet puede ser la de un módem de 33kbps, ya que se emplearán páginas con
contenidos sencillos, nada pesadas.
2.3 DIAGRAMA DE CASOS DE USO
Síntesis de las tareas realizables por cada actor, tras la lectura de la descripción funcional.
Cada tarea recibirá el nombre de “caso de uso”, de ahora en adelante referidos en ocasiones como
“CDU”, y serán tenidos en cuenta a lo largo de todo el documento como se ve fácilmente en el índice.
15
BAJAR
REGULARMENTE
EL CORREO
APLICACIÓN
REENVÍO MENSAJES
INICIAR SESIÓN
CONSULTAR DATOS
LISTA
ACCEDER MENSAJES
DE LISTAS PÚBLICAS
INVITADO
ACCEDER LISTA
ARCHIVOS DE
LISTAS PÚBLICAS
DARSE DE ALTA
COMO USUARIO
IDENTIFICARSE
CREAR LISTA
REGISTRADO
CONSULTAR DATOS
USUARIO
MODIFICAR DATOS
USUARIO
REGISTRARSE EN
LISTA
Nota: los actores que vienen a continuación “heredan” los casos de uso del actor REGISTRADO,
puesto que estar registrado en lista o ser creador de una implica estar previamente registrado en la
web.
16
CONSULTA LISTAS
ESTOY REGISTRADO
DESREGISTRARSE
EN LISTA
RECIBIR O NO
MAILS LISTA
POR CORREO
ACCESO MENSAJES
LISTA PRIVADA
REG ISTRADO
EN LISTA
ACCESO ARCHIVOS
LISTA PRIVADA
ENVIAR MENSAJE
DESDE WEB
ENVIAR MENSAJE
POR CORREO
CONULTAR
LISTAS CREADAS
MODIFICAR DATOS
LISTA CREADA
CREADOR
LISTA
EXPULSAR
USUARIO DE LISTA
READMITIR USUARIO
DE LISTA
2.4 DIAGRAMA DE CLASES DE LOS CASOS DE USO
Corresponde ahora concretar los CDU, y examinar las clases que forman parte en cada una de ellos
sin interesarnos de momento ni en su intercambio de datos ni cuál es su orden de creación.
Estas clases, llamadas de análisis, son de 3 tipos: frontera, entidad y control.
Las primeras son la interfaz gráfica, las “pantallas” en las que hombre cumplimenta formularios, y
recibe outputs de la máquina. Las clases entidad representan datos persistentes, objetos de negocio
que son creados, actualizados o del que recuperamos información mediante las clases de control.
En un esquema clásico una clase de control hace de intermediario entre entidad y frontera.
Haremos, sin embargo, una subdivisión dentro de las clases de control: las encargadas de la gestión
de las clases de entidad que las acompañarán en la capa de negocio, y unas que designaremos “de
17
acción”,
cuyo cometido será el intercambio entre la capa presentación y la capa de negocio6
permitiéndonos separar ambas.
El motivo perseguido es que la lógica de presentación no tenga acceso directo a la lógica de negocio
ni viceversa7. Por lo tanto, se advertirá que toda clase-acción llamará a una clase de control, recibirá
los resultados y los enviará a la pantalla. Por eso veremos en los diagramas de clases de casos de uso
que de las clases acción suele haber tanto flechas de ida como de vuelta.
Aunque este gráfico no corresponda al apartado de especificaciones se considera oportuno incluirlo
para entender los diagramas de clases siguientes.
CAPA PRESENTACIÓN
INTRODUCCIÓN
DATOS
CAPA NEGOCIO
1: datos
CLASE
ACCIÓN
2: crea
4: resultado
CLASE
GESTIÓN
3:
5.1:
PÁGINA ÉXITO
CLASE
ENTIDAD
5.2:
PÁGINA ERROR
Es una simplificación, pero a cualquier clase frontera le antecede una clase acción. Éste puede invocar
a una o varias clases de gestión. Cada clase de gestión puede acceder a varias clases de entidad. A la
vuelta, según los datos, la clase acción nos dirige a una clase frontera u otra. Normalmente, será una
única página la que devolverá la clase-acción. Nada impide tampoco que la clase frontera que invoca a
la clase acción y la clase frontera que recibe de ésta sean la misma.
Otro tipo de clase empleado, serán los “beans de formulario”, partícipes del intercambio de
información entre las páginas que incluyen formularios y las clases-acción. Pueden considerarse
“clases-entidad”, pues representan la entidad “formulario” pero no forman parte de la lógica de
negocio.
En UML la regla es: a cada caso de uso le corresponde un único diagrama de clases de análisis. Se
observará, sin embargo, que en algunas ocasiones varios casos de uso tienen un mismo diagrama,
por ejemplo los casos del tipo consultar/modificar.
No obstante, no fusionaremos explicaciones en un mismo diagrama, pese a compartirlo. Así
mantenemos el mismo orden que en el diagrama de casos de uso, además que a lo largo de varios
capítulos (diseño, desarrollo, evaluación de pruebas) los casos de uso volverán a ser mencionados, y
conviene una explicación unívoca de cada uno.
Por último en los CDU 1 y 2 al ser tareas sin interfaz gráfica no encontraremos ni clases de frontera ni
clases-acción.
La existencia de la capa de negocio en este proyecto es virtual, ya que los objetos deben su existencia a los
objetos Struts que los crean, y no se encuentran dentro de un contenedor de EJB’s. De todas formas, con Struts
mantenemos una separación entre presentación y lógica.
7 Hay un motivo más: en Struts se emplean estas clases Action.
6
18
CDU 1. Bajar regularmente correo
aplicación
gestión
pop
pop
mensajes
lista
•
Actor: aplicación.
•
Precondición: proceso que arranca cada cierto lapso de tiempo.
•
Postcondición: mensajes nuevos guardados en la base de datos.
•
Pasos:
o
o
o
o
o
•
para cada lista de distribución la aplicación se autentica en su cuenta de correo.
descargamos los mensajes.
los procesamos.
los guardamos en la base de datos
se enlaza con el CDU2 para que los reenvíe.
Notas: entidad “pop” es externo y aparece en el diagrama para hacerlo más claro. Por lo tanto, no
pertenece al proyecto y no se considerará clase de entidad del mismo.
CDU 2. Reenvío mensajes
aplicación
gestión
smtp
smtp
•
Actor: aplicación.
•
Precondición: proceso que arranca llamado por CDU 1 ó CDU 18.
•
Postcondición: mensajes reenviados a los usuarios que lo pidieron.
•
Pasos: para cada mensaje descargado por CDU 1 se observa usuarios registrados a la lista que
desean recibirlos y se les reenvía. Similar con CDU 18.
•
Nota: la clase “smtp” representa un servidor smtp externo, que incorporamos en el diagrama
para hacerlo más claro. Por lo tanto, no pertenece al proyecto y no se considerará clase de entidad
del mismo.
19
CDU 3. Iniciar sesión
introduce en navegador
direccion web
Acción
inicio
Actor
pantalla Inicio
sesion
•
Actor: invitado.
•
Precondición: acceder a página de inicio.
•
Postcondición:
o se crea un objeto sesión.
o página inicio devuelta.
•
Pasos:
o invitado entra en la página de inicio de la web
o “acción inicio” crea objeto “sesión” cuyos atributos login y password estarán a nulo
indicando que es un usuario invitado
o se redirige a página de inicio.
•
Notas: accesos posteriores a la página inicial por parte del mismo usuario no crean nuevos objetos
sesión.
CDU 4. Consulta datos lista
crea
pantalla Inicio
datos lista
Acción
lista
pantalla listas
estoy registrado
gestión
listas
representa
bean form.
lista
pantalla
datos lista
lista
pantalla listas
fundadas usuario
•
Actor: cualquiera.
•
Precondiciones:
o lista distribución a consultar existente.
o indicar desde qué pantalla accedemos para poder volver.
•
Postcondición: página de datos lista devuelta.
•
Pasos:
o accedemos desde cualquiera de las pantallas que se observan.
o ”acción lista” crea objeto “gestión listas” que consulta en la lista y devuelve la información
a objeto acción. Éste cumplimenta el bean formulario que es pasado a la pantalla.
o en pantalla datos lista recibimos datos consulta.
20
•
Notas: las precondiciones se cumplen siempre si accedemos desde alguna de esas páginas.
CDU 5. Acceso mensajes de listas públicas
crea
gestión
acceso
acceso / no acceso
pantalla Inicio
acción
acceso
pantalla listas
estoy registrado
login
acción
listado
mensajes
tipo lista, baneado?
registrado?
sesión
lista
baneados
pantalla acceso
pantalla listas
denegado
fundadas usuario
pantalla
listado mensajes
gestión
listado
mensajes
bean form.
listado mensajes
acción
mensaje
pantalla
mensaje
bean form.
mensaje
acción
extiende
solicita mensaje
mensajes
lista
datos mensaje
pantalla
extiende
•
Actor: cualquiera.
•
Precondiciones:
o acceder desde las pantallas señaladas.
o seguir los pasos.
•
Postcondiciones:
o acceso a los mensajes.
o página de acceso denegado, en la que se avisa que los no registrados en lista o registrados
en alta pero expulsados sólo podrán leer los mensajes.
•
Pasos:
o accedemos desde cualquiera de las pantallas que se observan.
o “acción acceso” crea “gestión acceso” el cual:
• consulta la sesión para saber si el usuario está logineado o no (login nulo=
invitado).
• si logineado, se comprueba que no esté expulsado de la lista.
• lee de lista que su tipo es “lista pública”.
o se ejecutará “acción listado mensajes” si todo está correcto, en caso contrario, recibimos
página con los motivos por los cuales sólo podemos acceder en modo lectura.
o “acción listado mensajes” llama a “gestión listado mensajes” que lee los mensajes de la
lista a devolver en la página de listado de mensajes, según los parámetros recibidos por el
formulario.
o se puede cambiar los valores de los controles del formulario las veces que se considere
necesarias, o dejarlo tal cual está. En cada cambio, se modificará la información en el
bean de formulario de listado mensajes que será leído por “gestión listado mensajes”.
21
o
o
o
•
en la página elegimos el mensaje que deseamos leer.
una vez leído, podemos leer otros volviendo a la lista de mensajes o navegando entre ellos.
Siempre que leemos un mensaje, se ejecuta la “acción mensaje” que a su vez llama a
“gestión listado mensajes”.
desde la página de mensaje, si éste forma parte de un hilo de discusión, mediante la
“página extiende” veremos todos los mensajes relacionados.
Notas: objeto “Lista” contiene las propiedades de la lista, es la “cabecera” en memoria, en
contraposición con “mensajes lista”, que por su potencial número se recupera de disco.
CDU 6. Acceso archivos de listas públicas
pantalla listado
mensajes
acción
listado
archivos
archivos
lista
pantalla listado
archivos
bean form.
listado arch.
gestión
listado
archivos
pantalla
mensaje
descarga
archivo
archivo
(descargado)
archivo
(disco duro servidor)
•
Actor: cualquiera.
•
Precondiciones:
o acceder desde las pantallas señaladas.
o seguir los pasos.
•
Postcondiciones: archivo descargado.
•
Pasos:
o accedemos desde cualquiera de las pantallas que se observan: pantalla listado archivos vía
pantalla listado mensajes (1) ó pantalla mensaje(2).
(1) se devuelve un listado de todos los archivos existentes en una lista, se elige el que se
desea descargar:
•
“acción listado archivos” llama a “gestión listado archivos” que lee los archivos de
la lista a devolver en la página de listado de archivos, según los parámetros
recibidos por el formulario.
•
se puede cambiar los valores de los controles del formulario las veces que se
considere necesarias, o dejarlo tal cual está. En cada cambio, se modificará la
información en el bean de formulario de listado archivos que será leído por
“gestión listado archivos”.
(2) adjunto de un mensaje.
22
CDU 7. Alta usuario
pantalla inicio
acción login
pantalla login
pantalla
datos usuario
acción
usuario
bean form.
usuario
gestión
usuarios
crea
login,
email
pantalla
login ya existe
representa
usuario
sesión
•
Actor: invitado.
•
Precondiciones:
o acceder desde la pantalla de inicio.
o no haberse logineado y no existir como ese usuario.
•
Postcondiciones:
o usuario nuevo creado.
o login automático.
•
Pasos:
o un usuario que no existe no puede identificarse. Por ello desde la pantalla de login,
permitiremos crear nuevo usuario.
o “acción usuario” recibe un formulario cumplimentado por la página de datos del usuario.
o “gestión usuarios” comprueba que no exista un usuario con el mismo login:
•
•
•
no existe: crea un objeto usuario y actualiza el objeto sesión con el login y email.
Entonces “acción usuario” muestra “pantalla datos usuario” en modo de
modificación.
existe: “acción usuario” recibe el aviso del objeto de gestión y redirige a la página
“pantalla login ya existe”, donde se informa de la incidencia y se ofrece volver a
probar el alta con un login distinto o bien abandonar.
Notas: con los campos login, password y email en blanco o con el campo email con un texto que
no tenga formato de correo electrónico no se aceptará crear un nuevo usuario.
CDU 8. Identificarse
crea
pantalla Inicio
acción
login
pantalla login
bean form.
login
acción
check login
pantalla
login aceptado
23
login/no login
pantalla
login no
aceptado
usuarios
gestión
login
login, password
sesión
•
Actor: invitado8.
•
Precondiciones:
o acceder desde la pantalla de inicio.
o no haberse logineado y no existir como ese usuario.
Postcondiciones: logineado, sesión actualizada
•
•
Pasos:
o introducimos login y password.
o “acción check login” crea un objeto “gestión login” el cual busca en todos los usuarios uno
que tenga dichos login y password, recibidos a través del bean de formulario.
•
•
si existe: actualizamos el objeto sesión con login y password, retornamos a “acción
check login” que nos devolverá la “pantalla de login aceptado”.
si no existe: “acción check login” devolverá “pantalla login no aceptado”.
CDU 9. Crear lista
agregamos a
pantalla listas
fundadas
usuario
pantalla no
se pueden
crear mas listas
acción
crear lista
bean form.
lista
lista
gestión
listas
listas fundadas
usuario
mails
disponibles
sesión
pantalla
datos lista
acción
lista
pantalla
no se pudo
crear lista
•
Actor: registrado.
•
Precondiciones: acceder desde la pantalla indicada.
•
Postcondiciones: nueva lista creada o bien aviso si no fue posible.
•
Pasos:
o clicamos en el enlace “nueva lista” de la “pantalla listas fundadas usuario”.
En la práctica, tanto en el caso de uso anterior “alta usuario” como en “identificarse” permitiré que el actor
sea cualquiera, debido a que restaría fluidez en la defensa del proyecto iniciar y detener la aplicación cada vez
que nos logineamos o si debemos crear algunos usuarios.
8
De seguir estos dos casos de uso al pie de la letra, desde la página de inicio el enlace a la página “login” no
debería aparecer si ya estamos logineados, con lo cual sería imposible volver a identificarse o crear un usuario
nuevo. Recordemos que las pruebas se realizan sobre una máquina y sesión.
Por lo tanto, podremos crear varios usuarios y loginearnos como varios usuarios desde una misma sesión.
24
o
llamado por “acción crear lista” el objeto “gestión listas” comprueba si hay el recursos
disponible para crear una nueva lista: una cuenta de correo que ligaremos a la misma.
•
•
o
•
existe: entramos en “pantalla datos lista” para rellenar el formulario.
no existe: “pantalla no se pueden crear más listas”
cumplimentado el formulario, lo devolvemos de nuevo a “gestión listas”:
• éxito: tenemos una lista nueva
• fracaso: “pantalla no se pudo crear lista” donde se ofrece volver a intentarlo ó
abandonar el proceso.
Notas: para que el formulario sea aceptado los campos “nombre lista” y “descripción lista” no
pueden estar en blanco.
CDU 10. Consulta datos usuario
pantalla Inicio
acción
usuario
bean form.
usuario
gestión
representa
usuarios
pantalla listas
estoy registrado
pantalla
listas fundadas
usuario
sesión
pantalla
datos
usuario
usuario
•
Actor: registrado.
•
Precondiciones: acceder desde cualquiera de las pantallas indicadas.
•
Postcondiciones: ninguna.
•
Pasos:
o clicando en el enlace de cualquiera de esas páginas accederemos a la “pantalla datos
usuario”.
o “gestión usuarios” lee el login de “sesión” para saber qué usuario debe recuperar.
o la información recibida por “acción usuario” se trasvasa en el bean de formulario para
que sea leída por la pantalla.
25
CDU 11. Modificar datos usuario
pantalla Inicio
bean form.
usuario
pantalla listas
estoy registrado
registros
usuario
representa
gestión
usuarios
email
pantalla
listas fundadas
usuario
pantalla
datos
usuario
acción
usuario
sesión
usuario
•
Actor: registrado.
•
Precondiciones: acceder desde cualquiera de las pantallas indicadas.
•
Postcondiciones: usuario y sesión modificados.
•
Pasos:
o clicando en el enlace de cualquiera de esas páginas accederemos a la “pantalla datos
usuario”.
o efectuamos las modificaciones que consideremos oportuno.
o “gestión usuarios” modifica el usuario y si es necesario cambia el email en “sesión” y en
todos los “registros usuario” para que las listas conozcan la nueva dirección de correo.
•
Notas:
o no se permite modificar el login.
o en este CDU, el bean de formulario sirve tanto para mostrar en la pantalla el estado inicial
y los cambios producidos, como para ser leído por la acción.
CDU 12. Registrarse a lista
representa
pantalla
datos
usuario
pantalla
listas fundadas
usuario
pantalla listas
donde estoy
registrado
acción
listas estoy
registrado
gestión
usuarios
lista
sesión
•
Actor: registrado.
•
Precondiciones: acceder desde cualquiera de las pantallas indicadas.
•
Postcondiciones: registrado a lista.
26
registros usuario
•
Pasos:
o clicando en el enlace de cualquiera de esas páginas accederemos a la “pantalla listas donde
estoy registrado”, que mostrará tanto las listas donde estamos registrados como las listas a
las que podemos registrarnos.
o “sesión” permite saber qué usuario accede a la página.
o nos registramos en la lista con un clic.
o seguimos en la misma pantalla, donde se muestra la actualización.
CDU 13. Consulta listas registrado
pantalla listas
donde estoy
registrado
pantalla usuario
representa
acción
listas estoy
registrado
gestión
usuarios
sesión
lista
registros usuario
•
Actor: registrado en lista.
•
Precondiciones: acceder desde cualquiera de las pantallas indicadas.
•
Postcondiciones: ninguna.
•
Pasos:
o clicando en el enlace de cualquiera de esas páginas accederemos a la “pantalla listas donde
estoy registrado”, que mostrará tanto las listas donde estamos registrados como las listas a
las que podemos registrarnos.
o “sesión” permite saber qué usuario accede a la página.
CDU 14. Desregistrarse de lista
Mismo diagrama que CDU 12.
•
Actor: registrado en lista.
•
Precondiciones: idem CDU 12.
•
Postcondiciones: desregistrado de lista.
•
Pasos: ídem CDU 12 pero desregistrándonos.
27
CDU 15. Recibir o no mails lista por correo
Mismo diagrama que CDU 12.
•
Actor: registrado en lista.
•
Precondiciones: acceder desde cualquiera de las pantallas indicadas.
•
Postcondiciones: recibiremos o no mensajes de la lista por correo electrónico.
•
Pasos:
o clicando en el enlace de cualquiera de esas páginas accederemos a la “pantalla listas donde
estoy registrado”, que mostrará tanto las listas donde estamos registrados como las listas a
las que podemos registrarnos.
o “sesión” permite saber qué usuario accede a la página.
o podemos marcar con un clic si deseamos recibir mensajes o no, de las listas en las que
estemos registrados.
o después de la operación seguimos en la misma página.
CDU 16. Acceso mensajes de lista privadas
Mismo diagrama que CDU 5.
•
Actor: registrado en lista.
•
Precondiciones:
o acceder desde las pantallas señaladas.
o seguir los pasos.
•
Postcondiciones:
o acceso a los mensajes.
o página de acceso denegado, en la que se avisa que no puede leerse ni escribir mensajes sin
estar registrado en la lista o bien si estando registrado en ella hemos sido expulsados.
•
Pasos: los mismos que en el CDU 5.
CDU 17. Acceso archivos de listas privadas
Mismo diagrama que CDU 6.
•
Actor: registrado en lista.
•
Notas: idem CDU 6.
28
CDU 18. Enviar mensaje desde web
pantalla listado
mensajes
acción
nuevo
mensaje
pantalla nuevo
mensaje
bean form.
mensaje
pantalla
mensaje
sesión
pantalla
mensaje no enviado
gestión
nuevo
mensaje
pantalla
mensaje enviado
mensaje
mensajes
lista
gestión
smtp
smtp
•
Actor: registrado en lista.
•
Precondiciones: acceder desde cualquiera de las pantallas indicadas.
•
Postcondiciones: mensaje guardado en la base de datos de la lista.
•
Pasos:
o se puede crear un nuevo mensaje desde “pantalla listado mensajes” o responder a uno
existente en “pantalla mensaje”.
o se envía a “gestión smtp” que ejecutará el CDU 2 “reenvío mensaje”.
o una vez creado el mensaje recibiremos una notificación si el mensaje se ha podido guardar
o no.
•
Notas:
o el campo de “asunto” y de “texto” no pueden estar en blanco.
o la clase “smtp” representa un servidor smtp externo, que incorporamos en el diagrama
para hacerlo más claro. Por lo tanto, no pertenece al proyecto y no se considerará clase de
entidad del mismo.
CDU 19. Enviar mensaje por correo
Es una tarea externa a la aplicación. El usuario envía un mensaje con su cliente de correo que es ajeno
a nuestro sistema. Luego, del mensaje recibido en la cuenta de correo se ocupará el actor
“aplicación” en el caso de uso “bajar regularmente el correo”.
CDU 20. Consultar listas creadas
gestión
usuarios
pantalla usuario
pantalla
listas estoy
registrado
acción listas
fundadas usuario
pantalla
listas
fundadas
usuario
29
sesión
listas fundadas
usuario
•
Actor: fundador lista.
•
Precondiciones: acceder desde cualquiera de las pantallas indicadas.
•
Postcondiciones: ninguna.
•
Pasos: un enlace nos lleva a “pantalla listas fundadas usuario”.
•
Notas: si el usuario no ha creado ninguna lista, aparecerá un aviso escrito en la misma pantalla
de listas fundadas usuario. No se considera un error.
CDU 21. Modificar datos lista
Mismo diagrama que CDU 4.
•
Actor: fundador lista.
•
Notas: idem CDU 4. La diferencia entre CDU 4 y CDU 21 :
o
o
o
CDU 4: el usuario no creó la lista por lo que puede consultar los datos de la lista pero no
modificarlos.
CDU 21: el fundador puede modificar datos.
los objetos y pantallas visitadas en ambos casos son los mismos.
CDU 22. Expulsar usuario lista
pantalla
datos lista
acción
usuarios
registrados
en mi lista
pantalla usuarios
registrados en
bean form.
lista
usuarios reg.
en mi lista
acción expulsar
pantalla usuario
expulsado
bean form.
expulsar
gestión
baneados
gestión
listas
usuarios registros
usuarios
listas
sesión
baneados
•
Actor: fundador lista.
•
Precondiciones: acceder desde la pantalla indicada.
•
Postcondiciones: usuario expulsado.
•
Pasos (desde “pantalla usuarios registrado en lista” en adelante):
o se clica sobre el usuario a expulsar de entre la lista de usuarios registrados.
o “acción expulsar” devuelve un formulario en blanco donde indicar motivo de la expulsión,
en “pantalla usuario expulsado”.
o al reenviar el formulario a la acción, se crea “gestión baneados” que ejecuta la expulsión.
30
o
•
volvemos a la pantalla desde donde se expulsó.
Notas:
o la expulsión es propiamente desde la “pantalla usuarios registrados en lista”. En el
diagrama aparece los objetos requeridos para crear esa pantalla, y desde dónde es llamada.
En el CDU siguiente, no mostraremos estos preliminares.
o en “pantalla usuarios registrados en lista” están presentes los usuarios expulsados y los no
expulsados.
CDU 23. Readmitir usuario lista
pantalla usuarios
registrados en
lista
acción expulsar
sesión
gestión
baneados
baneados
•
Actor: fundador lista.
•
Precondiciones: acceder desde la pantalla indicada.
•
Postcondiciones: usuario readmitido.
•
Pasos:
o se clica sobre el usuario a readmitir.
o “gestión baneados” rehabilita al usuario.
o seguimos en la misma pantalla.
•
Notas: en “pantalla usuarios registrados en lista” están presentes los usuarios expulsados y los no
expulsados.
2.5 RELACIÓN DE CLASES
Con la suma de información de todos los apartados anteriores, estamos en disposición de perfilar las
clases básicas que encontraremos en el proyecto.
La información concentrada aquí servirá de punto de partida para el apartado de diseño.
CLASES FRONTERA
Corresponden a las futuras pantallas y en consecuencia forman parte de la interfaz de usuario.
p_inicio, p_datos lista, p_listado mensajes, p_listado archivos, p_datos usuario, p_login, p_login
ya existe, p_login aceptado, p_login no aceptado, p_listas fundadas usuario, p_nueva lista, p_no se
pueden crear más listas, p_no se pudo crear lista, p_listas estoy registrado, p_usuarios registrados
en lista, p_usuario expulsado,
p_acceso denegado, p_mensaje, p_extiende, p_nuevo mensaje,
p_mensaje enviado ,p_mensaje no enviado.
31
CLASES DE ACCIÓN
Preceden a las páginas, porque invocan objetos de lógica de negocio y en función de resultados envían
a una u otra página (ejemplo: login correcto, login incorrecto).
a_inicio, a_crea lista, a_lista, a_acceso, a_mensaje, a_listado archivos, a_listado mensajes,
a_extiende, a_usuario, a_login, a_check login, a_nuevo mensaje, a_ listas fundadas usuario,
a_listas estoy registrado, a_usuarios registrados lista, a_expulsar.
CLASES DE CONTROL
Las clases de control son los intermediarios entre las clases frontera y las clases entidad.
Suministrarán información en una u otra dirección según el caso.
g_POP, g_SMTP, g_listas, g_acceso, g_listado mensajes,
g_usuarios, g_login, g_nuevo mensaje, g_baneados.
g_listado archivos, descarga archivo,
CLASES DE ENTIDAD
aplicación, usuario (invitado, registrado, registrado en lista, fundador lista), sesión, lista, mensajes
lista, archivos lista, usuarios, baneados, mails disponibles, registros usuario, listas fundadas usuario,
registros usuarios_listas.
BEANS DE FORMULARIO
Empaquetado de información que viaja entre los jsp y las clases-acción. Principalmente sus atributos
son los valores de los controles de un formulario html.
bf_lista, bf_listadoMails, bf_listadoArchivos,
bf_usuarios registrados en mi lista.
bf_mensaje, bf_usuario, bf_login,
32
bf_expulsar,
3. DISEÑO
3.1 RELACIÓN COMPLETA DE LAS CLASES DEL PROYECTO
Enumeramos el total de clases creadas en el proyecto. En su mayoría a partir de las clases de
especificaciones. En los subapartados posteriores se razonarán las decisiones que han llevado a
prescindir de ciertas clases o a crear nuevas.
A los nombres de las clases se les antecede el prefijo “My” cuando puede haber algún equívoco
respecto a clases de otros paquetes.
Clases-frontera [capa presentación]:
p_inicio
p_login
p_login ya existe
p_login aceptado
p_login no aceptado
p_acceso denegado
p_listado mensajes
p_listado archivos
p_extiende
p_mensaje
p_mensaje enviado
p_mensaje no enviado
p_nuevo mensaje
p_no se pueden crear más listas
p_no se pudo crear lista
p_datos usuario
p_listas estoy registrado
p_listas fundadas usuario
p_nueva lista
p_datos lista
p_usuarios registrados en lista
p_usuario expulsado
-------------------------------------------------------------------------------------
index.jsp
login.jsp
loginYaExiste.jsp
bienvenido.jsp
login_error.jsp
acceso.jsp
listadoMails.jsp
listadoAttachments.jsp
extiende.jsp
detalle.jsp
mensajeEnviado.jsp
mensajeNoEnviado.jsp
nuevoMail.jsp
nuevasListasNo.jsp
nuevaListaError.jsp
usuario.jsp
usuario2.jsp
usuario3.jsp
lista.jsp
lista.jsp
lista2.jsp
banear.jsp
indice.jsp
indiceDetalle.jsp
mail.jsp
Clases-acción [Struts]:
a_inicio
a_acceso
a_login
a_check login
a_listado mensajes
a_listado archivos
a_mensaje
a_extiende
a_nuevo mensaje
IndexJspAction.java
AccesoAction.java
EditLoginAction.java
CheckLoginAction.java
ListadoMailsAction.java
ListadoAttachmentsAction.java
DetalleAction.java
ExtiendeAction.java
NuevoMailAction.java
33
a_usuario
a_listas estoy registrado
UsuarioAction.java
Usuario2Action.java
a_ listas fundadas usuario
a_crea lista
a_lista
a_usuarios registrados lista
a_expulsar
Usuario3Action.java
CreaListaAction.java
ListaAction.java
Lista2Action.java
BanearAction.java
Beans de formulario [Struts]:
bf_login
LoginForm.java
bf_expulsar
bf_mensaje
bf_lista
bf_usuarios reg. en mi lista
bf_listadoMails
bf_listadoArchivos
bf_mensaje
bf_usuario
BanearForm.java
DetalleForm.java
ListaForm.java
Lista2Form.java
ListadoMailsForm.java
ListadoMailsForm.java
NuevoMailForm.java
UsuarioForm.java
Clases-control [capa negocio]:
g_POP
g_SMTP
g_listas
g_listado mensajes
g_listado archivos
g_login
g_usuarios
g_baneados
g_acceso
ThreadPop.java
ThreadSmtp.java
GestionListas.java
ListadoMails.java
ListadoAttachments.java
MyLogin.java
GestionUsuarios.java
GestionBaneados.java
GestionAcceso.java
g_nuevoMensaje
descarga archivo
---------------------------------------------------------
NuevoMail.java
9
FileDownload.jsp
Listado.java
PatternsPool.java
---------------------------------------------------------
PatternsReply.java
ThreadReplies.java
Clases-entidad [capa negocio]:
lista distribucion
sesión
mensaje
aplicación
archivo
----------------------------------------------------------------------------
9
ListaDistribucion.java
MySession.java
MyMessage.java
MyApplication.java
Attachment.java
ColaSincronizada.java
ComunASmtp.java
ComunPopReplies.java
FilaListado.java
MiLinkedList.java
Realizaremos la descarga a través de un JSP, que obviamente no es una clase de control.
34
3.2 INTERFAZ GRÁFICA
En un web-site de listas de distribución el visitante, quizás con la intención de leer varios mensajes,
demanda un servicio ágil. Ello implica que el peso de las páginas debe ser mínimo, sin efectos
gráficos o animaciones superfluas que ralenticen el proceso.
Al mismo tiempo, la navegación entre las páginas debe ser intuitiva, o por lo menos de fácil
aprendizaje, y respaldado en todo momento por una “ayuda”.
En la navegación, se ha tenido en cuenta que en toda página se encuentre un enlace a la página de
inicio o la anterior, por lo que desde cualquier lugar la página de inicio es accesible en un click o a lo
sumo dos. Y siempre hay una ayuda on-line disponible.
Enlaces que dirijan a páginas relacionadas entre sí son agrupados en un menú de pestañas (o tabs).
Se han aplicado hojas de estilos CSS en los enlaces, aspecto visitado y activo, en las tablas, en los
encabezados y pies de los listados y en los tabs de ciertas páginas. Un futuro cambio de estilo
comportaría alterar un solo archivo.
Empleo de JavaScript para cambiar el aspecto dinámico de los controles de los formularios,
activándolos o desactivándolos en función de las acciones del usuario y para verificar celdas no vacías
o formatos correctos como por ejemplo no introducir texto si se espera un número o una fecha,
avisando al usuario del error.
Con el uso del marco de trabajo Struts, conseguimos una eficaz separación entre la presentación,
reservada para los JSP, y los objetos de negocio, que representan el motor de la aplicación. Las
páginas incluirán etiquetas Struts, con un formato muy parecido al de las etiquetas HTML
destinados a recuperar datos recibidos directamente de una clase-acción o de forma indirecta a
través de un bean de formulario. Las ventajas son muchas:
•
•
•
•
•
•
liberamos los JSP de molestos scriptlets, porciones de código, que dificultan la lectura y el
mantenimiento.
un cambio en la presentación no implica forzosamente un cambio en la lógica del negocio y
viceversa.
en proyectos grandes, pueden formarse dos equipos: uno de diseñadores de páginas web, y
otro de programadores, sin que el trabajo de unos interfiera en el de los otros.
el borrado accidental de parte de un JSP no echa al traste un proyecto, sólo afecta a ese JSP.
es más fácil ampliar y rediseñar la aplicación web.
a través del archivo struts-config.xml es más fácil de seguir el esquema de la web.
Según este modelo, la única lógica aceptable en un JSP es de presentación, etiquetas que muestran
un elemento HTML ( un encabezado, un enlace ... ) en función de si se han recuperado o no datos.
Las páginas de error son simples, e incluso la misma página JSP que lanza el error podría mostrar el
mensaje. De nuevo , es mucho más útil que se ocupe Struts ya que evitamos introducir lógica en la
página de la que se puede ocupar la clase Action, redirigiéndonos a una u otra página de error.
Internamente, la gestión de “altas, consultas y modificaciones” sobre un mismo elemento se llevan a
cabo por un único JSP, ya que los objetos visuales que se muestran son los mismos. Así un rediseño
implicaría modificar una sola página y no tres.
Han sido tomadas unas medidas elementales de seguridad destinadas a evitar que un intruso entre
en páginas ajenas reescribiendo la dirección de una página junto con parámetros en la barra de URL
del navegador. Es imposible saltar el control de acceso, o ejercer de fundador de una lista sin serlo,
35
entre otras tareas, porque aunque algunos datos se pasen por queryString o post no son suficientes
sin la información contenida en los objetos de negocio.
Diagrama de navegación entre los JSP:
login.jsp
bienvenido.jsp
loginYaExiste.jsp
login_error.jsp
usuario.jsp
lista.jsp
nuevaListaError.jsp
index.jsp
usuario3.jsp
lista2.jsp
usuario2.jsp
acceso.jsp
nuevasListasNo.jsp
banear.jsp
listadoMails.jsp
nuevoMail.jsp
mensajeEnviado.jsp
mensjeNoEnviado.jsp
listadoAttachments.jsp
detalle.jsp
extiende.jsp
fileDownload.jsp
vuelven a detalle.jsp,
o listadoMails.jsp o listadoAttachments.jsp.
Respecto a los JSP que deducimos gracias a las clases-frontera, existen tres nuevas páginas JSP:
•
indice.jsp
o muestra los enlaces anterior, siguiente y tantos enlaces como páginas se divida el
resultado de listadoMails.jsp.
o incluida en listadoMails.jsp dos ocasiones, antes y después del listado de
mensajes.
36
•
•
mail.jsp
o cuerpo de un mensaje.
o incluido una vez en detalle.jsp y en extiende.jsp, que actúa de contenedor de
varios “mail.jsp”
indiceDetalle.jsp
o enlaces para navegar entre mensajes, llamado antes y después de mostrar un
mensaje.
Estas páginas auxiliares evitan repetir código innecesariamente, facilitando así el mantenimiento y la
legibilidad.
En cuanto al aspecto final de la interfaz, véase las capturas de pantalla en el manual de usuario.
37
3.3 STRUTS
El uso de Struts tiene como precio la multitud de clases de acción y beans de formulario adicionales
que han de ser implementadas.
Suele haber una correspondencia entre los nombres de los jsp, y el de las acciones que los preceden.
No coinciden en número, dado que una clase-acción en ocasiones redirige a más de una página en
función de los resultados.
Del mismo modo que las altas, consultas y modificaciones sobre una misma entidad se realizan desde
una sola página JSP, la clase de acción también es única para las tres operaciones.
Los beans de formulario se encuentran detrás de los formularios HTML. La información entre los dos
es bidireccional: de la página al bean y del bean a la página, según la necesidad.
Tanto ListadoMailsAction como ListadoAttachmentsAction emplean el mismo bean puesto que los
dos formularios HTML de sus páginas listadoMails.jsp y listadoAttachments.jsp son casi idénticos.
ListaForm y Lista2Form agrupan información para sus respectivas páginas, lista.jsp y lista2.jsp, pese
a que éstas no incluyen formulario. En este caso, representan una manera compacta de enviar a las
páginas información heterogenea en un solo objeto request en lugar de en varios.
En un esquema clásico de Struts el tratamiento de un formulario HTML se desdobla en dos Action:
edit_Action y save_Action. El primero dirige a la página JSP y el segundo crea un formulario para
recoger los datos a procesar de la página. Así no se crea un bean formulario en edit_Action que no se
vaya a utilizar.
En el CDU “identificarse” se ha procedido de esta forma,
editLoginAction.java y checkLoginAction.java.
con dos Actions
llamados
Sin embargo, en el resto de los CDU optamos por un único action que lleve a cabo todo el proceso. Es
cierto que se crea dos veces el bean de formulario. Pero también es cierto que la primera vez que se
crea, no se encuentra “en blanco” (salvo en los campos que debe editar el usuario, por supuesto) sino
que incorpora información a mostrar en la página.
Dentro de Struts, merece especial atención el connection_pooling.
Accesos repetidos de un modo convencional a una base de datos por parte de varios usuarios
exigirían abrir y cerrar multitud de conexiones. Una conexión a una base de datos consume mucho
tiempo, como mínimo alrededor de un segundo, si la base está en local.
El pool de conexiones se ideó para reducir estos tiempos de espera. Consiste en un objeto encargado
de mantener en memoria una colección de conexiones en lugar de ir creándolas y destruyéndolas.
Por lo tanto el consumo de segundos que supone cada conexión se da tan solo en el arranque de la
aplicación, ya que en el resto de ocasiones devolvemos una referencia, la cual es instántanea. Cuando
un objeto ya no requiere de la conexión, la “devuelve” al pool, permitiendo que el mismo objeto u
otro puedan volverla a utilizar más adelante.
Struts nos proporciona este connection-pool. Nosotros únicamente debemos especificar cuál es la
fuente de datos y rellenar algunos parámetros como el nombre de usuario, el password, el máximo
de conexiones simultáneas, el máximo de conexiones en memoria, etcétera.
A continuación,
mostramos una entrada en el archivo struts-config.xml:
38
<data-source type="org.apache.commons.dbcp.BasicDataSource">
<set-property value="MySQL" property="description" />
<set-propertyvalue="com.mysql.jdbc.Driver"
property="driverClassName" />
<set-propertyvalue="jdbc:mysql://localhost/pfcweb_sistema"
property="url" />
<set-property value="root" property="username" />
<set-property value="" property="password" />
<set-property value="100" property="maxCount" />
<!-- max conexiones en Pool -->
<set-property value="5" property="minCount" />
<!-- min conex. -->
<set-property value="75" property="maxActive" />
<!-- max conex. simultaneas -->
<set-property value="5000" property="maxWait" />
<set-property value="true" property="defaultAutoCommit" />
<!-- auto commit está por defecto a false -->
<set-property value="false" property="defaultReadOnly" />
</data-source>
Los propiedades especificadas de las conexiones son a modo de ejemplo. Según el número de visitas a
la web y la potencia del ordenador se deberían aumentar o disminuir.
Todos los objetos de negocio que requieran de un acceso a una base de datos lo harán con las
conexiones suministradas por los Action. Garantizamos así un uso rápido y eficiente de las
conexiones, y un control centralizado de sus propiedades.
Este es un motivo más por el que MyApplication es creado desde IndexJspAction y no de forma
independiente. Hubiera podido escogerse la inicialización a través de web.xml, creando una entrada
de este tipo:
<servlet>
<servlet-name>miApp</servlet-name>
<servlet-class>pfc_web_struts.MyApplication</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
Después hubiera podido llamarlo desde cualquier Action con:
request.getSession().getServletContext().getAttribute("miApp");
No obstante, al hallarnos fuera de Struts, no tendríamos ocasión de acceder al pool de conexiones.
Debería abrir conexiones por su propia cuenta para todas las cases creadas por él.
Los objetos de negocio, en su mayoría de ámbito “página”, disponen de un método setConexion()
con el cual recibir la conexión, si deben acceder a la base de datos.
MyApplication en lugar de obtener una conexión, obtiene un objeto DataSource, con el cual demandar
las conexiones que necesite para los objetos que crea.
Struts también nos ofrece una clase llamada FileForm que nos permite subir archivos desde el
ordenador local donde el usuario crea el mensaje al servidor donde se encuentra nuestra aplicación.
39
3.4 LÓGICA DE NEGOCIO
De entre las clases-entidad, se ha desestimado su paso a clases del proyecto a todas aquellas que al
no emplearse de forma continuada o debido a su extenso tamaño se recuperan directamente de la
base de datos sin mantenerlas en memoria:
•
usuario (invitado, registrado, registrado en lista, fundador lista)
la diferencia entre los
diversos tipos de usuario, se reduce tan sólo a un atributo. Por lo cual trataríamos con una
clase usuario. Pero a nivel interno sólo empleamos de forma habitual su login y e-mail, que
guardamos en un objeto sesión. Por ello no creamos una clase usuario, ni la mantenemos
entera en memoria. Para el acceso a los datos de un usuario ya tenemos el usuarioForm.
Entre los objetos del negocio no se trabaja con clases usuario, aunque podría crearse en el
futuro si fuera necesario.
•
mensajes lista: es inviable mantener en memoria un objeto por cada lista que contenga la
totalidad o parte de los mensajes de una lista.
•
archivos lista: idem anterior.
•
baneados: mantendremos el login de los usuarios baneados dentro de cada lista.
•
mails disponibles, registros usuario, listas fundadas usuario, registros usuarios_listas: se
emplean ocasionalmente.
Salvo la instancia de MyApplication cuya vida alcanza a la de la aplicación y las de MySession que se
mantienen mientras sus respectivos usuarios esté conectados a la web, y al margen de los objetos
creados por ellos que mantienen la misma duración, el resto de objetos de esta capa son de ámbito
request, esto es, se crean en el momento que una clase Action las solicita para atender una petición
de una JSP y acto seguido se “destruyen”, o mejor dicho, quedan a disposición del Garbage Collector.
40
DIAGRAMA ESTÁTICO DE CLASES
En el diagrama no establecemos la totalidad de dependencias con clases externas por no restar legibilidad al gráfico.
1
MyApplication
java.lang
1
javax.mail
Thread
JAVAMAIL
n
1
NuevoMail
1
1
ListaDistribucion
ThreadPop
guarda
GestionBaneados
1
crea
ThreadReplies
ThreadSmtp
1
MyMesssage
crea
ColaSincronizada
GestionUsuarios
1
1
0..n
GestionAcceso
PatternsPool
Attachment
1
PatternsReply
1
GestionListas
1
Listado
ListadoMails
FilaListado
ListadoAttachments
1
1
1
MyLogin
n
1
MySession
java.util
MyLinkedList
LinkedList
41
ComunPopReplies
ComunASmtp
INTERNET
Paso a detallar las clases participantes por orden alfabético, junto con sus métodos principales y una
síntesis de su funcionalidad:
Attachment.java
Representa las propiedades mínimas necesitadas por un archivo: nombre, directorio y tamaño.
También es el encargado de guardarlo en disco dentro de la carpeta de la lista, si es uploaded por un
usuario.
En caso de haber en el directorio por defecto, especificado en el registro PathAttachments de la tabla
sistema otro archivo de idéntico nombre, se crea una subcarpeta.
Métodos:
•
getters para obtener las propiedades del archivo.
•
public boolean guardaEnDisco(String
is)
nombreLista,java.io.InputStream
ColaSincronizada.java
Implementación de una cola con los métodos indispensables. Participan en ella un productor que
deja objetos y un consumidor que los recoge.
Evita que a un mismo tiempo ambos tomen el mismo objeto. También bloquea al consumidor
cuando no hay más objetos disponibles.
Métodos:
•
•
•
synchronized void add (Object o), encola.
synchronized Object get (), desencola.
int size (), tamaño de la cola.
ComunASmtp.java
En esencia es una cola donde ThreadPop y NuevoMail depositen los mensajes para que ThreadSmtp
los reenvíe en cuanto pueda.
Métodos:
•
•
ColaSincronizada getCola().
Session getSession (), empleado por el marco de trabajo JavaMail: cuando creamos
un mensaje para ser enviado desde ThreadPop o NuevoMail una de las propiedades
solicitadas es la sesión, que son las propiedades de sistema y el tipo de servidor smtp
utilizado, y que toman de este método.
42
ComunPopReplies.java
Se ha reducido a una cola donde ThreadPop envía mensajes a ThreadReplies.
Métodos:
•
ColaSincronizada getCola().
Tanto ComunASmtp como ComunPopReplies son actualmente simples contenedores de una cola. No
obstante, como representan la intermediación entre dos o más clases, y ya en desarrollos pasados
tuvieron más elementos quizás en el futuro podrían repetirse, lo que desaconseja desde las clases
usuarias de ComunASmtp y ComunPopReplies crear una ColaSincronizada directamente.
FilaListado.java
Encargado de crear las filas que aparecen en los listados de mensajes o archivos.
Métodos:
•
•
las propiedades se pasan por el constructor.
contiene varios getters para acceder independientemente a las distintas propiedades de la
fila: si un mensaje tiene adjunto, el nombre del remitente, el tamaño, la fecha, etcétera.
GestionAcceso.java
Control de usuarios sobre el acceso a listados.
Comprueba si está registrado en la lista, de ser ésta privada, o si está baneado, ofrece la fecha y el
motivo de expulsión.
Métodos:
•
public void setConexion(Connection conn), recibe la conexión del Action que lo
ha creado.
•
public void setListaDistribucion(ListaDistribucion ld), lista distribución
sobre la que deseamos comprobar si el usuario tiene acceso.
•
public boolean estaRegistradoEnLista(String login)
•
public boolean estaBaneado(String login)
•
public String getMotivo(), motivo por el cual fue expulsado.
•
public String getFecha(), fecha de la expulsión.
Internamente crea un GestionBaneados para la respuesta de los tres últimos métodos, que son
mostrados en la página de acceso, de ser rechazado.
43
GestionBaneados.java
Expulsiones y readmisiones de usuarios.
Un usuario expulsado no es desregistrado, ya que si es nuevamente readmitido tendría que volver a
introducir los datos de alta. Además, podría interesar guardar sus datos con varios fines estadísticos
y comerciales.
Métodos:
•
public void setConexion(Connection conn), recibe la conexión del Action que lo
ha creado.
•
public void setListaDistribucion(ListaDistribucion ld)
•
public boolean altaBaneado(String miLogin, String login, String
email, GregorianCalendar cl, String motivo), expulsión.
•
public boolean bajaBaneado(String miLogin, String login, String
email), readmisión.
•
public boolean modifBaneado(String miLogin, String login, String
motivo)
•
public String getFecha()
•
public String getMotivo()
Desde la página web no es posible la opción de alta o baja de expulsiones para un no fundador,
porque los enlaces que lo permiten se ocultan. Aun así, un usuario bien informado con aviesas
intenciones podría introducir en la barra de url del navegador:
http://localhost:8080/cuberes/banear.do?login=nuria&idLista=2&accion=alta&return=inde
x.do
Y expulsar al usuario. Por ello, a ciertos métodos restringidos les pasamos un parámetro adicional,
“miLogin”, correspondiente al login guardado en MySession cuando el usuario se identifica, y al que
no tiene acceso. Los métodos contrastarán el login con el del fundador de la lista, que obtenemos
de ListaDistribucion, antes de realizar alguna operación como alta o baja.
En bajaBaneado se requiere el email del expulsado con el fin que ListaDistribucion lo retire de la lista
de direcciones de las que acepta recibir mensajes.
GestionListas.java
Creamos con ella nuevas listas o modificamos existentes. Ofrece los usuarios registrados y los
expulsados de una lista.
Métodos:
•
public void setConexion(Connection conn), recibe la conexión del Action que lo
ha creado.
44
•
public ListaDistribucion getListaDistribucion (int idLista), devuelve
una referencia con la que podemos consultar las propiedades de la lista.
•
public
int
altaLista(String
nombre,
String
descrip,
String
comentario,
String
fundador,
GregorianCalendar
fecha,
boolean
esListaPublica)
o consulta en la tabla emailsDisponibles donde se encuentra toda la información sobre
una cuenta de correo libre que asociaremos a la nueva lista.
o agregamos un nuevo registro en tabla Listas con los datos pasados por parámetro y
otro en tabla registros donde el fundador consta como primer usuario de la lista, y
puede así pasar el control de acceso y enviar mensajes.
o si todo correcto, se guarda la transacción y se crea un objeto ListaDistribucion que
añadimos al hash de MyApplication.
•
public Collection getUsuariosExpulsados(int idLista)
•
public Collection getUsuariosRegistrados(int idLista)
•
public void modifLista(int id, String nombre, String descrip, String
comentario,
boolean esListaPublica)
•
public boolean puedenCrearseMasListas(), en caso de no encontrar una cuenta de
correo libre, devuelve false.
GestionUsuarios.java
Altas, consultas y modificaciones de usuarios, así como conocer las listas en las que se está o no
registrado, y las listas de las que se es fundador.
Métodos:
•
public void setConexion(Connection conn), recibe la conexión del Action que lo
ha creado.
•
public void setMySession(MySession bs), requerido antes de emplear ningún
método: si realizamos una alta debemos actualizar el MySession (login, email), si
modificamos el email personal también. En los demás métodos, se emplea para recuperar el
login, en lugar de recibirlo por parámetro .
•
public setLogin(String login), permite consultar los métodos siguientes para un
usuario que no sea el de la sesión. Por ejemplo un administrador podría consultar las listas
creadas de un usuario.
•
public boolean altaUsuario(String nombre, String apellido1, String
apellido2, String email, String password)
•
public void altaEnLista (int idLista)
•
public void bajaDeLista (int idLista), desregistrarse de una lista.
•
public String [] getDatosUsuario()
45
•
public Collection getListasCreadas(), listas de las que soy fundador.
•
public Collection getListasNoApuntado()
•
public Collection getListasUsuario()
•
public boolean modifUsuario(String nombre, String apellido1, String
apellido2, String email, String password)
•
public void recibirCorreo(int idLista, String opcion), si se desea recibir o
no correo de una lista a la que estamos registrados.
ListaDistribucion.java
Mantenemos información relativa a una lista de distribución que conviene encontrar en memoria
porque es solicitada de manera continua. Sin ir más lejos, desde la misma página de inicio, aparte de
otras páginas.
No se incluyen el conjunto total o parcial de mensajes o archivos porque su número será muy alto.
Sí, en cambio, el nombre de la lista, las direcciones de correo electrónico de los usuarios que desean
enviar o recibir correo externamente a la página, la fecha del último mensaje , la descripción de la
lista, el fundador, entre otros.
Una vez creado, lanza ThreadPop, ComunPopReplies y ThreadReplies. Estos objetos permanecen
por todo el tiempo de vida de la aplicación en memoria junto a ListaDistribucion, ya que su uso
continuo desaconseja crearlos y destruirlos en tiempo de ejecución.
Cada lista de distribución tiene sus propios threads, es más eficiente y lógico que si los dos threads
fueran compartidos por todas las listas. Así cada thread descarga los mensajes de su cuenta y
concurrentemente varios threads pueden estar bajando al mismo tiempo mensajes. Si no, una lista
no actualizaría sus mensajes hasta que no acabara el thread de atender la anterior lista, con lo que se
desaprovecharía el ancho de banda de la red. Si nos preocupa el espacio en memoria, recordemos
que diversas instancias de un thread no significa cargar “entero” ese objeto ese número de veces, sino
que el código se carga una vez, y cada hilo mantiene su estado.
Métodos:
•
constructor recibe la conexión y las propiedades de la lista antes comentadas.
•
getters para obtener las propiedades anteriores.
•
setters para actualizar las propiedades anteriores, y tambien el número de usuarios y de
mensajes.
•
public void addEmailUsuario(String login,String email), agregamos una
dirección de correo a la cual permitiremos enviar o recibir correo.
•
public boolean estaEnEmailsUsuario(String email)
•
public Address [] getAdressesDestinatarios(String from), devuelve en un
vector de Address (JavaMail) los emails de todos los receptores de la lista menos la del
remitente.
46
•
synchronized public boolean guardaEnBD(MyMessage msg), guardamos el
mensaje en la base de datos. Es un método sincronizado porque puede ser llamado por varios
usuarios simultaneamente cuando crean mensajes, incluido el ThreadPop. Centralizamos
pues, la grabación de mensajes, en lugar de hacerlo por separado desde ThreadPop y
NuevoMail.
Listado.java
Listado es una clase abstracta, base de ListadoMails y ListadoAttachments para la creación de
listados conforme a diversos criterios de ordenación y filtrado. Desde ambas clases se pueden
recuperar mensajes, por lo que todos los métodos comunes han sido concentrados aquí.
También muestra los mensajes, que pueden ser consultados desde un listado u otro.
Métodos:
•
public void setConexion(Connection conn), recibe la conexión del Action que lo
ha creado.
•
public int getAnteriorMail(),
getSiguienteMail(),
para navegar entre
mensajes, nos devuelve el mail contiguo al que estamos posicionados actualmente, ó –1 , si
no existe.
•
setters para establecer diversas consultas: por fechas, por un campo, en un determinado
orden, el número de página a visualizar, etcétera.
•
getters para recuperar los valores antes establecidos.
•
public MyMessage [] getTotalMailsHilo( int id),
aquél cuyo id pasamos por parámetro.
•
public FilaListado[] print(), devuelve una lista con los valores que responden a la
consulta realizada tras aplicar los diversos setters. Este método debe ser redefinido en las
subclases.
•
public void setHilo(boolean on),
indicamos si el listado que recorremos
internamente pertenece a un hilo de discusión. El parámetro “on” se pone a true, si desde
dentro de un mensaje mostramos el listado de mensajes relacionados.
•
protected String cadenaSQLWhere(), crea el Where del sql, según los setters.
•
protected String cadenaSQL(int pag, int lim, String where), crea la
sentencia completa sql, con la cadena where creada con el método anterior. Además se le
indica el número de página a listar, y lim se emplea para recibir la página completa o bien el
primer o último elemento de la página. La opción de página completa se emplea con print()
mientras que las otros dos son de uso interno, para conocer el mensaje anterior a uno que sea
primero de una lista, o el siguiente al que sea último.
mensajes relacionados con
Este método debe ser redefinido en las subclases.
•
protected
FilaListado
creaFila(ResultSet
GregorianCalendar hoy), llamado desde print().
47
rs,
Connection
conn,
•
public MyMessage getMail(int id), obtención de un mensaje.
El compilador no me permite crear los métodos print() y cadenaSQL() como abstractos, y como
private no serían visibles por los descendientes. Los declaro protected, aunque a efectos de
visibilidad una clase protegida es visible para todas las clases de un mismo paquete.
Las clases herederas implementan los criterios mínimos que puedan diferenciar el acceso al listado de
mails y al listado de attachments.
Internamente Listado conserva un vector con los id de los mensajes del listado que se muestre por
pantalla. No todos los mensajes, sino los n registros que forman la paginación.
Supongamos que no existiera el vector. Un usuario cuando entra en la página de listado de mensajes
lo hace para consultar mensajes nuevos. Suponemos que un usuario por término medio leerá varios
mensajes de una lista por sesión. Para cada mensaje leído, es necesario conocer el mensaje que le
antecede y el que le sigue, ya que para navegar con los enlaces “anterior” y “siguiente” que se
muestran en la página del mensaje se requieren estos valores.
Sin vector, una solución plausible sería que para cada mensaje consultáramos la base de datos
pidiendo el listado de los n registros de la página, recorriéramos el ResultSet, deteniéndonos en el id
buscado, con la precaución de guardar en cada iteración el id anterior. Entonces al llegar tendríamos
id anterior, id y moviéndonos una posición el id posterior.
Bien. Ello obliga a solicitar un listado de nuevo para cada mensaje:
•
primer mensaje leído: tengo id anterior, id mensaje, id posterior.
•
segundo mensaje leído: id anterior es el id del primer mensaje, pero debo volver a solicitar
un listado de n registros a la base de, ya que el listado no tiene por qué coincidir con la
posición de los registros en la tabla. Deberemos volver a recorrerlo para encontra el id del
segundo mensaje y así el id posterior.
•
igual para el resto de mensajes.
Además de solicitar un conjunto de registros innecesario en cada ocasión, la consulta debería ser con
los parámetros solicitados por el usuario.
Gracias al vector, actualizado sólo cuando el usuario entra en el listado de mensajes o de archivos o
cuando cambia de página para leer otros n registros, mediante un id conocemos el id de los mensajes
contiguos. Y no necesitamos ir reconsultando a la base de datos más que para solicitar el mensaje
actual. Mantenemos un cursor que apunte al id del mail actual, por lo que tampoco recorremos en
busca del id del mensaje, salvo en la primera vez.
La diferencia es recibir un único registro de un mensaje mediante una consulta SQL sencilla tipo
SELECT * FROM mensajes WHERE id=x o bien recibir 30 ó 40 que responderán a una consulta
que implicará un WHERE de varios parámetros y ordenado. En su conjunto, necesitaría más tiempo.
Prevalece asimismo la idea de leer en memoria antes que en disco duro, teniendo en cuenta que serán
muchos los usuarios que se encuentren consultando el correo en la aplicación.
Para que el vector persista en memoria a lo largo de la visita por varios listados paginados o
mensajes, la clase ha de tener un ámbito de sesión, cosa que hacemos guardando el Listado (sea de
mensajes , sea de archivos) en el MySession.
48
ListadoAttachments.java
Descendiente de Listado para listados de archivos.
•
public FilaListado[] print(), redefinición del método de Listado. Mostramos
listado de archivos.
•
protected String cadenaSQL(int pag, int lim, String where), redefinición
del método de Listado.
ListadoMails.java
Descendiente de Listado para listados de mensajes.
Métodos:
característica propia de los listados de
•
public boolean isListaRelacionada(),
mensajes, por lo que se define en esta clase.
•
public void setListaRelacionada(boolean var)
•
public FilaListado[] print(), redefinición del método de Listado. Mostramos
listado de mensajes.
•
protected String cadenaSQL(int pag, int lim, String where), redefinición
del método de Listado.
MyApplication.java
Inicializa la aplicación y mantiene en memoria los objetos que son necesarios constantemente desde
el arranque del sistema.
Al iniciarse:
•
el constructor recibe el DataSource de Struts.
•
lee los valores de inicialización generales a todo el proyecto de la tabla de sistema que se
pasarán por parámetro a los MySession, o a los objetos ListaDistribución: el número de
registros por página que se mostrará en los listados, el tamaño máximo autorizado de un
adjunto, el directorio donde se guardan los adjuntos, y el número de segundos que el
ThreadPop está dormido tras bajar el correo.
•
crea un ThreadSmtp y un ComunASmtp.
•
recupera de la base de datos las propiedades del total de listas de distribución existentes. Para
cada lista se crea un objeto ListaDistribucion que se guarda junto a las demás en un hash
accesible por el idLista.
Métodos:
•
getters para la obtención de los valores de la tabla sistema.
49
getComunASmtp(), acceso a la cola de mensajes salientes hacia
•
public ComunASmtp
ThreadSmtp.
•
public int getNumListas(), total de listas existentes.
•
public Collection
•
public ListaDistribucion getLista(int idLista) , obtención de una lista en
particular.
•
public void addLista(int id,ListaDistribucion ld), añade una nueva lista al
hash.
•
synchronized public Connection creaConexion(), recupera conexiones del
DataSource para los objetos creados por MyApplication que lo necesiten.
getListasExistentes() , contenido del hash.
MyLinkedList.java
Wrapper necesario para acceder al tamaño de la lista enlazada desde Struts. LinkedList dispone de la
propiedad “size()”. Los tags Struts que leen propiedades sólo reconocen métodos que comiencen
por “get”.
Método:
•
public int getSize()
MyLogin.java
Identificación de usuarios.
•
public void setConexion(Connection conn), recibe la conexión del Action que
lo ha creado.
•
public String log_in(String login, String passw)
MyMessage.java
JavaMail cuenta con una clase Message, que es abstracta. Crear una clase descendiente de ella
representa definir métodos que no me interesan. La clase MimeMessage no es apropiada para
trabajar con la base de datos, pues muchos propiedades que utilizo no existen y si representa a un
mensaje POP3 entrante entonces es de sólo lectura. Heredar de MimeMessage representaría crear
una clase cargada de extras que no necesito.
En definitiva, opto por definir mi propia clase de mensaje,
javaMail.Message para enviar o recibir de Internet.
50
para trabajar internamente
y
Métodos:
•
setters y getters para acceso a las propiedades habituales de un mensaje.
•
public LinkedList getAttachments(), lista de adjuntos del mensaje.
•
void addAttachment(Attachment a), añadimos un adjunto.
•
public String getMessage_ID(), identificador en Internet de un mensaje.
•
boolean esHTML(), si el correo entrante es HTML.
•
boolean esReplyPte(), los mensajes entrantes que responden a otro y que deberá ser
tratado por ThreadReplies.
•
String getReferences(), devuelve Message_ID del mensaje al que replica, o nulo.
•
void setReferences(String s)
•
void setMessage_ID(String s)
MySession.java
Ofrece los objetos de listado, el login y email de una sesion/usuario y los mantiene en memoria, pues
requieren de una vida más allá de los ámbitos page o request, al tener que mantenerse a lo largo de
varias páginas.
Tanto ListadoMails como ListadoAttachments responden a unos parámetros que el usuario ha
introducido a través de un formulario y devuelven un listado. Ya hemos hablado de la conveniencia
del vector de id de mensajes.
Otro argumento a favor de mantener en sesión estas clases es que deseamos que el estado de la
consulta, reflejado en los controles del mismo formulario, se mantenga tal como lo dejó el usuario
hasta que él decida cambiar de nuevo las condiciones de búsqueda.
Una posibilidad de mantener intacto el estado sería pasar las propiedades por queryString o por form
entre las páginas JSP. De todas formas, el carro de atributos tendría que moverse no sólo por las
páginas de listados, sino también por todas las que a través de ellas se puede enlazar, como las de
nuevo mensaje, lectura de mensaje, la de extender mensaje, y las que se pudieran crear nuevas con el
tiempo, de modo que al volver a la página la encontráramos igual. Este carro iría agrandándose con
los atributos propios de cada págia visitada, lo cual sería cada vez más confuso.
La clase MySession nace con la intención de agrupar todos los objetos sesión, en lugar de dejarlos
por separado.
Métodos:
•
public void setConexion(Connection conn), recibe la conexión del Action que lo
ha creado.
•
public ListadoAttachments getListadoAttachments(), si existe, devuelve un
objeto ListadoAttachments, si no existe, lo crea.
•
public ListadoMails getListadoMails(), idem anterior.
51
setters y getters para login y email.
•
Los objetos ListadoMails o ListadoAttachments se crean cuando se necesitan, o sea, si entramos
en el listado de mensajes o el de archivos respectivamente. Una vez creados se mantienen hasta que
el usuario cierre o pierda la conexión.
NuevoMail.java
Encargado de guardar un mensaje redactado desde la web de la aplicación, y de completarlo con
todos los datos necesarios para que pueda ser reenviado a los usuarios registrados que deseen recibir
correo.
•
public boolean enviaMail(String login, String emailUser, String
subject,Attachment attach,
String content, String message_ID) ,
internamente crea un mensaje de texto plano de una sola parte, o dos si incluye un adjunto.
Llama a ListadoDistribucion para que guarde el mensaje y para conocer los que han de ser
los destinatarios y lo enviamos a la cola de ThreadSmtp y de ComunPopReplies.
•
public String textoBR (String content), reemplazamos los saltos de carro del
textarea del formulario por etiquetas <BR> para que se visualice correctamente en la web.
•
public String textoReply (String contentMailReplyado), si nuestro mensaje
es respuesta de otro, introducimos signos “>” que precedan cada línea del texto del mensaje
original.
PatternsPool.java
Contiene expresiones regulares explotadas principalmente por el ThreadPop.
En cada mensaje entrante se aplica una serie de patrones de búsqueda con el fin de reconocer
algunas de sus propiedades, y de reemplazar algunos caracteres que no pueden guardarse tal cual en
la base de datos.
Ya que los emplearemos continuamente, nos conviene compilarlos y tenerlos en memoria, en lugar de
crearlos y destruirlos, pese a que son muy simples.
Por ello reunimos todos los patrones compilados en PatternsPool.
contenido o el asunto del mensaje.
La mayoría actúan sobre el
Métodos:
•
String comillasDobles(String str, boolean eliminar), trata comillas dobles
para que puedan ser entendidas por MySQL. Parámetro eliminar a true si deseamos
eliminarlas.
•
boolean esMIMEmultipart(String str), reconocer si un mensaje es multiparte.
•
boolean esMIMEtextPlain(String str) , si es un mensaje de texto simple.
•
boolean esMIMEtext(String str)
•
String retornosCarro(String str), cambia retornos de carro por etiquetas “<BR>”
52
PatternsReply.java
Similar a PatternsPool, pero éste es empleado sólo por ThreadPop, mientras que encontraremos
instancias de PatternsReply en ThreadPop, ThreadReplies y NuevoMail.
Métodos:
•
public boolean esReply(String str), revisa el comienzo del asunto del mensaje
en busca de un “Re”.
•
public int numeroReply(), para Re[n], devuelve n. Si no, devuelve cero.
•
public String quitaPrimerRe(String str), extrae el primer “Re” que encuentra
en la cadena de entrada.
ThreadPop.java
Responsable de bajar los mensajes de correo electrónico de la cuenta periódicamente, procesarlos,
grabarlos en disco y enviarlos a ThreadReplies, para que busque posibles relaciones con otros
mensajes y a ThreadSmtp para el reenvío a usuarios.
Métodos:
•
public ThreadPop (ListaDistribucion listaD, ComunPopReplies comun,
ComunASmtp
comunS,
String
pathBase,
int
maxSizeAttach,
int
segsDuermePop), constructor.
o recibe referencias a las colas de ThreadSmtp y ThreadReplies, el directorio donde
situar los adjuntos, el máximo tamaño aceptable para estos, y los segundos que
permanecerá dormido antes de volver a consultar la cuenta.
o hace las asignaciones correspondientes de los parámetros con las variables del objeto.
o crea un PatternsTool y un PatternsReply.
•
public void run(), método que debe implementar cualquier heredero de la clase Thread.
En un bucle continuo seguimos estos pasos:
o creación de los objetos de JavaMail y conexión a correo.
o para cada mensaje entrante:
comprobamos que el remitente puede enviar mensajes a la lista (si está
registrado y no expulsado). Si no, el mensaje se drena y se pasa al siguiente,
enviando antes un correo de aviso al remitente.
creación de objeto MyMessage.
trasvase de MimeMessage a MyMessage.
tratamos el mensaje para que pueda ser grabado en la base de datos.
encolamos en ComunPopReplies.
creación de nuevo al que trasvasamos información del MimeMessage y
ponemos en campo BCC los destinatarios.
encolamos en ComunSmtp.
se guarda en la base de datos, por el método de ListadoDistribucion también
usado en NuevoMail.
si todo ha sido correcto, se marca el mensaje entrante como borrable de modo
que cuando se cierre la carpeta de JavaMail elimine los mensajes que ya
tenemos guardados. En caso contrario, de ocurrir alguna incidencia, podremos
recuperar el mensaje la próxima vez que el thread descargue de la cuenta.
53
o
o
bajados todos los mensajes se pone a dormir los segundos establecidos en el
parámetro segsDuermePop, antes de volver a iniciar el proceso de nuevo.
si el thread no consigue conectar con la cuenta de correo (cuenta incorrecta, fallo en la
red, ...), duerme durante los segundos indicados por segsDuermePop y vuelve a
intentarlo. Pasados 5 intentos, el thread descansa durante una hora.
•
private Message creaMessageSMTP(Message m, Session session), creamos
mensaje que ThreadSmtp reenviará. No puede ser el mismo mensaje que hemos bajado por
correo, ya que los mensajes entrantes son de sólo lectura. El Message_ID de este nuevo
mensaje será el que guardemos en el campo del mismo nombre del registro de la base de
datos, porque los receptores del mensaje que deseen contestarlo harán referencia a este
identificador y no al del mensaje entrante.
•
private void llenaMyMessage(Message m, MyMessage m2), trasvase de
información de la clase de JavaMail a la clase del proyecto. En su interior llama a los métodos
que vienen a continuación.
•
private boolean mensajeAceptado(Message m), comprueba si el remitente puede
enviar mensajes a la lista.
•
private void trataCaracteresEspeciales (MyMessage
mensaje para que pueda ser guardado en la base de datos.
•
private void trataMultiPart(Part m, MyMessage m2, int nivel, boolean
[] plain), método recursivo que trata las partes de un mensaje.
m2),
preparamos
Los mensajes de correo constan de una o varias partes. Cada parte a su vez puede incluir otras
subpartes.
Un mensaje simple que no incluya más que texto forma una sola parte. Si el mensaje es en
HTML, por regla general, tiene al menos dos partes10: una con el cuerpo del mensaje original
y otra con el mismo contenido en texto sin formato para que pueda ser leído por cualquier
cliente de correo que no reconozca HTML.
Si el mensaje anterior incluye en el interior del contenido además del texto imágenes o
cualquier otro objeto de extensión MIME , cada uno de ellos conformará una parte.
Cada archivo adjuntado es una parte también, y si este archivo es un mensaje, mantendrá las
mismas partes que el mensaje original.
•
private void trataAttachment (MimeBodyPart part, MyMessage msg), recibe
la parte del mensaje que se ha descubierto que es un archivo, y la pasamos a nuestra clase
Attachment que se encarga de grabarla en el disco.
•
private void trataReferences(Message m,MyMessage m2), comprobamos si es
un mensaje respuesta de otro y lo marcamos para que se haga cargo posteriormente
ThreadReplies.
En la cabecera de un mensaje que es contestación de otro se encuentra uno de estos dos
campos: References o In_Reply_To. Nadie puede evitar que exista algún caso aislado de
mensajes que no incluyen ninguno de los dos, y no obstante sean una respuesta. Esto sucede
cuando en lugar de responder un mensaje pulsando el botón adecuado, se crea un mensaje
10 No siempre es así, Yahoo, por poner un ejemplo, envía partes con sólo HTML, si al crear una nueva cuenta
POP3 especificamos que podemos recibir mensajes de este tipo.
54
nuevo al que luego añade un asunto encabezado por un “Re: .. (mensaje al que quiero
responder)”.
Estos campos contienen entradas
mensaje único para todo Internet.
con un formato de Message_ID,
un identificador de
In_Reply_To sólo contiene un registro. En References, en cambio, es posible encontrar
varias entradas, ya que se suele utilizar en hilos de conversación. El listado de referencias no
es fiable, habiendo ocasiones en los que mensajes pertenecientes a una misma discusión,
ordenados por tiempo, algunos incluyen la lista completa de referencias y otros una parcial de
varios o un solo elemento. Con tal de no equivocarnos nos interesaremos pues en la última
entrada.
ThreadReplies.java
El propósito de este thread es descargar de trabajo al ThreadPop. Mientras que el segundo se dedica
de manera exclusiva a bajar correo, el primero puede ir examinando relaciones entre mensajes y
actualizando la tabla de relaciones.
En la actualidad las relaciones se limitan a encontrar hilos de conversación. Sin embargo, podrían
indexarse también mensajes por varios criterios, o realizar algún tipo de búsquedas, algo de lo que no
podría encargarse el ThreadPop porque supondría una pérdida de tiempo.
El desdoble del procesado entre ambos threads, tiene pues sentido en este momento y aun más con
vistas a la escalabilidad.
ThreadReplies permanece a la espera de recibir en ComunPopReplies algún mensaje a examinar
procedente de ThreadPop, permaneciendo activo mientras encuentre mensajes en la cola.
Métodos:
•
public ThreadReplies(ComunPopReplies comun, Connection conn, int
idLista), precompila las consultas SQL utilizadas para consultar las relaciones. Crea un objeto
PatternsReply.
•
public void run(), método que debe implementar cualquier heredero de la clase Thread. En
un bucle continuo, vamos extrayendo mensajes comprobamos su relación y los insertamos
correctamente en la tabla. Los mensajes de los cuales no hayamos podido encontrar el mensaje
referido no se registrarán en la tabla relación, sino que añadiremos su id en la tabla huérfanos.
Internamente accede a un hash donde se mantienen transitoriamente los mensajes de los cuales
no se haya encontrado un padre. Esto sucederá varias veces a lo largo del uso de la aplicación y
no es en absoluto anómalo. En efecto, la descarga de mensajes del buzón de correo ni es
ordenada ni hay modo de ordenarla y es fácil de observar en la base de datos como mensajes más
antiguos pueden tener identificadores recientes, razón por la que los listados se ordenan por
fecha.
En el hash pues irán los hijos que llegaron antes que los padres, y los hijos de estos, con una
estructura del tipo clave es igual a Message_ID del mensaje referenciado y valor de la casilla hash
una lista enlazada de todos los mensajes que tengan el mismo mensaje referenciado.
Será al llegar el padre, que se extraerán el resto de mensajes del hilo, para lo cual deberemos leer
recursivamente el hash.
El último mensaje leído siempre antes de bloquearse a la espera de la siguiente sesión es un
mensaje nulo que introduce expresamente el ThreadPop al acabar la descarga del buzón. Una vez
ThreadReplies, recibe esta señal sabe que han sido bajados todos los mensajes y que puede
55
examinar el hash con la conciencia que si queda algún mensaje colgado y no ha aparecido su
padre ya no aparecerá jamás. Por lo tanto recorre el hash, y archiva en huerfanos los mensajes
que quedaron pendientes.
content,
String
palabra),
veces que
•
private int buscaEnContent(String
aparece la palabra en el contenido.
•
private int estudiaSubjects(MyMessage msg), compara el subject del posible reply
con los subjects de mails en la base de datos a ver si encaja con alguno. Devuelve id del que
deduce que podría ser el mensaje al cual contesta ó 0, de no encontrar ninguno.
•
private int IDdelReplied(String references), devuelve id del mensaje referenciado o
-1 si no lo encuentra.
•
private boolean guardaEnBD(int reply, int refiereA), guarda mensaje en la tabla
de relaciones.
•
private boolean guardaEnBD (MyMessage msg),
no son reply.
igual al anterior, para mensajes que
ThreadSmtp.java
Reenvía los mensajes creados o recibidos desde la web. Al contrario que ThreadPop o ThreadReplies,
en los que cada lista de distribución tienen los suyos, éste es único para toda la aplicación.
Métodos:
•
public ThreadSmtp(ComunASmtp comun, boolean autenticacion, String
username,String password, String smtphost) , constructor. Recibe referencia a la
cola por la que recibe los mensajes a enviar y los parámetros de conexión. En autenticacion se
indica si el servidor de correo saliente requiere de login y password. Si está a false los valores de
dichas variables no se tienen en cuenta.
•
public void run(), método que implementa al ser descendiente de la clase Thread. Bucle
continuo: al recibir un mensaje, se debloquea conecta al servidor de Smtp y lo envía. Sigue
entonces conectado enviando mensajes mientras encuentre la cola llena. Cuando esté próximo a
bloquearse (observa si número de mensajes es uno o más) envía el último mensaje y cierra la
sesión con el servidor Smtp.
56
3.5 BASE DE DATOS
Diagrama
listas
id,
nombre,
email,
host,
login,
password,
comentario,
registro,
fecha,
founder,
descripcion,
attachments
mails
int(11)
varchar(75)
varchar(75)
varchar(75)
varchar(25)
varchar(75)
text
enum("si","no")
date
varchar(75)
varchar(100)
id ,
xfrom,
email,
n subject,
content,
idLista message_ID,
time_,
size,
idLista,
1
id
int(11)
varchar(75)
varchar(75)
varchar(75)
text
varchar(75)
datetime
int(11)
int(11)
1
id
1..n
idLista
id
xfrom
id
idLista
0..n
idLista
baneados
nombre, varchar(25)
valorInt, int(11)
valorStr, varchar(75)
1
relacion
id id,
int(11)
ordinalThread, smallint(6)
nivel,
smallint(6)
timeOrigen,
datetime
0..1
login,
varchar(25)
idLista,
int(11)
recibeCorreo, enum("si","no") 0..n
login,
varchar(25)
idLista, int(11)
login
fecha, date
n
motivo, text
sistema
1
n
registros
int (11)
int(11)
varchar(5)
varchar(75)
int(11)
1
1
1
idMail,
idAttach,
0..n path,
nombre,
idMail tamanyo,
login
huerfanos
id,
int(11)
1
login
users
1
login,
login nombre,
1 apellido1,
apellido2,
email,
password,
mailsdisponibles
id,
email,
host,
login,
password,
varchar(25)
varchar(75)
varchar(75)
varchar(75)
varchar(75)
varchar(25)
int(11)
varchar(75)
varchar(75)
varchar(75)
varchar(75)
Tipos de datos presentes en las tablas
•
date : fecha.
•
enum (“si”, “no”) : campo enumerativo que recuperamos desde JDBC como si fuera una cadena.
Equivale a un booleano, pues en la versión de MySQL empleada no existe este tipo de campo. Sus
desarrolladores prevén, empero, incorporarlo en el futuro.
•
int(11) : el tamaño de entero establecido por defecto en MySQL para los campos clave numéricos.
•
smallint(6): cuando no se alcanzarán valores altos.
•
text: en campos que desconocemos el tamaño total, pero que suponemos puede ser extenso.
•
datetime: campo de tipo “timestamp”, esto es, fecha más hora. Mientras que de algunos
registros nos es suficiente con saber su día de creación, y por ello empleamos un campo “date”, en
el caso de los mails nos interesa una precisión mayor.
57
Un campo datetime resulta más cómodo y eficaz en una tabla que el mantener dos campos uno
tipo date y otro tipo time. Es más rápido al indexar , buscar, o bien incluso al recorrer un
ResultSet para comparar fechas.
•
varchar(n): cadena de longitud variable de tamaño máximo n.
Tablas
attachments
Archivos adjuntos. En el campo “path” se indica la subcarpeta donde físicamente se halla el archivo
en el servidor en el caso que ya exista en la carpeta raíz uno de idéntico nombre.
baneados
Expulsiones realizadas. Como el número ha de ser muy bajo, de incorporar estos campos a la tabla
“users” estarían en más del 95% de los casos vacíos, razón por la cual se mantienen en una tabla
aparte.
listas
Cabeceras de las listas de distribución. Propiedades generales y valores necesarios para conectar con
la cuenta de correo electrónico asociada.
•
id: identificador de la lista usado internamente por el proyecto.
•
nombre: nombre de la misma.
•
email, host, login, password: relativos a la cuenta de correo.
•
descripción: breve descripción de la lista.
•
comentario: descripción tan extensa como se quiera.
•
fecha: día, mes y año de creación de la lista.
•
founder: fundador.
•
registro: si requiere estar registrado para acceder a la lista.
mails
Mensajes de las listas.
•
id: identificador de mensaje.
•
xfrom: remitente. La equis evita que MySQL se confunda en las sentencias con la palabra
reservada, si bien aceptaría la forma `from`, entre acentos abiertos.
58
•
email: dirección de correo del remitente11.
•
subject, content, fecha, tiempo: propiedades típicas de un mensaje.
•
message_ID: identificador único de un mensaje en Internet. Debe guardarse porque futuros
mensajes que sean respuesta harán referencia a él. No obstante, se prefiere “id” como clave
primaria porque un índice numérico es más eficiente en inserciones y consultas que uno
alfanumérico.
•
idLista: identificador de lista a la que pertenece.
•
time_ : momento de envío del mensaje en nuestra hora, +2.00 respecto hora universal. Aparte
de información para el usuario, nos permite ordenar los mensajes, ya que id, es útil para
identificar un mensaje en sí, pero no para ordenar ya los mensajes obtenidos del buzón de entrada
llegan parcialmente desordenados.
mails disponibles
Conjunto de direcciones de correo libres, preparadas para asignar a listas de correo nuevas. Cuando
se crea una, se elimina el registro tomado y la información pasa a la lista.
Otra posibilidad sería crear un campo idLista en esta tabla, de manera que en las direcciones libres
estaría a NULL y en los otros casos se encontraría vinculado con la tabla “listas”.
relación
Relaciones entre mensajes.
•
•
•
•
id: identificador del mensaje.
timeOrigen: identificamos conjunto de mensajes de un mismo hilo de conversación.
ordinalThread : posición dentro del hilo de un mensaje.
nivel: posición ocupada en la jerarquía de hilo.
Una primera elección en la que se pensó para conservar las dependencias entre mensajes constaba de
dos campos, uno con el id del mensaje y otro con el id del mensaje al que referenciaba. Se
comprobó, sin embargo, que para obtener los listados eran necesarios algoritmos con costes de
desarrollo y temporales altos.
Por ejemplo, para establecer las relaciones de un mensaje determinado, se requiere saltar entre los
registros de la base de datos, con una lectura a la misma por registro.
Queremos conservar el mensaje tal como llegó. Un usuario no puede cambiar su login, pero sí su email. Por
lo tanto, un cambio de dirección de correo-e de un usuario haría que todos los mensajes enviados con
anterioridad cambiarían también la dirección, si escogiéramos eliminar este campo “email” y leer de la tabla
“users”.
11
59
El registro con id 20, refiere a 12. Ahora debo leer el registro con id 12 que me lleva al 10. Pero esto
no sería suficiente, porque los registros relacionados son 10, 11, 12, 17, 20 y 19. Así, al llegar al
registro con id 12 debo buscar si hay otros hijos aparte del 20, otra lectura a la base de datos . Igual
con 10, que nos devolvería 11 y 19 . Aparte del abuso de accesos a la base de datos, luego habría que
ordenar los resultados para mostrarlos tal como se encuentran en la ilustración.
Esto es tan solo referido a las relaciones de un mensaje. No olvidemos que también deseamos
mostrar todos los mensajes relacionados y en orden. Además, tiene que ser fácilmente paginable,
de modo que ir a la página n de un listado no represente tener que recalcular todas las relaciones
anteriores. Ejemplo, si deseo ir a la última página, y el primer registro de ella tiene id 453, primero
he de haber reconstruido la lista de relaciones entera y luego fraccionar en páginas para saber que es
ese registro.
Luego la primera elección, es decididamente fallida e ineficiente.
Es preferible, una o dos lecturas, en lugar de varias, y recibir un cursor con todos mensajes, y no de
uno en uno.
El método escogido se fundamenta ante todo en tener el listado en la tabla tal como se va a
recuperar. Así pasar de una página de n registros a otra no contigua es inmediato.
Con el campo nivel podremos saber el nivel de un mensaje sin necesidad de recorrer los mensajes
anteriores en su hilo. Un mensaje que no responde a ningún otro será de nivel uno. Una respuesta a
ese mensaje tendrá nivel dos. Respuesta a este mensaje estará en un nivel tres. Y así sucesivamente.
El ThreadReplies irá insertando los mensajes a medida que los recibe de la cola. En más de una
ocasión, encontrará un mensaje que va “en medio” de otros dos. Sirva de ejemplo tras colocados
mensaje 21, mensaje 22 y unos cuantos más , todos de nivel uno aparece mensaje 49 que es
respuesta de mensaje 21 y debe ir entre los dos. No podemos partir la tabla en dos. Aparte que nos
obligaría a arrastrar los mensajes de 22 en adelante hacia nuevas posiciones.
Necesitamos, pues, una forma en que sin alterar las posiciones físicas, se mantenga el orden, o sea,
guardar un orden lógico.
Un orden a nivel global sería muy costoso. Imaginemos un campo llamado posLogica y que
renumeráramos a partir de un registro determinado cada vez que apareciera uno nuevo que vaya
antes que él, las inserciones se ralentizarían.
Sí, en cambio, podemos ordenar los mensajes de un hilo. Un orden parcial frente a un orden total. Es
cierto que se presenta el mismo problema que antes, pero a un nivel mucho menor. Es decir, un
hilo compuesto por mensajes en orden 1,2,3,4,5 al aparecer mensaje posterior a insertar entre 2 y
3 deberemos renumerar el orden, corriendo un número el orden a partir del antiguo 3. Contamos
con la ventaja que los hilos de conversación son prácticamente siempre de pocos elementos. Y no es
lo mismo ordenar diez elementos que mil.
Dispondremos de dos campos: timeOrigen y ordinalThread, donde el segundo realizará el orden
parcial. No confundir los campos nivel y ordinalThread. Se comprenderá fácilmente que entre varios
mensajes de un mismo nivel hay un orden entre ellos según la fecha de llegada.
El campo ordinalThread es necesario. Porque SELECT con un ORDER BY timeOrigen, nivel, id en
este orden de parámetros o en cualquier otro no funcionará. Comprobado.
Mediante timeOrigen nos aseguramos el orden entre los diferentes hilos. Anteriormente se estudió un
campo similar que identificaba todos los mensajes de un mismo hilo con el id del primer mensaje del
hijo. Sin embargo, dos situaciones hacían inútil esta posibilidad. La primera es que no podemos
asegurar que el orden de bajada de los mensajes coincidirá con el orden de envío de los mismos, ya
que un mensaje enviado antes puede llegar más tarde que otro (supongamos dos respuestas a un
60
mismo mensaje uno hace un recorrido más largo que otro por Internet), e incluso el buzón de entrada
no entrega los mensajes ordenados completamente. Con lo cual orden de bajada no es del todo igual
a orden de llegada de los mensajes al buzón. El segundo error parte de que si un mensaje por
cualquier motivo no puede ser bajado en la sesión actual y se baja en la siguiente, el id que recibiría
sería posterior y al ordenar por id, mostraría un listado inexacto. En cambio, timeOrigen ordena
por la fecha y hora de envío del mensaje, y un mensaje bajado en una sesión posterior al ordenar por
este campo aparecería correctamente en su posición.
En consecuencia de todo lo expuesto, el listado de mensajes relacionados se obtendría, en orden
ascendente con "select * from mails,relacion where mails.id=relacion.id order by relacion.timeOrigen
asc,relacion.ordinalThread asc limit m,n; ", donde “m” es la posición inicial (cero si es desde el
primer registro) y “n” el número de registros que recuperamos. En un listado descendente, basta
con cambiar asc por desc en el order de timeOrigen.
Entre las tablas de mails y relación hay una cardinalidad de 1:1, por lo que podrían fusionarse
ambas en una sola. No obstante, preferimos la división ya que resulta más claro y además
dividimos las inserciones entre:
•
inserciones en mails, ThreadPop
•
inserciones en relación, ThreadReplies
huerfanos
Archivamos los id de los mensajes que por algún motivo no se hayan podido relacionar. Podría
pensarse si no es posible alguna sentencia SQL tipo left/right join que permita obtener un listado de
los identificadores de los mensajes que se encuentran en la tabla mails pero no en la tabla relación.
Tras diversos intentos infructuosos se optó por crear finalmente esta tabla.
Cerca del 2%12 del total de mensajes no guardan la relación que debieran por el uso equivocado que
esporádicamente hacen algunos usuarios. Un ejemplo sería enviar dos veces el mismo mensaje.
Aparte, en principio pueden darse dos de los siguientes motivos. En primer lugar, el caso más
corriente es crear un nuevo topic mediante un ‘reply’ a un mensaje. La segunda posibilidad es la que
nos ocupa. Se da en mucha menor proporción, cuando en lugar de pulsar el botón “responder a”,
crean un nuevo mensaje que titulan “Re: (mensaje anterior)”. Ese mensaje está relacionado
lógicamente con el anterior en la mente del individuo pero no hay señal alguna en la cabecera del
mensaje que nos indique dicha relación, y por lo tanto constituirá un huérfano.
Podría pensarse rápidamente en nada más recibir un mensaje sin references considerar el asunto o
el cuerpo del mensaje para compararlo con el de mensajes ya archivados, pero esto nos lleva a
algoritmos enrevesados que tienen una fiabilidad baja. Varios intentos al respecto han hecho
desestimar el uso de estas técnicas.
No es tan sencillo como sondear entre mensajes que tengan el asunto “(mensaje anterior)”, ya que
el mensaje anómalo puede pretender ser respuesta de otro que pertenezca a un thread de discusión
en el que todos tengan como asunto “Re: (mensaje anterior)”. ¿Cómo saber a cuál pertenece?
Quizás podríamos encontrar en el mensaje que es respuesta trazas del mensaje respondido, del
mismo modo que también es probable que no las haya. Es posible, como se hace a menudo, que en
texto del asunto haya añadido algunas palabras “Re: (mensaje anterior) xxxxxx”, con lo que el
ordenador buscaría un asunto inexistente”. Si nos decantamos por buscar palabras clave entre los
dos mensajes. ¿Qué palabras buscar? ¿Cómo estamos seguros que esas palabras no se encuentran en
otra decena de mensajes? Etcétera, etcétera.
12
Estimado después de hacer pruebas con listas de Yahoo Groups sobre un millar de mensajes.
61
El número de posibilidades que hagan fracasar la relación en un mensaje sin references es altísimo,
así como el coste computacional y de implementación.
Por lo tanto, una opción más fácil sería informar al usuario del modo correcto de responder
mensajes, algo que se podría realizar automáticamente al observar que el mensaje ha quedado sin
relacionar.
registros
Registros de usuarios en listas, en los que se especifica si desea enviar o recibir correo en su e-mail.
users
Datos generales de los usuarios.
sistema
Valores de inicialización del sistema13.
nombre
regsXPagina
pathAttachments
maxSizeAttachments
segsDuermePop
debug_desactivaPop
listaEjemplo
smtp_auth
smtp_login
smtp_password
smtp_host
valorInt
30
0
512000
60
valorStr
./PFC_Attachments
no
[email protected]
si
projetse04
fentproves
smtp.correo.yahoo.es
La estructura con los tres campos está pensada para que se puedan añadir fácilmente entradas,
identificables por el nombre, que sean números o cadenas.
•
regXPagina: especificamos el número máximo de registros que se volcarán en el listado de
mensajes por página.
•
pathAttachments: directorio raíz donde se almacenarán los archivos bajados.
•
maxSizeAttachments: indicamos tamaño máximo aceptable en bytes de un attachment. Un
archivo mayor no se guarda en disco.
•
segsDuermePop: tiempo que duerme el thread de bajada de mensajes una vez que ha acabado
antes de volver a conectar con el servidor POP.
•
debugDesactivaPop: empleado para depuración, activa o desactiva la bajada de mensajes.
•
listaEjemplo: explicación en apartado Evaluación Pruebas. Una vez testeado, no tiene ninguna
utilidad.
13 en la versión entregada los threads duermen 30 segundos para facilitar las pruebas. Asimismo, el smtp es el
de urv, por lo tanto smtp_auth=no.
62
•
smtp_... : parámetros de conexión al servidor de correo saliente. Si smtp_auth es “no” (no
requiere autenticación) los valores de smtp_login y smtp_password no se tienen en cuenta.
Script de la base de datos
create database if not exists `pfcweb_sistema`;
use `pfcweb_sistema`;
drop table if exists `attachments`;
CREATE TABLE `attachments`
(
`idMail` int(11) NOT NULL default '0',
`idAttach` int(11) NOT NULL auto_increment,
`path` varchar(5) default NULL,
`nombre` varchar(75) default NULL,
`tamanyo` int(11) default NULL,
PRIMARY KEY (`idAttach`),
KEY `idAttach` (`idMail`)
) TYPE=InnoDB;
drop table if exists `baneados`;
CREATE TABLE `baneados`
(
`login` varchar(25) NOT NULL default '',
`idLista` int(11) NOT NULL default '0',
`fecha` date default NULL,
`motivo` text,
PRIMARY KEY (`login`,`idLista`)
) TYPE=InnoDB;
drop table if exists `huerfanos`;
CREATE TABLE `huerfanos`
(
`id` int(11) NOT NULL default '0',
PRIMARY KEY (`id`),
) TYPE=InnoDB;
drop table if exists `listas`;
CREATE TABLE `listas`
(
`id` int(11) NOT NULL auto_increment,
`nombre` varchar(75) default NULL,
`email` varchar(75) default NULL,
`host` varchar(75) default NULL,
`login` varchar(25) default NULL,
`password` varchar(75) default NULL,
`comentario` text,
`registro` enum('SI','NO') default NULL,
`fecha` date default NULL,
`founder` varchar(75) default NULL,
`descripcion` varchar(100) default NULL,
PRIMARY KEY (`id`)
) TYPE=InnoDB;
63
drop table if exists `mails`;
CREATE TABLE `mails`
( `xfrom` varchar(75) default NULL,
`email` varchar(75) default NULL,
`subject` varchar(75) default NULL,
`content` text,
`id` int(11) NOT NULL auto_increment,
`message_ID` varchar(75) default NULL,
`time_` datetime default NULL,
`size` int(11) default NULL,
`idLista` int(11) default NULL,
PRIMARY KEY (`id`)
) TYPE=InnoDB;
drop table if exists `mailsdisponibles`;
CREATE TABLE `mailsdisponibles`
( `id` int(11) NOT NULL auto_increment,
`email` varchar(75) default NULL,
`host` varchar(75) default NULL,
`login` varchar(75) default NULL,
`password` varchar(75) default NULL,
PRIMARY KEY (`id`)
) TYPE=InnoDB;
drop table if exists `registros`;
CREATE TABLE `registros`
(
`login` varchar(25) NOT NULL default '0',
`idLista` int(11) NOT NULL default '0',
`recibeCorreo` enum('true','false') NOT NULL default 'false',
PRIMARY KEY (`login`,`idLista`)
) TYPE=InnoDB;
drop table if exists `relacion`;
CREATE TABLE `relacion`
(
`pos` int(11) default NULL,
`id` int(11) NOT NULL default '0',
`ordinalThread` smallint(6) default NULL,
`nivel` smallint(6) default '1',
`timeOrigen` datetime default NULL,
PRIMARY KEY (`id`)
) TYPE=InnoDB;
drop table if exists `sistema`;
CREATE TABLE `sistema`
( `nombre` varchar(25) default NULL,
`valorInt` int(11) default NULL,
`valorStr` varchar(75) default NULL,
PRIMARY KEY (`nombre`)
) TYPE=InnoDB;
drop table if exists `users`;
CREATE TABLE `users`
( `nombre` varchar(75) default NULL,
`apellido1` varchar(75) default NULL,
`apellido2` varchar(75) default NULL,
`email` varchar(75) default NULL,
`login` varchar(25) NOT NULL default '',
`password` varchar(25) default NULL,
PRIMARY KEY (`login`)
) TYPE=InnoDB;
64
4. DESARROLLO
En los diagramas de colaboración exponemos todos los objetos principales que entran en juego en
cada caso de uso.
CDU 1. Bajar regularmente correo
javax.mail
4: getFolder("Inbox")
:Store
INTERNET
:Folder
2:getStore("pop3"): Store
:Session
5: getMessages( )
Message
3: connect( )
1:despierta
9:duerme
6: *[i=1..n]: Message
:ListaDistribucion
:ThreadPop
:ComunPopReplies
:PatternsPool
7.1:
7.2:
:Message
reenvío mensaje
7.4:
7.3:
8: despierta / recoge mail
:MyMessage
:ThreadReplies
:Attachment
:PatternsReply
Pasos:
1: ThreadPop despierta después de un tiempo dormido fijado en el registro segsDuermePop en la
tabla Sistema y que se le ha pasado a través del constructor.
2: la instancia de la clase Session representa una sesión de correo, sobre la que recuperamos un
objeto Store en la que indicamos el protocolo de correo a utilizar.
3: conectamos con el servidor de correo.
4: del servidor bajamos la “carpeta” (folder) que nos interesa. En el caso de POP3 sólo existe una
carpeta14, pero de todas formas debemos especificarlo por parámetro: getFolder(“inbox”).
14 en otros protocolos como IMAP existen varias carpetas como las de “mensajes enviados”, “borrador”,
etcétera.
65
5: dentro de la carpeta encontramos los mensajes. Con
vector de objetos de la clase Message.
folder.getMessages() tenemos un
6: con un “for” recorremos cada uno de los mensajes. Cabe indicar que los mensajes no se han
bajado todos a una con getMessages( ). JavaMail descarga los mensajes por demanda, y más
concretamente las partes de un mensaje. Por lo tanto, cuando me encuentro en una posición
cualquiera del vector recupero un objeto Message vacío. Es precisamente cuando voy solicitando las
partes de este mensaje que las va descargando.
Para cada mensaje:
Antes que nada se comprueba que el remitente tiene permiso para escribir en la lista. De no ser así,
se le envía un correo informativo, y se pasa al siguiente mensaje de entrada.
7.1: creo una instancia de MyMessage que cumplimentamos con todos los datos del Message que
deseamos guardar en la base de datos. Para las distintas fases por las que pasa MyMessage se
emplean PatternsPool y PatternsReply.
7.2: creamos una nueva instancia de Message, no podemos emplear el mismo Message de POP3
porque es de sólo lectura, al que le insertamos un nuevo Message_ID que será al que referirán las
futuras respuestas al mensaje que pudiera tener ya que este Message está destinado a ser reenviado.
No podemos emplear el mismo Message_ID, ya que identifica no sólo el mensaje sino también el
instante en que fue enviado y no es posible copiarlo del mensaje original.
7.3: encolamos MyMessage en ComunPopReplies después de haberlo guardado en la base de datos
invocando el método guardaEnBD( ) de ListaDistribucion. Si no ha habido ningún problema, se
marca el mensaje como “borrable”.
7.4: reenviamos el mensaje: CDU 2.
8: al haber un elemento en ComunPopReplies, el ThreadReplies despierta, el cual comprueba si el
mensaje recibido tiene alguna relación con algún mensaje ya almacenado y lo guarda en la tabla
relación.
Los pasos 7.1, 7.2, 7.3 porque forman parte del mismo proceso. El número 8, ya es independiente
del trabajo de ThreadPop.
Cuando ThreadPop ha tratado todos los mensajes, cerramos los objetos Folder y Store. Al cerrar
Folder con el parámetro expunge a true se eliminan todos los mensajes que hemos marcado
anteriormente. Si un mensaje por cualquier motivo no pudo guardarse y no se marcó, estará
disponible en la siguiente ocasión.
9: ThreadPop duerme. Y después se volverá a repetir todo el proceso desde paso 1.
Los objetos Store y Folder se abren en cada ocasión por no estar permanentemente conectados al
servidor de correo y porque son susceptibles de generar excepciones. Si los abriéramos al crearse el
Thread y hubiera un error, no habría posibilidad de recuperarse. En cambio si el error sucede al
despertar el thread, vuelve a dormir y lo prueba más tarde.
66
CDU 2. Reenvío mensajes
:ComunASmtp
desbloquea /
recoge
*[i=1..n]: Message
:ThreadSmtp
tr.connect( )
tr.sendMessage( )
tr.close( )
javax.mail
tr:Tranport
INTERNET
Pasos:
ThreadSmtp se desbloquea cuando cualquiera de los threads de bajada de correo deposita un
mensaje. Entonces conecta con el servidor de Smtp y envía cada uno de los mensajes encolados.
Cuando ComunASmtp esté vacío, se desconectará del servidor y se desbloqueará a la espera de
nuevos mensajes.
67
CDU 3. Iniciar sesión
2: consulta
10: consulta
1: petición index.do
STRUTS
4: dirige
Actor
8: getListasExistentes( )
7: login
:MySession
:MyApplication
:ListaDistribucion
:index.jsp
6: crea / invoca
5: crea / invoca
crear
3: action
11: página
12: carga
9: datos
:indexJspAction
struts-config.xml
(mapa)
crear
crear
:ThreadSmtp
:ComunASmtp
crear
crear
:ThreadPop
crear
:PatternsPool
crear
:ComunPopReplies
:ThreadReplies
crear
:PattersReply
crear
:PattersReply
Pasos
1: el usuario solicita la página index.do.
2: Struts consulta en el archivo XML para saber qué acción debe ejecutar.
3: la acción devuelta es IndexJspAction.java.
4: Struts ejecuta la clase acción.
5: IndexJspAction crea un objeto MyApplication si es la primera vez que se llama a esta página
desde que se arrancó el contenedor de servlets, si no lo llama.
68
Al crearse el objeto MyApplication, se generan las clases mostradas en el cuadrado: tantas listas de
distribución como las encontradas en la base de datos, más un ThreadSmtp y un ComunSmtp para
conectar a él.
Cada ListaDistribución tendrá su ThreadPop y su ThreadReplies y el objeto intermedio entre
ambos.
6: crea un objeto MySession si el usuario entra por primera vez para una sesión en esta web, si no lo
llama.
7: recogemos el login. Si el usuario no se ha identificado, será nulo, luego está como invitado.
8: obtenemos las listas existentes, una colección de referencias a los objetos ListaDistribucion.
9: colocamos en el ámbito request, el login y la colección para que pueda ser recuperado desde la jsp.
Es la principal manera de compartir información entre Action y JSP en Struts.
10: Struts consulta qué pagina jsp debe cargar15.
11: devuelve que la página es index.jsp.
12: carga la página index.jsp. En el navegador aparecerá como “index.do”. En el interior de la página
hay etiquetas Struts que recuperan los datos que hemos colocado en el objeto Request.
CDU 4. Consulta datos lista
2: consulta
14: consulta
1: petición lista.do
página JSP
STRUTS
5: dirige
:ListaAction
4: carga
13: vuelve
struts-config.xml
(mapa)
3: action y form
15: página
16.1: carga
:lista.jsp
12: llena
6: invoca
8: invoca
7: referencia
objeto
:MyApplication
11: getListaDistribución
9: login
:ListaForm
16.2: lectura
10: crea
:GestionListas
:MySession
Pasos
1: solicitamos listado.do desde una página JSP que disponga de un enlace a él.
2: Struts consulta en el archivo XML para saber qué acción debe ejecutar.
3: devuelve que la acción es ListaAction.java y que empleamos un bean de formulario llamado
ListaForm.
El contenedor de servlets crea una sola instancia por cada JSP, a compartir por todas las peticiones para
dicha página. Otra buena razón para no incluir código de lógica en las páginas. Por lo tanto por “cargar una
página jsp” entendemos que accede a ella, y será el contenedor de servlets, no Struts, quien se encarga de
interpretar el jsp y crear el servlet o bien si ya está creado, de devolver una referencia a él.
15
69
4: Struts carga ListaForm.java en blanco.
5: Struts carga ListaAction.java.
6: invoca MyApplication.
7: extrae referencia de MyApplication del contexto del servlet que ejecuta el Action.
8: invoca MySession.
9: recibe el login. Si el login coincide con el del fundador, el formulario de la página se podrá editar.
10: crea GestionListas. Le pasamos referencia a MyApplication, objeto que tiene la colección de listas
de distribución16.
11: devuelve ListaDistribución.
12: llenamos el bean de formulario con los datos de la lista, y la indicación de si es modificable o no
en la propiedad “action”. El bean lo hemos recibimos como un parámetro más en el método execute(
) del Action y es de ámbito request.
13: volvemos a Struts.
14: Struts consulta a qué página debe reconducir.
15: devuelve lista.jsp.
16.1, 16.2: Struts carga entonces lista.jsp. y con etiquetas Struts de formulario accedemos al bean.
Si desde los datos principales de la lista, queremos conocer los usuarios registrados de la misma,
haríamos clic en el enlace que realiza la petición lista2.do:
1: petición lista2.do
2:, 17: consulta
:lista.jsp
struts-config.xml
(mapa)
STRUTS
3: action y form
18: página
4.2:dirige
4.1: crea
19.1: carga
16: vuelve
:Lista2Action
:Lista2Form
:lista2.jsp
11: llena
19.2: lectura
5: invoca
7: invoca
6: referencia
objeto
:MyApplication
8: referencia
objeto
10, 13, 15: devuelve
9: getListaDistrib.( )
:MySession
12: getUsuariosRegistrados( )
14: getUsuariosExpulsados( )
:GestionListas
Podríamos obtener la lista desde el mismo objeto MyApplication. Pero en especificaciones indicamos que la
lista la recuperaríamos a través del objeto GestiónListas.
16
70
Pasos:
1, 2, 3, 4.1, 4.2, 5, 6, 7, 8: 9, 10: a GestionListas le pasamos las referencias de los objetos llamados anteriormente. Obtenemos
lista distribución.
11: llenamos Lista2Form con el nombre de la lista y algunos valores más como los títulos y los enlaces
de expulsar y readmitir, si quien ha realizado la petición es el fundador de la lista. De hecho en
lista2.jsp no vamos a encontrar ningún formulario. Aquí el bean de formulario se emplea para
empaquetar cadenas . Luego accederemos como un bean cualquiera de visibilidad request.
12, 13, 14, 15, 16, recuperamos las colecciones de usuarios de pleno derecho y de usuarios
expulsados, que depositamos en el objeto request del contenedor de servlets.
17, 18, 19.1, 19.2: lista2.jsp recupera las dos colecciones y los valores del bean.
CDU 5. Acceso mensajes lista pública
1: petición creaLista.do
2:, 12: consulta
página JSP
struts-config.xml
(mapa)
STRUTS
3: action
13: página
4: dirige
11: vuelve
14: carga
"listadoMails.do"
:AccesoAction
5:
6:
7:
10:
8:
9:
:MyApplication
:MySession
:GestionAcceso
:acceso.jsp
Pasos:
1: la página JSP desde la que se hará la petición es principalmente index.jsp, aunque también es
posible desde usuario2.jsp y usuario3.jsp.
2, 3, 4: 5, 6: obtenemos el objeto ListaDistribucion que enlazaremos a MySession si se acepta el login.
7,8: login del usuario, que puede ser cadena vacía si entra como anónimo.
9, 10: se controla el estatus del usuario en la lista, si está expulsado, si está registrado. En caso de no
aceptarse el login, devuelve el mensaje que se mostrará en la página.
11: antes de volver, si se acepta el acceso MySession contiene una referencia a la lista de distribución.
12, 13, 14: según el resultado se mostrará la página de acceso denegado o bien se realizará una
petición a “listadoMails.do”, que se concreta en el siguiente diagrama.
71
2:, 12, 16, 26: consulta
1:petición listadoMails.do
"listadoMails.do"
struts-config.xml
(mapa)
STRUTS
3, 17: action, form
13, 27: página
4.1, 18.1: dirige
4.2, 18.2: carga
11, 25: vuelve
15: petición listadoMails.do
:ListadoMailsAction
14.1, 28.1: carga
22: lectura
9, 24:
5, 19:
:ListadoMailsForm
10: llena
6, 20:
18.3: cambios
formulario
8, 23:
7, 21:
:MySession
14.2, 28.2: lectura
:ListadoMails
:listadoMails.jsp
Pasos:
1, 2, 3, 4: 5, 6, 7 : recibimos referencia de MySession. Dentro de este objeto hay la referencia a ListadoMails
que se actualizó al hacer el acceso, en el anterior diagrama.
8,9: parametrizamos el objeto con los valores por defecto, ya que es la primera vez que llamamos a la
página, recibimos el resultado de la consulta en forma de colección de FilaListado, que pasamos a la
Action.
10: llenamos los valores por defecto que debe mostrarse en el formulario de consulta.
11: guardamos en el objeto request del servlet la colección del resultado.
12, 13, 14.1, 14.2: cargamos la página.
15: si deseamos hacer una consulta no genérica, como la que acabamos de recibir, cambiamos los
valores en los controles del formulario, el orden, el tipo de campo a ordenar, etcétera y pulsamos en
el botón de submit.
16, 17, 18.1, 18.2, 18.3: cargamos el Action y el bean de formulario, al que pasamos los cambios
hechos en el formulario HTML.
19, 20, 21: idem 5,6,7.
22, 23, 24: idem 8,9 pero parametrizando con los cambios que se encuentran en el bean de
formulario. Este bean se comparte entre los dos formularios que tiene el listado.
25, 26, 27, 28.1, 28.2: -
En el caso que elijamos un mensaje en especial, se ejecutaría el proceso siguiente:
72
2, 12: consulta
1:petición detalle.do
:listadoMails.jsp
struts-config.xml
(mapa)
STRUTS
4.1: dirige
4.2: carga
3: action, form
13: página
11: vuelve
14.1: carga
:DetalleAction
:DetalleForm
9:
5:
6:
10: llena
8:
7:
:MySession
14.2: lectura
:ListadoMails
:detalle.jsp
Pasos:
Al igual que en el diagrama anterior, de MySession tomamos la referencia a ListadoMails.
Solicitamos que nos devuelva un mensaje en particular, así como el listado de todos los mensajes
relacionados.
Si pulsaramos sobre un botón de navegación entre mensajes, se realizaría una nuev a petición a
detalle.do, en la que el proceso se repetiría, aunque en este caso la página que lo inicia no sería
listadoMails.jsp sino la propia detalle.jsp.
DetalleForm mantiene algunos valores a mostrar en detalle.jsp, pero no el mensaje mismo, ya que no
era factible colocar el mensaje dentro del formulario, entre otras razones por dos principalmente:
•
las etiquetas Struts muestran los textos literalmente. Esto quiere decir que no se interpretarían
las etiquetas HTML que se encuentran en el texto, como por ejemplo los <BR> de salto de
carro.
•
porque detalle.jsp incluye mail.jsp, y éste espera un objeto MyMessage. Si empleáramos un
bean de formulario para encapsular el propio mensaje, deberíamos cambiar mail.jsp. Si
cambiamos mail.jsp ya no nos valdría para extiende.jsp, en el que se muestran varios
mensajes, porque un Action sólo es capaz de emplear un solo bean de formulario.
Por último dentro de detalle.jsp puede solicitarse el listado completo de mensajes relacionados vistos
en una sola página:
2, 11: consulta
1:petición extiende.do
:detalle.jsp
struts-config.xml
(mapa)
STRUTS
4.1: dirige
3: action
12: página
10: vuelve
:ExtiendeAction
13: carga
9:
5:
6:
8:
:extiende.jsp
7:
:MySession
:ListadoMails
73
Pasos:
Igual a los diagramas anteriores. En esta ocasión, de ListadoMails recogemos una colección de
MyMessage.
CDU 6. Acceso archivos de listas públicas
Tanto desde el listado de archivos, al que se accede a través de listado de mensajes, como desde un
mensaje determinado, para descargar un adjunto el enlace se llama a fileDownload.jsp a través de
un formulario. En el caso de listado de archivos está oculto, y le pasamos los parámetros con
JavaScript en el instante de hacer clic sobre el enlace.
En el jsp, especificamos en el response el MIME que recibirá el navegador “APPLICATION/OCTETSTREAM”, y el nombre del archivo. Abrimos un objeto de tipo FileInputStream que lee de disco y
trasvasa al objeto out del servlet.
CDU 7. Alta usuario
2, 8, 12, 22: consulta
1: petición usuario.do
:login:jsp
struts-config.xml
(mapa)
STRUTS
3, 13: action y form
9, 23: página
5, 15: dirige
4, 14: carga
24.1: cargar
7, 21: vuelve
:UsuarioAction
6: llena
11: pet.
usuario.do
:UsuarioForm
17: invoca
18:
referencia
:MySession
20:
16: lectura
:loginYaExiste.jsp
10.1, 24.2.1:
carga
19: crea
10.2, 24.2.2:
lectura
:GestionUsuarios
:usuario.jsp
Pasos:
1, 2, 3, 4, 5: 6: introducimos en el bean de form algunos valores que indican que la página es para hacer un alta,
como setAction=”alta” y el título de la página.
7, 8, 9, 10.1, 10.2 : cargamos página usuario.jsp con el formulario en blanco.
11, 12, 13, 14 ,15: 16: leemos los datos del formulario con el alta.
17, 18: tomamos una referencia de MySession.
19: creamos GestionUsuarios, y le pasamos la referencia a la sesión. Efectúa el alta. Si ha sido
satisfactoria, en MySession habrá el login y el email del usuario creado.
20, 21, 22, 23: -
74
24: si el alta se ha producido se seguirá mostrando usuario.jsp, donde aparte se mostrará un menú
de pestañas para que pueda darse de alta a listas, o crear listas. Si no, aparecerá una pantalla de
error.
CDU 8. Identificarse
2:, 6:, 10:, 18: consulta
1: petición login.do
:index.jsp
STRUTS
3: action
11: action, form
7:, 19: página
4: dirige
8: crea
:EditLoginAction
12.1:crea
struts-config.xml
(mapa)
12.3: dirige
20:carga
5: vuelve
:bienvenido.jsp
17: vuelve
9: petición
checklogin.do
13: lectura
:LoginForm
:CheckLoginAction
:login.jsp
12.2: llena
16: setLogin( ),
setEmail( )
14: crea, log_in( )
:login_error.jsp
15: email
:MyLogin
:MySession
Pasos:
1, 2, 3, 4: 5: a toda página le antecede un Action. En este caso, el action sólo redirige a la página.
6, 7, 8: 9: una vez el formulario HTML ha sido cumplimentado, pedimos “checkLogin.do”.
10: 11: el archivo XML devuelve el Action que necesitamos, y el bean de formulario que el Action leerá.
12.1, 12.2, 12.3: creamos el bean de formulario que contendrá los valores del formulario HTML y el
Action.
13: CheckLoginAction lee el bean formulario.
14: creamos MyLogin y le pasamos los valores del bean.
15: MyLogin devuelve email del usuario o cadena vacía si no existe el usuario o los datos del login son
incorrectos.
16: si la cadena de email no está vacía, actualizamos el objeto MySession.
17: volvemos a Struts. En el return del Action se indica si el login ha sido correcto (“success”) o no
(“failure”).
18: consultamos qué página se mostrará en el navegador según el return del Action.
19: devuelve la página.
20: carga la página.
75
CDU 9. Crear lista
1: petición creaLista.do
2:, 10:: consulta
:usuario3.jsp
struts-config.xml
(mapa)
STRUTS
3: action
11: página
4: dirige
9: vuelve
12: carga
:CreaListaAction
"lista.do"
8 puedenCrearseMasListas( )
5:
6:
7: crear
:MyApplication
:GestionListas
:nuevasListasNo.jsp
Pasos:
1,2,3,4: 5,6: necesitamos una referencia a MyApplication para pasárselo a GestionListas.
7,8: creamos GestionListas, le pasamos la referencia y consultamos si hay posibilidad de crear nuevas
listas.
9: volvemos a Struts con la respuesta de GestionListas.
10,11 : según si la respuesta recibida de la Action fue “success” o “failure” cargamos una página u
otra.
12: cargamos la página. Si la página es de error, terminamos aquí, si no, continuamos.
Siempre que llamamos a una página con extensión .do se ejecuta una Action, mientras que una
llamada a una página que tenga extensión .jsp no. Por ello “listado.do”, ejecutará los pasos
mostrados en el siguiente diagrama.
1: petición lista.do
"lista.do"
2:, 7:, 12:, 24: consulta
struts-config.xml
(mapa)
STRUTS
4.2: ,15: dirige
3:, 13: action y form
8:, 25: página
4.1:, 14:1 crea
26.1:
6:, 23:
nuevaListaError.jsp
21:
:ListaAction
9:, 26:2 cargar
:ListaForm
14.2: lectura
5:
16:
:MyApplication
17:
18:
19:
:MySession
22:
9:, 20: crear
76
11: petición
lista.do
10, 27: lectura
:GestionListas
lista.jsp
Pasos:
1, 2, 3, 4.1, 4.2: 5: introducimos en el bean de form algunos valores que indican que la página es para hacer un alta,
como setAction=”alta” y campos que se inicializaron con el valor “automático” al crearse el
formulario.
6, 7, 8, 9, 10 : cargamos la página lista.jsp con el formulario en blanco.
11: una vez hemos rellenado el formulario y pulsado el botón de envío, volvemos a Struts.
14:1, 14:2: al crearse el bean de formulario, recuperamos los valores existentes en el JSP.
15: cargamos la Action.
16, 17: tomamos referencia a MyApplication.
18,19: invocamos MySession, del que recibimos el login.
20, 21, 22: leemos los valores en el bean de formulario y damos de alta la lista.
23: volvemos.
24,25, 26.1, 26.2 : mostramos la página que corresponda según si el alta ha sido válida o no.
De momento creada el alta muestra la página lista.jsp. También podría hacerse para que volviera a la
página usuario3.do.
27: como estamos en lista.jsp leemos del formulario.
CDU 10. Consulta datos usuario
2, 12: consulta
struts-config.xml
(mapa)
1: petición usuario.do
:index:jsp
STRUTS
3: action y form
13: página
5: dirige
4: carga
14.1:
carga
11: vuelve
:UsuarioAction
10: llena
:UsuarioForm
6: invoca
:MySession
7:
referencia
9: getDatosUsuario( )
8: crea
14.2: lectura
:GestionUsuarios
Pasos:
1: solicitamos usuario.do desde index.jsp.
2: Struts consulta en el archivo XML para saber qué acción debe ejecutar.
77
:usuario.jsp
3: devuelve que la acción es UsuarioAction.java y que empleamos un bean de formulario llamado
UsuarioForm.
4: Struts carga UsuarioForm.java en blanco.
5: Struts carga UsuarioAction.java.
6, 7: recuperamos referencia a MySession.
8, 9: creamos GestionUsuarios y le pasamos el MySession, recuperamos los datos del usuario con el
método getDatosUsuario( ). Es imposible que el usuario no exista, puesto que para llegar a este caso
de uso hemos tenido que clicar un enlace que solo se muestra cuando el usuario está logineado.
10: llenamos el bean de formulario con los datos de usuario.
11,12,13, 14.1, 14.2: carga de la página, que recupera los valores de los campos del formulario HTML
del bean de formulario.
CDU 11. Modificar datos usuario
2, 14: consulta
struts-config.xml
(mapa)
1: petición usuario.do
:usuario.jsp
STRUTS
3: action y form
15: página
16.1: carga
4.2:llena
4.1: carga
5: dirige
13: vuelve
16.2: lectura
10: lectura
:UsuarioForm
:UsuarioAction
6: invoca
8: invoca
9: referencia
7: referencia
:MySession
:MyApplication
12: vuelve
11: crear,
modifUsuario( )
:GestionUsuarios
Pasos:
1, 2, 3, 4.1, 4.2, 5, 6, 7: 8,9: recibimos referencia de MyApplication necesaria por si el usuario ha cambiado su email, ya que
entonces modifUsuario( ) tendrá que cambiar dicha dirección en todas las listas en las que participa.
10, 11: crea GestionUsuarios, lee el form y pasa los datos a modifUsuario( ).
12, 13, 14, 15, 16.1, 16.2: volvemos a la página inicial con los cambios hechos.
78
CDU 12. Registrarse en lista
1: petición usuario2.do
2, 12: consulta
:usuario2.jsp
struts-config.xml
(mapa)
STRUTS
3: action
13: página
14: carga
4: dirige
11: vuelve
:Usuario2Action
5: invoca
10: vuelve
7: invoca
8: referencia
:MySession
6: referencia
9: crea,
altaEnLista( )
:MyApplication
:GestionUsuarios
Pasos:
1, 2, 3, 4: 5,6: referencia de MySession, necesaria para tener el login.
7,8: referencia de MyApplication necesaria para actualizar la lista de usuarios registrados de la lista de
distribución donde nos registremos.
9,10: creamos GestionUsuarios. Pasamos referencia a MySession y MyApplication. Llamamos a
altaEnLista( int idLista) y volvemos a Struts.
11, 12, 13, 14: la página cargada ya muestra en sí misma si estamos registrados o no.
CDU 13. Consulta listas registrado
1: petición usuario2.do
2, 16: consulta
:usuario.jsp
struts-config.xml
(mapa)
STRUTS
3: action
17: página
4: dirige
15: vuelve
:Usuario2Action
5: invoca
18: carga
10, 12 , 14: vuelve
:usuario2.jsp
7: invoca
8: referencia
:MySession
6: referencia
9: crea,
11: getListasUsuario()
13: getListasNoApuntado()
:MyApplication
79
:GestionUsuarios
Pasos:
1, 2, 3, 4: cargamos Usuario2Action.
5, 6, 7, 8: referencias de MySession y MyApplication a pasar a GestionUsuarios. Del primero
obtenemos el login. La referencia a MyApplication no se utiliza en este CDU, pero esta Action es
común a los CDU de registrarse, desregistrarse y recibir correo. El coste computacional de
referenciar MyApplication es nulo, el mismo que poner un par de condiciones.
9, 10, 11, 12, 13, 14, 15: recuperamos las listas en las que está registrado y en las que puede registrarse
que se pasan por el objeto request para que las etiquetas Struts del jsp receptor puedan leerlos.
16, 17, 18: cargamos la página destino.
CDU 14. Desregistrarse en lista
El diagrama y los pasos son los mismo que en el caso “registrarse en lista”, salvo que el método
llamado en GestionUsuarios es bajaDeLista( int idLista).
CDU 15. Recibir o no mails por correo
El diagrama y los pasos son los mismo que en el caso “registrarse en lista”, salvo que el método
llamado en GestionUsuarios es recibirCorreo(int idLista, String opcion).
CDU 16. Acceso mensajes lista privada
Es exactamente el mismo diagrama y pasos que en una lista pública.
CDU 17. Acceso archivos listas privada
El procedimiento es el mismo que para archivos de listas públicas.
CDU 18. Enviar mensaje por web
2, 11, 15, 24: consulta
1: petición nuevoMail.do
página JSP
STRUTS
struts-config.xml
(mapa)
3, 16: action y form
12, 25: página
4.2, 17.2: dirige
14: peticion nuevoMail.do
26: carga
10, 23: vuelve
:NuevoMailAction
13.1: carga
4.1, 17:1: crea
:nuevoMail.jsp
:mensajeEnviado.jsp
5, 18:
invoca
7, 21:
8, 22:
20: lectura
6, 19:
referencia
:mensajeNoEnviado.jsp
13.2: lectura
9: llena
:MySession
:NuevoMail
:NuevoMailForm
17.2: lectura
80
Pasos:
1: página JSP puede ser “listaMails.jsp”, “detalle.jsp”, o “extiende.jsp”. Desde los dos últimos es
para responder a mensajes.
2, 3, 4: 5, 6, 7, 8: tomamos una referencia a MySession para obtener el login, la lista de distribución y el
objeto ListadoMails. Si es una respuesta, recuperamos el mensaje al que responde, y lo tratamos con
símbolos “>” antes de cada línea. El método que realiza esto último se encuentra en NuevoMail.
9: ponemos el nombre de la lista, y el login del destinatario en el bean del formulario, más el texto
tratado si el mensaje será una respuesta.
10, 11, 12, 13.1, 13.2: cargamos la página nuevoMail.jsp.
14: cuando se ha terminado el mensaje, y pulsamos el botón del formulario se realiza una petición a
la misma página.
15, 16, 17.1, 17.2: cargamos NuevoMailAction y el bean de formulario con los valores del jsp.
18, 19: referencia a MySession que pasaremos a NuevoMail, ya que necesitará llamar al método de la
ListaDistribucion tanto para guardar el mensaje en la lista como para decidir los correos electrónicos
que recibirán el mensaje.
20, 21, 22: leeremos del bean y pasamos los valores a NuevoMail para que lo guarde en la lista y lo
reenvíe por Internet. Si se adjunta un archivo, se llama a MyApplication para conocer el tamaño
máximo que puede tener dicho archivo y se crea un objeto Attachment con lo recibido del form, y que
pasaremos a NuevoMail para que lo añada al MyMessage que ha de crear y enviar.
23, 24, 25, 26: cargamos una página u otra que indican si el mensaje ha sido enviado o no. Si el
motivo por el cual no se acepta el mensaje es el excesivo tamaño del archivo adjunto, la página de
resultado explica el motivo.
CDU 19. Enviar mensaje por correo
En especificaciones ya se comentó que este caso no se estudia, por ser externo a la aplicación. Si lo
tendremos en cuenta en el apartado de pruebas.
81
CDU 20. Consultar listas creadas
1: petición usuario3.do
2, 13: consulta
:usuario.jsp
struts-config.xml
(mapa)
STRUTS
3: action
14: página
4: dirige
12: vuelve
15: carga
:Usuario3Action
11: vuelve
5: invoca
:usuario3.jsp
7: invoca
8: referencia
6: referencia
:MySession
9: crea,
10: listasCreadas()
:MyApplication
:GestionUsuarios
Pasos:
1, 2, 3, 4: cargamos Usuario3Action.
5, 6, 7, 8: referencias de MySession y MyApplication a pasar a GestionUsuarios.
9, 10, 11, 12: recuperamos la relación de listas creadas por el usuario, pasadas por un objeto request
para que las etiquetas Struts del jsp receptor puedan leerlos.
13,14,15: cargamos la página destino.
CDU 21. Modificar datos lista
2:, 13: consulta
1: petición lista.do
struts-config.xml
(mapa)
STRUTS
:lista.jsp
3: action y form
14: página
15.1: carga
4.2:llena
15.2:
lectura
4.1: carga
5: dirige
10: lectura
12: vuelve
:ListaAction
:ListaForm
6: invoca
11: crea,
modifLista( )
8: invoca
9: login
:MyApplication
7: referencia
objeto
:MySession
82
:GestionListas
Pasos:
1: para modificar debe haberse entrado en modo consulta y ser fundador. Luego estamos en
lista.jsp, hemos hecho algunos cambios y hemos pulsado el botón del formulario.
2: Struts consulta en el archivo XML para saber qué acción debe ejecutar.
3: devuelve que la acción es ListaAction.java y que empleará un bean de formulario llamado
ListaForm17.
4.1, 4.2: Struts crea ListaForm.java y le pasa los valores del formulario de lista.jsp.
5: Struts carga ListaAction.java.
6, 7, 8, 9: idem consulta datos lista.
10: leemos formulario.
11: crea GestionListas. Le pasamos referencia a MyApplication, objeto que tiene la colección de listas
de distribución y llamamos a método modifLista( ) con los datos leídos del formulario.
12: volvemos a Struts.
13: Struts consulta a qué página debe reconducir.
14: devuelve lista.jsp.
15.1, 15.2: Struts carga entonces lista.jsp y con etiquetas Struts de formulario accedemos al bean.
CDU 22. Expulsar usuario de lista
Desde el CDU anterior 20, si el usuario pulsa en el link de expulsión se ejecuta lo siguiente:
1: petición banear.do
2, 11, 16, 29: consulta
:lista2.jsp
4.1, 18:1: crea
4.2, 18:3: dirige
10, 28:
14: lectura
:BanearForm
19:
23:
6, 21:
:MyApplication
3, 17, 30: action y form
12: página
15: peticion
banear.do
13: cargar
9:
:BanearAction
5,20:
struts-config.xml
(mapa)
STRUTS
22:
:banear.jsp
18.2: lectura
27:
8,25:
26:
:MySession
:GestionBaneados
7, 24:
:GestionUsuarios
17 los bean de formulario se crean cuando desde struts-config.xml se indica que una Action va a hacer uso de
ella. Las etiquetas Struts de formulario dentro de un JSP, no crean beans de formulario.
83
Pasos:
1: de la lista de usuarios registrados, hacemos clic sobre aquél que deseamos expulsar.
2, 3, 4, 5, 6: 7, 8: GestionUsuarios para obtener el email del usuario a expulsar.
9: guardamos nombre, email y fecha de expulsión.
10, 11, 12: 13, 14, 15: mostramos la página con los valores del bean formulario, introducimos el motivo y
pulsamos el botón de alta.
16, 17, 18, 19: 20, 21: ListaDistribucion.
22, 23: MySession tiene el login de quién va a realizar la expulsión.
24, 25: obtenemos email del usuario a expulsar.
26, 27: creamos GestionBaneados y ejecutamos el alta de expulsión, pasándole el login y email del
expulsado y el login del fundador. El email del expulsado es para retirarlo de la ListaDistribucion.
28, 29, 30, 31: volvemos a lista2.do, o sea volveríamos a CDU20.
CDU 23. Readmitir usuario a lista
1: petición banear.do
2, 14: consulta
:lista2.jsp
struts-config.xml
(mapa)
STRUTS
16: cargar
4.1, 18:1: crea
4.2: dirige
3: action y form
15: página
13: vuelve
:BanearAction
:BanearForm
8:
5:
6:
:MyApplication
7:
10:
12:
9:
:MySession
:GestionUsuarios
11:
:GestionBaneados
Pasos:
Similar a los pasos del segundo diagrama de expulsar usuario, pero tras la readmisión se vuelve a
lista2.jsp sin pasar por banear.jsp.
84
5. EVALUACIÓN PRUEBAS
A fin de mantener la coherencia seguida en el curso del documento, las pruebas son expuestas bajo
los epígrafes de los casos de uso. Debido a que se encuentran entre ellos en algunos casos
fuertemente relacionados es poco menos que inevitable que algunas pruebas se repitan.
De las listas de distribución empleadas, contamos con una, llamada “lista principal”, cuya fuente de
mensajes será externa a la aplicación, ya que su cuenta de correo está suscrita a una lista de Yahoo
Groups. Ello permite disponer de un número considerable de mensajes, nos evita redactarlos
nosotros mismos y aumentamos las posibilidades de localizar errores en el tratamiento del correo y
en la relación entre los mismos.
No hay que olvidar que es una lista externa, con el propósito de ser usada en funciones de depuración
y demostración pero que no correspondería con el funcionamiento normal de la aplicación: las listas
deben contener mensajes de ellas mismas.
Al ser una lista externa, no controlaremos los usuarios que participan en ella, al contrario que en una
lista creada en nuestra aplicación.
En las pruebas realizadas fuera de la universidad se ha empleado el smtp de Yahoo que requiere
autenticación. Ello me ha permetido emplear varias cuentas para hacer las pruebas. La recepción de
mensajes a través de correo electrónico puede no ser inmediata, tardando algunos minutos (dos,
cinco... ) según el proveedor del servicio. Es algo a tener en cuenta al probar el envío de mensajes a la
lista fuera de la aplicación.
La red de ETSE no permite emplear otro servidor de correo saliente que no sea
smtp.urv.es, que no exige autenticación, pero sí que el destinatario sea de dominio
urv.es.
Por ello, la aplicación entregada funciona con dicho servidor de correo saliente y no
incluye usuarios, habrá de crearlos quien lo ejecute con cuentas de correo urv.es,
puesto que yo únicamente dispongo de una cuenta con extensión de la universidad.
La base de datos además viene con dos listas creadas: “la principal” y una propia, más la posibilidad
de crear una tercera sobre la marcha.
Por abuso de lenguaje hablaremos de páginas al referirnos a elementos con la extensión .do
cuando en realidad son peticiones que tras pasar por una clase Action nos llevan a la verdadera
página de igual nombre y extensión .jsp.
CDU 1. Bajar regularmente correo
En la base de datos existen tres listas vacías, una de ellas es la “lista principal”.
Arrancamos la aplicación.
En el output de Tomcat:
pop
pop
pop
pop
zapateros bajando 0 mensajes
pensadores bajando 0 mensajes
lista 2 bajando 0 mensajes
lista principal bajando 195 mensajes
85
pop zapateros duermo 3018 segundos
pop pensadores duermo 30 segundos
pop lista 2 duermo 30 segundos
Los threads que no tienen mensajes duermen al instante. Al cabo de 30 segundos vuelven a leer el
buzón de correo, y así cíclicamente. La lista principal duerme una vez bajados todos los mensajes.
Se constata que los 195 mensajes de “lista principal” son guardados en la BD en orden y
relacionados correctamente.
Los mensajes enviados por usuarios expulsados, o no registrados (tanto en la lista como en la
aplicación en general) son eliminados. Vemos que reciben mensajes de aviso, al visitar las cuentas
de correo de los mensajes. Esto no se aplica en la “lista principal”, pues es una lista de ejemplo.
Se crea una nueva lista (CDU 9) y se observa como un nuevo thread se encarga del buzón de la nueva
lista.
Probamos con otra nueva lista (CDU 9) , pero en este caso los datos de la cuenta son incorrectos con
lo cual no será posible una conexión.
pop cuenta_mal error en conexión
duermo 30seg, y volveré a intentarlo. ( 1 de 5 intentos )
Pasados los 5 intentos pasa a dormir durante una hora.
Probamos a enviar mensajes desde web en lista principal, mientras sigue recibiendo correo por
internet: sin incidencias.
Prueba de recibir correo por Internet desde dos cuentas: se guardan los mensajes de ambas en sus
respectivas listas.
CDU 2. Reenvío mensajes
Los mensajes de listas que no son la de ejemplo reenvían los mensajes que reciben a todos los
usuarios registrados y no expulsados, salvo el usuario mismo que lo ha enviado.
CDU 3. Iniciar sesión
Este CDU inicia una sesión para cada usuario que accede a la página principal. La petición de esta
página hace que para el primer usuario que entra recién puesto en marcha Tomcat arranque
automáticamente la aplicación antes de recibir la sesión.
En el directorio bin de Tomcat escribimos startup.bat.
Con Tomcat cargado y la aplicación todavía no en marcha, abrimos el navegador e introducimos la
dirección: http://localhost:8080/PFC_Web_Struts/index.do. En la ventana de Tomcat, se observa
como la aplicación arranca y se ejecuta CDU 1.
Si ahora cerramos el navegador, la aplicación sigue su curso.
Volvemos a abrir el navegador e introducimos de nuevo la dirección anterior, estudiamos la página
index.do. Los datos y los enlaces son correctos. Cada ocasión que refrescamos la página si en el
18 Se escogen 30 segundos para hacer las pruebas cómodamente. Este valor debería tener en cuenta si hay
usuarios conectados en ese momento en ella, para descargar con mayor o menor frecuencia.
86
buzón ha recibido nuevos mensajes o si hemos creado un nuevo mensaje, aparece actualizado el
contador de mensajes de la lista implicada, y la fecha u hora del último mensaje bajado. Si creamos
una nueva lista al volver a index.do aparecerá en la relación, con el número de mensajes a cero y un
usuario registrado, el propio fundador.
CDU 4. Consulta datos lista
Este caso se da cuando consultamos las propiedades de una lista, por ejemplo desde index.do al
hacer clic sobre “descripción” de una lista.
El funcionamiento de este CDU se observa en dos páginas: lista.do y lista2.do.
Los datos en ambas páginas aparecen correctos y sus enlaces funcionan.
En lista.do se comprueba que sólo como usuario fundador se tienen los cuadros de texto habilitados
por si se desea hacer algún cambio. Cualquier otro usuario los encuentra desactivados.
En lista2.do, los enlaces que permiten la expulsión y readmisión de usuarios en la lista sólo se
presentan al fundador. Cualquier otro usuario encuentra listados de sólo lectura.
Seguridad:
Intentos de acceder directamente a las páginas sin pasar por index.do (donde se inicia la sesión)
muestran en lista.do un formulario en blanco de nueva lista que no permite guardar y en lista2.do un
página en blanco.
Introducir direcciones lista.jsp y lista2.jsp con o parámetros o sin ellos produce resultado en blanco.
Con la sesión iniciada, desde cualquier lugar de la aplicación introducir lista.do?idLista=2
&return=index.do nos mostrará la lista pero con los derechos que tengamos, ya sea usuario normal o
fundador. Igual con lista2.do.
CDU 5. Acceso mensajes de listas públicas
Acceso
Probamos con un usuario expulsado en la lista. Surge un mensaje como el anterior informando
además de la expulsión. Pulsamos enlace “entrar” y accedemos a listado mensajes.
Probamos con un usuario registrado: accede directamente a listado de mensajes.
El acceso se controla internamente y no es posible saltárselo poniendo directamente en la barra de
URL la dirección de listadoMails, listadoAttachments, detalle, extiende. En todos estos casos, sólo
muestra la página si ya hemos accedido a ella anteriormente, y para la última lista que hayamos
visitado. Bien distinto es que haciendo diversas pruebas, escribamos la dirección y obtengamos la
página almacenada en la caché del navegador, pero ello es porque hemos accedido antes.
Listado
Entramos como registrados en una lista que veamos que no tiene mensajes. Indica “no se produjeron
resultados”. Hacemos clic en “redactar nuevo mensaje”, y hacemos un mensaje con un adjunto.
Aceptamos. Volvemos a la lista y vemos que se ha actualizado correctamente.
87
Introducimos otros mensajes relacionados entre ellos. Elegimos “listado relacionado”
formulario de consulta, y vemos como aparecen indentados según la jerarquía en la relación.
en el
Como hay menos registros que el número de registros por el que se pagina no aparece el índice de
páginas.
Vamos ahora a “lista principal”, como no registrados a ella. No aparece el enlace “redactar nuevo
mensaje”. El número de registros es superior al que se muestra por página, por lo que vemos que
aparece un índice de páginas al estilo anterior [1] [2] [3] siguiente . Probamos a movernos
clicando en página 1, página 2... probamos anterior , siguiente. Nos aseguramos que no aparezcan
páginas en blanco, o que el enlace “anterior” esté desactivado cuando estemos en la primera página
o el “siguiente” cuando estemos en la última.
Probamos el panel de consulta: probamos orden ascendente y descendiente por todos los campos
posibles. Filtramos por varios criterios en orden ascendente y descendiente. Se visa con JavaScript
si: dejamos campos en blanco, si al esperar formato fecha se introduce otra cosa, si se colocan letras
donde se esperan números. El panel funciona correctamente y el listado que se obtiene es acorde al
panel.
Al filtrar la consulta, el número de registros puede ser cero, entonces muestra “no se produjeron
resultados” o un número inferior al número de registros por página, con lo que no se muestra el
índice de páginas, o se muestra un número inferior.
Mensaje
Elegimos mensajes que estén en los extremos de las páginas: el primer y último mensaje de cada
página. Para cada mensaje, recorremos dentro de detalle.do
con los enlaces “anterior” y
“siguiente”. Se observa que el recorrido a través de la lista es correcto en todos los casos. Los enlaces
se desactivan, “anterior” cuando estamos en el primer mensaje y “siguiente” al estar en el último. Al
volver a la lista nos encontramos en la página perteneciente al último mensaje que hemos
consultado. Por ejemplo, si estábamos en el mensaje de la segunda fila de la página 2 y pulsamos
“anterior” tres o más veces al volver nos encontramos en la página uno.
Si el mensaje es accedido por un usuario con permiso para responder,
correspondiente. El resto de los enlaces están correctos.
aparece el enlace
Los mensajes con adjunto permite descargarlos.
Si el mensaje pertenece a un hilo de discusión, vemos el listado de todos los mensajes relacionados.
El mensaje actual aparece en negrita y sin enlace.
En el listado del hilo de discusión muestra el mensaje actual en negrita y sin link. Pulsamos en
cualquiera de ellos, ahora el recorrido de mensajes es el del hilo de discusión.
88
Extender
Pulsamos en [EXTENDER] para la lista de hilo de discusión dentro de un mensaje que tenga
relaciones. Muestra todos los mensajes del hilo. Si el usuario tiene permiso, en cada mensaje hay un
enlace para responder. La página extiende.do tiene los enlaces correctos.
Entramos como usuario registrado, respondemos un mensaje, al volver a extiende.do el mensaje
está en su posición correcta dentro de la jerarquía de relaciones.
CDU 6. Acceso archivos de listas públicas
Acceso
El acceso nunca es directamente a la lista de archivos. El usuario accede a la lista de mensajes y a
partir de ahí hace clic en el link “archivos”.
Listado
Escogemos una lista sin adjuntos. Aparece “no se produjeron resultados”. El panel de consulta es
idéntico.
Escogemos una lista con adjuntos. Los enlaces son correctos. Pulsamos sobre el enlace de nombre
de archivo, se abre la ventana del navegador para descarga del archivo, guardamos en el escritorio.
Abrimos el archivo: se bajó correctamente.
Volvemos a lista, pulsamos ahora sobre el enlace que indica quién envió el adjunto: se abre el
mensaje que incluía el adjunto.
Probamos con el panel de consulta, lo mismo que en CDU 5, pues es un formulario prácticamente
idéntico.
CDU 7. Alta usuario
Entramos en usuario.do desde el enlace en login.do o bien tecleándolo directamente. Aparece un
formulario en blanco, con algunos campos obligatorios. Los enlaces son correctos.
En las siguientes pruebas, JavaScript nos avisa de campos en blanco:
•
•
•
Pulsamos el botón de submit con todos los campos en blanco.
Pruebo a rellenar los campos con espacios.
Relleno todos los campos menos alguno o algunos obligatorios.
Todos los campos correctos, salvo el de e-mail el cual no tiene formato de correo eléctronico: aviso de
JavaScript.
Los dos campos de password no coinciden: aviso de JavaScript.
Intentamos introducir un alta de un usuario que emplea un login que ya pertenece a otro usuario y
nos redirige a una página con el aviso.
Probamos una alta válida, nos aparece la misma página por si deseamos modificar algo, y unos
nuevos links, conforme al nuevo usuario que acabamos de crear. Los enlaces son correctos.
Al producirse el alta, somos logineados automáticamente.
89
CDU 8. Identificarse
Entramos en login.do desde el enlace en index.do o bien tecleándolo directamente. Los enlaces a
“inicio”, “alta nuevo usuario” o “ayuda” son correctos.
Pulsamos directamente sobre el botón del formulario con uno o los dos campos en blanco (ya sea por
no haber introducido nada o por haber colocado sólo espacios): una alerta de JavaScript nos avisa
que hemos olvidado completar uno o ambos campos.
Introducimos login y/o passwords incorrectos: nos redirige a página de “usuario no existe o datos
incorrectos”. En dicha página, login_error.jsp (al que accedemos por forward bajo la dirección
“checkLogin.do”) probamos ambos enlaces: funcionan.
Uno de los enlaces es “probar de nuevo”. Volvemos a página de login. Probamos ahora con entradas
válidas de varios usuarios: nos redirige en cada caso a la pantalla de bienvenida. La sesión creada
al entrar por primera vez en index.do ya no es anónima, volviendo a esa página comprobamos que es
así. No existe manera externa de hacerse pasar por un usuario sin conocer su password.
CDU 9. Crear lista
La tabla “mailsdisponibles” está vacía.
Desde la página de listas creadas por el usuario, usuario3.do, hago clic en el enlace “nueva lista”.
Aparece una página avisando que no es posible crear nuevas listas.
Agrego un registro en tabla “mailsdisponibles” con la configuracion necesaria para acceder a una
cuenta de correo válida: nombre de la cuenta, login, password, y dirección del servidor POP. Esta
tabla se supone que tendría un conjunto de registros válidos de forma que el usuario al crear una
nueva lista, se le asigne transparentemente la cuenta de correo.
En la misma página de antes, volvemos a clicar “nueva lista”. Aparece la página de nueva lista, un
formulario en blanco donde especificar las propiedades de la lista.
Pruebo a enviar el formulario totalmente en blanco y luego también con uno o varios campos
obligatorios en blanco o con espacios: una ventana en JavaScript avisa que los campos señalados con
asterisco deben cumplimentarse.
Los enlaces de la página de crear lista son los mismos que los de consultar datos lista, y son
correctos.
Finalmente, pongo los valores correctos y damos a botón de formulario. Si hubiera algún fallo
aparecería el mensaje de nuevaListaError.jsp. Pulsado el botón, la página muestra un nuevo
enlace a “usuarios registrados”, si lo visitamos veremos que hay un único usuario por el momento,
el fundador de la lista.
Miramos en la ventana de output de Tomcat: ha aparecido un nuevo thread encargado de descargar
los mensajes de la nueva lista. Visitamos index.do, muestra una nueva fila.
Enviamos un mensaje a la nueva lista, cuando el thread vuelve a estar despierto recoge el mensaje y
lo muestra en el listado de mensajes.
Hacemos otra prueba con una cuenta no válida. Seguimos todos los pasos. Observamos en la
ventana de Tomcat como avisa que la conexión no es válida, que va a dormir n segundos antes de
90
volverlo a intentar. Como la cuenta es inexistente, lo intentará cinco veces y finalmente el thread
permanecerá parado durante una hora.
Intentar crear listas sin estar registrado es imposible. En primer lugar no le aparecerá el link para
acceder
y
prueba a entrar
introduciendo la dirección en la barra de URL:
http://localhost:8080/PFC_Web_Struts/creaLista.do?idLista=0&return=usuario3.do le aparecerá
un formulario en blanco pero al pulsar el botón le dará error al crear la lista.
CDU 10. Consulta datos usuario
Entramos desde el enlace perfil que aparece en index.do en los usuarios logineados. La página es la
misma que la de alta usuario. En este caso no está en blanco, sino que muestra los datos generales del
usuario.
CDU 11. Modificar datos usuario
Los datos de CDU 10 se pueden modificar en cualquiera de los campos, salvo login que se mantiene
deshabilitado. Se realizan las mismas pruebas que en CDU 7, y se prueban diversas modificaciones
válidas en cualquiera de los campos.
CDU 12. Registrarse a lista
Se siguen los pasos del CDU-1319. Escogemos varias listas en “Listas a las que puedo registrarme” y
hago clic en las aspas de registrar. Para cada una, la fila sube a “Listas en las que estoy registrado”.
Nos registramos en una lista pública, vamos a la lista de mensajes de dicha lista y vemos que
podemos escribir mensajes dentro de la aplicación. Nos desregistramos. Volvemos a intentar
redactar un mensaje en la misma lista pero ya no hay enlaces de “responder” en los mensajes o de
“redactar nuevo mensaje”.
Nos registramos en una lista privada, vamos a la lista de mensajes de dicha lista y vemos que
podemos leer y escribir mensajes dentro de la aplicación. Nos desregistramos. Volvemos a la lista,
pero tenemos el acceso denegado.
Enviamos un mensaje a la dirección de correo electrónico de la lista a una lista pública y sin registrar:
el mensaje no se guarda y nos envía un mensaje avisándonos.
Enviamos un mensaje a la dirección de correo electrónico de la lista a una lista privada y sin
registrar: el mensaje no se guarda y nos envía un mensaje avisándonos.
Enviamos un mensaje a la dirección de correo electrónico de la lista a una lista pública y registrado:
el mensaje se guarda, se muestra en el listado de mensajes.
Enviamos un mensaje a la dirección de correo electrónico de la lista a una lista privada y sin
registrado: el mensaje se guarda, se muestra en el listado de mensajes.
Nota: el tiempo que tarde en llegar un mensaje a una cuenta, ya sea del destinatario a la lista o de la
lista al destinatario no la podemos prever: a veces es al minuto, a los cinco minutos... depende del
proveedor del servicio de correo.
19 El orden de estos dos CDU aquí resulta caprichoso, pero seguimos el orden del diagrama de casos de uso
donde sí tenía un sentido, porque pertenecían a actores diferentes “registrado” y “registrado en lista”.
91
CDU 13. Consulta listas registrado
El acceso normal a este caso es el de un usuario logineado o recién creado que desea acceder a la
página “usuario2.do” para comprobar en qué listas está registrado y quizás registrarse o
desregistrarse en alguna.
Desde usuario.do o usuario3.do por el enlace, vamos a “usuario2.do”. Si es un usuario anónimo no
logineado a través de estas páginas no podrá, ya que no está logineado. Si introduce la petición a
través de la barra del navegador encontrará una página en blanco.
En los casos de usuario recién creado o usuario ya existente la página mostrada tiene todos los
enlaces correctos. Para un usuario nuevo, bajo el título “Listas en las que estoy registrado” aparece
“No estás registrado en ninguna lista“. Para un usuario que se haya registrado en todas las listas
aparece bajo “Listas en las que no estoy registrado”, “Estás registrado en todas las listas”.
En esta página se pueden llevar a cabo los casos CDU-12, CDU-14 y CDU-15.
CDU 14. Desregistrarse de lista
Se siguen los pasos de CDU-13. Escogemos una lista cualquiera dentro de “Listas en las que estoy
registrado” hacemos clic en “baja” y baja a “Listas a las que puedo registrarme”.
El resto de pruebas a realizar son las mismas que en CDU-12.
CDU 15. Recibir o no mails lista por correo
Escogemos una lista registrada de CDU-12. Al registrarnos en una lista por defecto la recepción de
la lista por correo es “No”. Hacemos clic en la fila “estado email” se pone a “Sí”
Enviamos un mensaje a la lista por correo y otro desde la web de la aplicación, ambos por otro
usuario registrado, y al minuto abrimos cuenta correo del usuario registrado: recibe los mensajes
enviados a la lista por el otro usuario. Sin embargo, si abrimos la cuenta de correo del usuario que
escribió los mensajes vemos que no los ha recibido, ya que sólo se reciben los mensajes del resto de
participantes, no los de uno mismo.
CDU 16. Acceso mensajes de lista privadas
Probamos el acceso de un usuario no registrado. Aparece página de acceso denegado informando que
debe registrarse para leer o escribir mensajes. No podemos entrar en el listado.
Probamos el acceso de un usuario expulsado. Aparece página de acceso denegado informando fecha
de la expulsión y motivos. No podemos entrar en el listado.
Nos logineamos como un usuario registrado a la lista y sin expulsión: acceso directo.
El resto de apartados es idéntico a CDU 5
92
CDU 17. Acceso archivos de listas privadas
Idéntico CDU 6. La lista de archivos de listas privadas es a través del CDU 16, por lo que si no hemos
sido aceptados tampoco podremos entrar aquí.
CDU 18. Enviar mensaje desde web
Redactamos nuevo mensaje por web desde listado de mensajes.
Redactamos de nuevo desde listado de mensajes con adjunto que supera el máximo aceptado: se
avisa de la restricción en el tamaño de los adjuntos y no se permite guardar. Probamos con uno con
un tamaño tolerado, se guarda y se envía el mensaje con adjunto a los participantes que solicitan
reenvío.
Los mensajes se reenvían, salvo si la lista tiene un solo usuario que sólo se guarda en la base de datos
pero no se envía por correo al usuario que ha escrito en la web.
Probamos a redactar mensajes como respuestas a mensajes ya existentes en la base de datos. Se
relacionan correctamente.
CDU 19. Enviar mensaje por correo
Este CDU está relacionado con CDU-12 y CDU-14. Como ya han sido probados, faltará probarlo
para un usuario expulsado, en el CDU-22.
Se prueba que no se pueda enviar mensaje mayor de 500 KB. Esta restricción no la aplicaremos a la
lista de ejemplo. El remitente recibe correo de aviso que su mensaje no ha sido guardado en la lista.
Probamos que no admite un mensaje mayor de 500KB, salvo “lista principal”.
CDU 20. Consultar listas creadas
Desde el enlace de perfil, llegamos a una página con una pestaña con el título “listas creadas”, la
pulsamos. Muestra todas las listas de las que el usuario es fundador. Todos los enlaces están
correctos.
CDU 21. Modificar datos lista
La página desde donde se realizan las modificaciones es lista.do, la misma de CDU 4. Sólo el
fundador encuentra ciertos cuadros de texto activados. Se comprueba que se puede modificar por
cualquiera de ellos.
De igual modo, dejar en blanco campos obligatorios lanza un aviso de JavaScript.
Al cambiar la naturaleza de la lista de pública a privada se pueden observar las restricciones de
acceso en usuarios no registrados.
93
CDU 22. Expulsar usuario lista
Desde la página de usuarios registrados en lista en la que hemos entrado como fundador, escogemos
un usuario y hacemos clic en expulsar. Una vez en la página de expulsión, decidimos que no
queremos sancionarlo, pulsamos en “volver” y vemos como el usuario sigue en la lista de arriba.
Volvemos a escoger un usuario. Clicamos en expulsar. En la página decido no explicitar un motivo al
darle al botón de submit. Un mensaje en JavaSript nos avisa.
Esta vez, exponemos un motivo. Pulsamos lo que nos lleva a la página anterior. Comprobamos que
el usuario se encuentra en la lista de abajo.
En otros CDU’s ya hemos comprobado qué sucede con los usuarios expulsados.
Expulsamos todos usuarios y la lista queda vacía con el mensaje “no hay ningún usuario registrado
en la lista”.
CDU 23. Readmitir usuario lista
Escogemos cualquiera de los usuarios antes expulsados, y hacemos clic en “readmitir”. Realizando
otros CDU vemos que es usuario ha sido rehabilitado.
Intentamos ahora expulsar o readmitir algún usuario a través de la URL sin ser el fundador.
Probamos tanto como usuario anónimo como usuario registrado en lista pero no fundador
introduciendo “banear.do?login=nuria&idLista=2&accion=alta &return=index.do “ en ambos casos
muestra formulario pero no permite expulsar.
94
6. CONCLUSIONES
Struts implica un trabajo extra en la conversión de una aplicación puramente en JSP, ya que deben
implementarse varias clases Action y beans de formulario adicionales. Aun así, la ventaja de poder
separar entre capas es evidente desde el primer momento, puesto que facilita el mantenimiento y la
legibilidad.
En el modelo de JSP todo lo referido a una página se encuentra apelmazado dentro de ella, y pese al
empleo de beans y de bibliotecas de tags para atenuar este inconveniente, código y presentación
siguen yendo juntos.
Sin embargo, gracias a Struts, la separación es fácil y natural: cada elemento tiene su sitio y así es
más fácil encontrarlo y depurar errores. La presentación corresponde a las páginas JSP, el negocio a
clases que no son accedidas directamente desde la página. Struts hace de mediador entre unos y
otros proporcionando además un pool de conexiones a las clases de negocio.
Durante el desarrollo del proyecto también se ha constatado la dificultad que entraña blindar una
aplicación frente a la innata capacidad del ser humano a equivocarse, ya sea usuario o programador,
muy en especial los mensajes descargados del buzón de correo. La casuística de mensajes mal
formados es afortunadamente baja pero diversa y son en principio por uno de estos dos motivos:
ausencia de algún header en el mensaje y sobre todo por errores de usuarios, tal como se explicó
respecto a tabla “huérfanos”, en las decisiones de bases de datos.
Dos ojos nunca son suficientes para testear una aplicación.
95
7. RECURSOS UTILITZADOS
BIBLIOGRAFÍA
•
HTML y CGI, José Manuel Framiñán Torres, editorial Anaya Multimedia, 1997.
•
Programming Jakarta Struts, Chuck Cavaness, editorial O’Reilly.
•
Apuntes de Enginyeria del Software, Benet Campderrich, para la realización de este documento.
PÁGINAS WEB
He visitado un buen número de páginas web. Como es lógico, tuve que filtrar entre diversos
contenidos de escaso interés. Entre las páginas que he tenido en consideración, ya sea porque me han
aportado en ocasiones pequeñas ideas útiles, información sobre clases, sobre librerías, o ya sea para
desestimar ciertas líneas de actuación se encuentran las siguientes:
En primer lugar, la documentación más estudiada ha sido, sin duda, la proporcionada en las webs de
MySQL, Jakarta-Tomcat y las API’s de Java y JavaMail.
Además debo mencionar, clasificando por temas:
Java, general:
http://mindview.net/ , “Thinking in Java” de Bruce Eckel.
http://www.cica.es/formacion/JavaTut/Cap7/comunica.html , comunicación entre threads.
http://www.programacion.com/java/articulo/expresionesreg/ , expresiones regulares en Java.
http://www.programacion.com/java/tutorial/jdcbook/ , tutorial de Sun traducido al castellano sobre
uso de servlets y JDBC, sesiones, entre otros, con un ejemplo de una Casa de Subastas on line.
http://www.sc.ehu.es/sbweb/fisica/cursoJava/applets/javaBeans/fundamento.htm , introducción a
los JavaBeans.
http://www.lab.dit.upm.es/~lprg/material/apuntes/log/log.htm , sobre el uso de loggers para
depuración.
JavaMail:
http://www.javaworld.com/javaworld/jw-10-2001/jw-1026-javamail.html , introducción a la
funcionalidad de JavaMail.
http://www.jguru.com/faq/home.jsp?topic=JavaMail&page=3 , conocer Message-ID de un mensaje
antes de enviarlo.
http://www.echomountain.com/support/JavaMailAPI.html , autenticación en servidores SMTP que
lo requieren.
96
http://java.sun.com/products/javabeans/glasgow/jaf.html , información sobre JAF, Java Activation
FrameWork, usado por JavaMail.
http://www.jguru.com/forums/view.jsp?EID=1077307 , JavaMail y los proxies.
JSP:
http://www.ciberteca.net/articulos/programacion/arquitecturajsp/ , arquitectura JSP y acceso a
base de datos.
http://www.desarrolloweb.com/articulos/832.php , comparando JSP con ASP
http://www.programacion.com/foros/6/msg/49637/, breve respuesta a cómo controlar número de
sesiones abiertas.
http://www.javahispano.org/articles.print.action?id=83, depuración de errores en JSP. Posibilidad
de redigirir a una página de “error”.
http://www.codigoescrito.com/archivos/000075.html, sobre las ventajas e inconvenientes de
recuperar los datos en un array de campos. Una ventaja código más legible y rápido de crear y una
desventaja, si alteramos orden campos en la base de datos hay que retocar donde se reciba este array.
http://forums.devshed.com/search.php?searchid=241155, descarga de un attachment con JSP.
http://www.programacion.com/tutorial/jspyxml/ , tutorial de Sun traducido al castellano sobre el
desarrollo de aplicaciones web JSP y XML.
http://www.wmlclub.com/articulos/jsp.htm , ventajas de JSP frente ASP.
STRUTS:
http://struts.apache.org/ , descarga del framework, ejemplos , tutorial, FAQ’s, ...
http://programacion.com/java/tutorial/joa_struts/ , iniciación a Struts.
http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=strutsb , tutorial con una breve
aplicación de ejemplo.
http://www.reumann.net/struts/main.do , otro tutorial con ejemplos.
http://j2ee.masslight.com/index.html, tutorial de JSP , Struts y EJB’s. Detalla los principales tags
de Struts.
http://www.programacion.com/bbdd/articulo/ale_poolstruts/ , pool de conexiones en Struts.
http://www.informit.com/articles/article.asp?p=23734&redir=1 , configuración del descriptor strutsconfig.xml.
http://www.mmbase.org/download/builds/2003-0601/mmdocs/administrators/webxml
onfiguration.html , configuración descriptor web.xml.
JDBC:
http://www.programacion.com/java/tutorial/jdbc/ , tutorial de jdbc de Sun traducido al castellano.
97
http://dev.mysql.com/doc/connector/j/en/, sobre el conector JDBC de MySQL.
Javascript:
http://www.desarrolloweb.com/articulos/705.php?manual=26 , estudiando las librerías de funciones
de JavaScript.
http://javascriptkit.com/javatutors/re3.shtml , expresiones regulares en JavaScript.
Estudio de listas existentes:
http://www.phpbb.com/ , foros en PHP.
http://www.elistas.net/es/ , ejemplo de lista distribución donde estudiar estilo y características.
http://yahoo.es , analizando los Yahoo Groups.
http://www.mail-archive.com/, ejemplo de lista de distribución más sencillo que el mío, en aspecto
y funcionalidad
HTML:
http://www.duiops.net/curso/ , curso de html.
http://geneura.ugr.es/~pedro/dhtml/dhtml3.htm , estudio de los layers en HTML por si los
empleaba para mostrar mails largos haciendo correr la capa dejando fijo el cursor sobre un botón para
avanzar el scroll... al final se optó por hacerlo como en cualquier web: si mail es largo que vayan
haciendo el scroll vertical del navegador.
http://www.webexperto.com/articulos/articulo.php?cod=94 , idem. anterior layers y scroll.
http://www.baby.com.ar/doc/protocolos_correo.html , información sobre tipos MIME.
http://www.math.northwestern.edu/~mlerma/iworld/correo.html , idem sobre MIME.
http://www.w3.org/TR/REC-html40/interact/forms.html ,
explicado en profundidad, según el estándar de W3C.
controles de un formulario HTML
http://www.webexperto.com/articulos/articulo.php?cod=134 , sobre hojas de estilo en cascada, CSS.
Otros:
Muchas de estas direcciones ofrecían productos o tecnologías que yo no iba a emplear pero que me
llevaron a dirigirme a otros lugares.
http://bulma.net/body.phtml?nIdNoticia=770 , tutorial de expresiones regulares de PERL. Servía
como iniciación al tema.
http://www.hallogram.com/jmail/index.html , en mi búsqueda de información sobre envío de
correos encontré una utilidad de pago llamada Jmail que desestimé.
http://java.sun.com/products/javamail/Third_Party.html , utilidades de mail creadas por empresas
ajenas a Sun. En su mayoría de pago. Desestimadas.
98
http://cr.yp.to/immhf/thread.html , sobre como se realiza un seguimiento de un hilo de discusión:
Message-ID, References, In-Reply-To.
http://www.guiffy.com/diff_java_h.html , algoritmo diff en Java de comprobación de diferencias
entre dos ficheros de texto. Se rechazó por dos motivos: primero, porque al ser muy complejo era
también propenso a fallos, y porque comportaría un coste computacional alto teniendo en cuenta que
en mi proyecto se aplicaría en mensajes que no incorporen en su header los campos In-Reply-To o
References pero que aún así observáramos que refieren a algún otro mensaje leyendo su contenido.
¡Ello implicaría aplicar diff a esa mensaje y a los restantes de la base de datos!
http://www.oscookbook.com/index.pl/las_caractersticas_de_webgui ,
Perl, por lo tanto se aleja de mis intereses.
creación de foros emplea
http://www.karneim.com/jrexx/project01/project01.htm , librería de expresiones regulares para
java, llamado jrexx. Desestimado cuando descubrí que java dispone una desde la versión 1.4.
http://jpinedo.webcindario.com/doc-paginator.php , paginador de resultados en PHP. Buscaba uno
en jsp. No sirve.
http://www.glocksoft.com/ep , utilidad shareware que procesa y filtra de forma automática mensajes
de correo entrante. No me es útil.
http://www.cica.es/formacion/JavaTut/Cap9/smtp.html , implementación de un cliente mínimo de
SMTP mediante sockets y escribiendo uno mismo los comandos que espera el protocolo. Como
empleamos JavaMail, sería absurdo descender a ese nivel.
http://www.softonic.com/ie.phtml?n_id=9189 , Advanced Maillist Verify 4.25. Programa shareware
que verifica si las direcciones de e-mail son válidas. No es java.
http://www.programacion.com/java/articulo/paginacion_asp/, ejemplo paginación con ASP.
http://www.linux.or.cr/listas/archivo/gulcr_200002/msg00074.html, mensaje de una lista sobre la
Netiquette en foros y listas.
http://www.ucm.es/info/dsip/Docencia/P-Concurrente/monit.html , concurrencias.
http://www.programacion.com/tutorial/aplic_jsp/ , tutorial sobre crear aplicaciones web con
Tomcat-4 y MySQL.
SOFTWARE
Marco de trabajo de la aplicación:
•
j2sdk_1.4.2, Java ( jre no es válido, Tomcat necesita compilar clases)
•
jakarta-tomcat-5.0.24, contenedor de servlets.
•
MySQL 4.0.14, servidor y cliente de bases de datos.
•
Integrado en el WAR (Web Application Archive):
o
JavaMail, gestión de correo electrónico.
o
jakarta-struts 1.1, modelo vista-controlador, connection-pooling y uploading de
archivos de cliente a servidor.
99
Entorno de desarrollo:
•
JBuilder 9 en la compilación, depuración de Actions de Struts y clases Java, .
•
SQLYog v3.52 para consultas y modificaciones rápidas en la base de datos.
•
DreamWeaver MX para aspecto externo páginas JSP.
•
Paint Shop Pro 6.00 , en la elaboración del manual: retoque capturas imágenes, escala de
grises, redimensionar.
•
Pacestar UML Diagrammer Version 4.17, en la elaboración de los diagramas del manual.
Pruebas en los navegadores Explorer 6, Mozilla 1.5, Opera 7.23 bajo Windows XP, y Opera, Linux
y Konqueror bajo SuSE Linux 8.2 Pro. Las pruebas más exhaustivas se han realizado con Explorer
y Mozilla en Windows XP.
HARDWARE
El ordenador empleado en el desarrollo y los test ha sido un Athlon con 1GHz y 256MB bajo
Windows XP y SuSE 8.2. Principalmente bajo el primer sistema operativo. Funciona sin
problemas.
En un P-III 850 MHZ , 64MB y Windows XP , la aplicación iba forzada al compilar JSP porque el
sistema operativo dejaba poca memoria de trabajo. En el administrador de tareas java consumía por
término medio unos 15-19 MB ( más que por la aplicación, la memoria la ocupa Tomcat, el JVM...)
con picos de hasta 25 MB al compilar Tomcat JSP bajo demanda.
También se probó en un ordenador de la universidad bajo Windows 98, del cual no se recuerdan las
características pero creo recordar similares a la del Pentium III. Funcionaba bien.
100
8. MANUALES
8.1 INSTALACIÓN
La instalación es algo laboriosa, ya que no se trata tan solo de un ejecutable sino que se requiere
además un marco de trabajo asociado.
Al ser una aplicación Java que emplea MySQL y Tomcat, presentes en varias arquitecturas y
sistemas operativos, no debiera suponer una especial complicación instalarlo bajo Linux. Las
primeras pruebas se realizaron tanto en este sistema como en Windows. No obstante, hace tiempo que
centré su desarrollo bajo Windows XP.
La instalación ha sido probada en Windows 98 (universidad) y Windows XP. Todo el material
necesario se encuentra en el cedé.
Instalación en windows.
1. Si no existe en el sistema una versión de java 1.4.2 ó superior ( probamos en la línea de
comandos “java –version”) copiamos instalable en escritorio e instalamos java en directorio
C:\cuberes\jdk.
2. Si no existe en el sistema versión de jakarta-tomcat-5.0.24 ó superior: copiar zip en escritorio
y descomprimir en C:\cuberes.
(si existe tomcat, pero versión java es anterior a la 1.4.2 o no sabemos versión tomcat, realizar
pasos 1 y 2)
Establecer variables de entorno:
•
•
CATALINA_HOME=”c:\cuberes\jakarta-tomcat-5.0.24”
JAVA_HOME=”c:\cuberes\jdk”
En Windows NT y XP se establecen en: panel de control sistema opciones
avanzadas botón variables de entorno.
En windows 98, hay que editar el fichero autoexec.bat, cada línea anterior debe ir precedida
por SET.
3. Grabamos mysql-connector-java-3.0.11-stable-bin.jar en la carpeta de tomcat common\lib.
(struts-config.xml no lo ve si está en el WEB-INF\lib del WAR)
Desconozco si este archivo es válido para versiones de MySQL superiores a la 4.0.14.
4. Si no existe MySQL 4.0.14, copiar zip en escritorio, descomprimir en c:\cuberes\temp, ir a la
carpeta y ejecutar setup. Debe instalarse en c:\mysql (directorio por defecto).
En C:\mysql\bin hacemos clic en winmysqladmin. Si todo está correcto aparecerá un
semáforo verde en la barra de iconos. Si no, siempre podemos probar a arrancar el demonio
directamente en C:\bin\mysqld.exe
5. Script de base de datos:
No podemos inicializar la base de datos desde la aplicación, ya que lo primero que se lee es
struts-config.xml y en ella se hace mención a la base de datos pfcweb_sistema. Por lo tanto,
la base debe estar creada antes de arrancar el proyecto.
101
Cogemos el script creaBD.sql y la colocamos en C:\mysql\bin.
En la línea de comandos para C:\mysql\bin escribimos mysql. Se abre un cliente de mysql.
Escribimos “\. creaBD.sql”. Mostrará una serie de lineas conforme va creando las tablas.
Salimos con “quit”.
6. Coger el archivo PFC_Web_Struts.war y colocarlo dentro del directorio de tomcat webapps.
Funcionamiento
Arrancamos tomcat, en el directorio bin “startup”.
Abrimos el navegador e introducimos http://localhost:8080/PFC Web Struts/ (escrito así
PFC_Web_Struts) con lo que se pondrá en marcha la aplicación.
Una vez hechas todas las pruebas, cerramos Tomcat en el directorio bin con “shutdown”, porque no
basta con cerrar el navegador.
Nota para windows 98: es muy probable que bajo este sistema operativo, al intentar arrancar
tomcat, dé un error de insuficiente memoria para las variables de entorno. En tal caso deberemos
aumentarla mediante este comando en el CONFIG.SYS:
SHELL=c:\windows\command.com/E:1024/P. Y luego reiniciar.
En las peticiones a las páginas JSP podemos encontrar en principio una ligera lentitud (dependerá de
la memoria y la potencia de la máquina), ya que Tomcat para la primera vez que ejecuta una página,
compila un servlet que será quien atienda las peticiones. Este servlet lo guarda en su directorio de
trabajo, de forma que para siguientes peticiones a la misma página se accede directamente al servlet
y el tiempo de respuesta es mucho más rápido.
102
8.2 MANUAL DE USUARIO
Inicio
Página de inicio a nuestro servicio de listas de distribución. Se muestran todas las listas disponibles,
cada una con su nombre, una breve descripción, si es pública o privada, el número de mensajes que
contiene, el número de usuarios registrados a la misma y la fecha de recepción del último mail, o bien
si el mail ha sido recibido el mismo día, su hora de llegada.
Para obtener mayor información sobre la lista, pulse el link que aparece bajo la columna
“descripción”. Igualmente, los links bajo la columna “nombre” le dirigirán, en caso de tener acceso,
al listado con el total de mensajes existentes de la lista escogida.
Cabe indicar que usted al conectarse entra como “invitado”, lo cual le permite visitar únicamente las
listas públicas y sin posibilidad de introducir mensajes. Si desea un acceso pleno a todas las listas,
debe registrarse, para lo cual haga clic en el link de login y dese de alta.
Si ya es usuario registrado, entre en login igualmente e introduzca su login y password. En caso de
duda, pulse en ayuda cuando se encuentre ya en la página de login. Recuerde que en caso de dudas, en
cualquier página que visite encontrará el link “ayuda”.
103
Una vez registrado puede acceder a cualquier lista pública o privada si se ha dado de alta en ella. En la
imagen se observa un usuario con login “alex”. Al identificarnos y volver a esta página de inicio
observaremos que aparece un link al lado de nuestro login, “perfil”, con el que podemos acceder a
nuestra cuenta.
Login
Si usted ya es usuario registrado, introduzca su login y password. En caso contrario tiene dos
opciones:
La primera es pulsar en “volver” y mantenerse como usuario invitado, lo cual le permite visitar sólo
las listas de tipo público, sin posibilidad de escribir mensajes.
La segunda es darse de alta, haciendo clic en el link correspondiente en un proceso que no le llevará
ni treinta segundos. Siendo usuario registrado, podrá más adelante registrarse en las listas que le
interesen, escribir y leer mensajes desde nuestra web o desde su correo electrónico e incluso crear
su propia lista.
104
Alta usuario
En el momento de introducir sus datos personales requerimos como mínimo una dirección de correo
electrónico, el login con el que quiera identificarse para siempre y ser conocido por el resto de los
miembros de las listas a las cuales pertenezca y una contraseña. Sin completar estos campos, no
será posible darle de alta.
Una vez haya pulsado “ENVIA” ya estará registrado en nuestra web, y abierto la sesión con dicho
login. Observará entonces que la página cambia el nombre y pasa a llamarse de “Alta usuario” a
“Perfil usuario”, al mismo tiempo que aparecen junto a la pestaña de “datos personales” otras dos
llamadas “listas registradas” y “listas creadas”.
Para mayor información, lea la siguiente sección Modificación usuario. Si por el momento no
desea darse de alta en ninguna lista puede pulsar “inicio” que le llevará a la página principal donde
aparecerá no ya como “invitado” sino como el login que usted ha elegido.
105
Modificación usuario datos personales
En cualquier ocasión, ya sea justo en el momento de darse de alta por primera vez, como en cualquier
otro día que acceda a la web puede acceder a su perfil. Si acaba de darse de alta, ya ha sido dirigido
ahí. La primera página que se le muestra es la de sus datos personales, donde puede modificarlos o
bien gestionar su registro en listas o crear las suyas propias, si el servicio está disponible.
Dentro del apartado de datos personales puede modificar cualquier elemento que considere oportuno,
como un cambio en la dirección de correo electrónico o un cambio de password, o cualquier
equivocación que haya tenido y desee rectificar. Recuerde que hay unos campos mínimos que deben
ser rellenados y que no puede modificar el login que lo identifica exclusivamente a usted.
Cuando haya acabado, pulse en inicio. Si lo que desea es gestionar las listas a las que pertenece o
crear una propia, pulse para lo primero “listas registradas” y para lo segundo “listas creadas”.
106
Registro en listas
“Listas registradas” nos muestra las listados a las que estamos apuntados en la parte de arriba y a las
que podemos apuntarnos en la parte de abajo. La primera vez que entramos, no estamos registrados
en ninguna lista, por lo que bajo el título “Listas en las que estoy registrado” no aparecerá ninguna
fila. Para registrarse, basta que clique el link en forma de [X] perteneciente a la lista que le interese.
Si desea informarse antes, clique en el campo descripción de la lista.
Una vez registrado a la lista, que aparecerá ya en la parte de arriba, puede desregistrarse si se dio de
alta por equivocación o bien ha decidido que no quiere pertenecer a la lista y que tampoco desea
recibir ni enviar correos de la misma. Para ello pulse en la aspa [X] en “baja”.
Perteneciendo a una lista, puede leer sus mensajes aunque sea privada (privada se refiere a que
requiere registro incluso para su lectura), y puede también escribir en ella, ya sea desde nuestra web,
como a través de correo electrónico, siempre que el correo enviado coincida con el que usted nos ha
indicado en el apartado de datos personales.
Para escribir en una lista siempre hay que estar dado de alta en ella, ya sea pública o privada. Si no lo
está, desde nuestra web no se le permitirá redactar mensajes. Y externamente, cualquier mensaje con
dirección de correo electrónico no registrada en nuestra base de datos será ignorado. Exigimos
107
registro, para evitar el acceso incontrolado a las listas y evitar un mal uso por parte de elementos
como spammers.
Por último, si desea recibir en su dirección de correo electrónico todos los mensajes que son escritos
en la lista, clique en el aspa bajo la columna “estado mail”. Obsérvese que por defecto, al darse de
alta en una lista aparece como que no desea recibir los mensajes de la lista en su buzón de correo.
Aparece como un “No” de color rojo. Si pulsó sobre el aspa, cambiará a “Sí” en verde.
La decisión de recibir correo o no puede cambiarla cuando desee y es independiente de una lista a
otra. Puede disponer de supongamos cinco listas, y desear recibir correo en una, dos... todas o
ninguna.
Si ha terminado, vuelva a “inicio”. Si desea crear una lista o ver las listas creadas, pulse en “listas
creadas”.
Creación de listas
Podemos acceder a la lista directamente, o ver sus características, que podemos modificar, ya que
somos sus creadores.
El servicio de creación de listas puede estar desactivado momentáneamente. Si podemos crear una
lista nueva, aparecerá una imagen como en la siguiente página.
108
En ella, especificamos un nombre corto que sea lo más identificable posible con el tema sobre el que
deseamos crear la discusión. A mostrar junto al nombre de la lista en muchas páginas encontramos
una descripción breve.
Con el fin de poder explicar los fines de la lista de un modo más detallado, tenemos el campo
“comentario”. Los campos fundador de la lista, email de la lista (por si deseamos participar en la lista
externamente, mediante el correo electrónico) y fecha creación se rellenan automáticamente.
Por último decidimos si nuestra lista debe ser pública o privada. Si en algún momento decidimos
echarnos atrás, como en todas las altas, podemos pulsar el link “volver”. En caso afirmativo,
pulsamos el botón de alta.
Esto nos llevará a la misma página en modo de modificación, en la que podemos cambiar cualquiera
de los tres campos o el tipo de lista.
109
Desde muchas páginas que ofrecen una relación de listas de distribución podemos acceder a esta
página clicando en el campo “descripcion”. Si nosotros somos los fundadores de la lista, la
encontraremos en modo de modificación. Es por ejemplo el caso de haber creado la lista, volvemos a
la página con los campos automáticos ya rellenados. Las modificaciones únicamente se guardarán si
pulsamos en el botón de modificar.
De no ser los creadores de la lista, entramos en modo consulta, tal como muestra la anterior imagen
en la cual no es posible cambiar los campos, ni tampoco encontraremos ningún botón.
En ambos casos encontraremos una pestaña “usuarios registrados” donde se muestran los usuarios
de la lista.
110
La página de usuarios registrados a una lista es accesible a todos. En el caso que seamos el fundador
tendremos pleno derecho sobre el acceso de usuarios que a nuestro parecer no muestren la debida
consideración hacia los demás.
Esta misma página accedida por un usuario corriente no muestra los enlaces
“readmitir”, tal como veremos en la siguiente imagen.
111
“expulsar” y
Expulsión, readmisión de usuarios
En la captura anterior, usuarios registrados visto por el fundador, permite la expulsión y readmisión
de usuarios. El usuario expulsado no podrá enviar ni recibir la lista por correo electrónico, ni tampoco
escribir mensajes en la web. Si la lista es pública podrá leerla como cualquier usuario invitado, si es
privada no podrá acceder.
Página empleada para expulsar a alguien si se es fundador, así como para ver los motivos de su
expulsión, si se es usuario.
112
Si es fundador de la lista y va a expulsar un usuario, los tres primeros campos son rellenados
automáticamente. Usted debe indicar un motivo de su decisión. Al pulsar “modifica” la expulsión se
lleva a cabo. Siempre podrá readmitirlo más adelante. De haber entrado en esta página por error,
pulse en “volver”.
Un usuario no fundador puede consultar esta página, sin posibilidad de hacer cambios. El fundador
puede cambiar el texto con los motivos en cualquier momento.
113
Si el usuario expulsado accede a una lista se le mostrará una página, llamada de acceso que le
informará que ha sido baneado. Si la lista es pública podrá acceder, con los derechos limitados tal
como hemos comentado antes. Si la lista es privada, esta página le impide el acceso. De hecho esta
página también impide el acceso a los usuarios no registrados a una lista privada.
En el caso que un usuario no tenga acceso vía web a la lista de mensajes, tampoco podrá enviar
mensajes a través de un cliente de correo electrónico. De hacerlo, su mensaje no será incorporado en
la lista, y el remitente recibirá un correo informativo en el cual se le explicarán los motivos.
A continuación, veremos las listas en sí mismo.
114
Lista de mensajes
Al acceder desde el link con el nombre de la lista que puede encontrarse en muchas páginas, como la
de inicio, encontramos la página mostrada sobre el texto.
Podemos observar un panel para la ordenación o filtrado de la lista. Para la ordenación debemos
activar el cuadro de opción de “listado”, el mismo que se obverva en la imagen. El listado puede
mostrarse “normal” o “relacionado”, que es la forma de mostrar la relación entre los mensajes y sus
respuestas.
Por defecto, se muestra “normal” ordenado por fecha descendiente, con lo cual los mensajes más
recientes son los primeros a mostrarse. No obstante, puede cambiarse el orden de presentación,
“ascendente” o “descendente”. También existe la posibilidad de ordenar por otro campo que no sea
la fecha como puede ser los mostrados en el cuadro de lista: “de”, “asunto” o “tamaño”.
115
A continuación mostramos un ejemplo de listado relacionado:
Las cruces indican el nivel del mensaje dentro de lo que llamaremos el hilo de discusión, esto es, un
conjunto de mensajes relacionados entre sí. El primer mensaje que inicia la cadena, será de nivel uno,
por lo que no mostrará ninguna cruz. Quienes responda a este primer mensaje tendrán “++”. Si
luego a su vez son respondidos, el mensaje de respuesta tendría “+++”, etcétera.
Si lo que deseamos es filtrar los resultados ya que buscamos un mensaje o conjunto de mensajes.
Tenemos la posibilidad de hacerlo también por los campos de “fecha”, “de”, “asunto” o “tamaño” y
ordenarlos en orden ascendente o descendente.
116
En este ejemplo buscamos por fecha. Los filtrados por fechas o por tamaño son por un rango,
mientras que para “de” o “asunto” se introduce en el campo “contiene” del formulario la palabra que
buscamos.
En este caso, al ser únicamente 9 registros, no mostramos el índice de páginas.
Como el usuario ha entrado en una lista pública sin registrarse, no puede introducir mensajes nuevos
ni responder a los existentes. Sí puede leerlos, clicando en el enlace bajo la columna “asunto”.
Mostramos ahora un ejemplo, de la ventana para un usuario registrado que busca registros que
procedan de remitentes que contengan la letra elle.
117
A la izquierda del remitente, vemos unos clips para los mensajes que tienen algún adjunto. También
podemos observar que al entrar como usuario registrado aparece un link para introducir un mensaje
nuevo.
118
Mensaje
Página que aparece tras clicar “Redactar nuevo mensaje”. Si no deseamos finalmente enviar ningún
mensaje, podemos clicar en “volver”. Para enviar un adjunto, puede escribirse la ruta directamente
en el campo “adjunto” o bien abrir una ventana para movernos por los directorios de nuestro
ordenador pulsando el botón “Examinar...”.
La página es la misma si el mensaje a componer es respuesta de un mensaje anterior en la lista, con la
salvedad que el asunto tendrá un formato de la forma "Re[..]:.. (asunto original)", que puede variarse,
y en el contenido aparecerá el mensaje original.
Después de pulsar en “ENVIA” se nos informará que el mensaje ha sido enviado, con lo cual
podremos volver a la lista o bien redactar otro mensaje. El mensaje enviado se mostrará en la web y
se enviará por correo a todos los usuarios que hayan solicitado dicho servicio, salvo al remitente del
mensaje.
Si en la lista, clicamos sobre el mensaje, nos mostrará la siguiente página:
119
Los links “anterior” y “siguiente” son para movernos por los mensajes a través de la lista. En este
caso, este mensaje es el primero de la lista, ya que nos encontramos en una lista con sólo 2 mensajes
ordenada en descendiente. Por ello, el link a anterior está desactivado. Podemos movernos a través
de la lista entera pulsando estos dos links. Si nos encontramos al final de una página y seguimos
pulsando siguiente, automáticamente saltamos a la página que sigue, y cuando volvamos a la lista nos
mostrará la página donde se encuentra el último mensaje que examinamos. Igualmente sucede con
anterior.
Otros links son “inicio”, que nos llevaría a la página inicial, “lista” que nos devuelve a la página
anterior, y “responder” para contestar el mensaje.
Como este mensaje incluye un adjunto, aparece un cuadro donde se muestra su nombre y tamaño y un
botón para descargarlo, si el usuario lo desea.
Supongamos que deseamos responder a este mensaje, entonces nos llevará a la página de redacción
de mensajes donde automáticamente el asunto estará encabezado por un “Re:” y aparecerá el texto
120
del mensaje que respondemos precedido por “>” en cada línea. Si lo que replicamos es ya un “Re:”
entonces nos aparecerá “Re[2]:”, y si el mensaje es de nivel n, “Re[n]”.
Al volver, si el listado estaba relacionado, encontrará su mensaje que aparece dependiente del
mensaje que respondió.
Todos los mensajes, procedan de un listado “normal” o “relacionado” muestran el hilo de discusión
(grupo de mensajes relacionados) al que pertenecen, de pertenecer a alguno. En la imagen anterior,
el mensaje no pertenece a ningún hilo.
En esta imagen podemos observar el final de la página de un mensaje que pertenece a un hilo. El
mensaje al que hemos accedido se muestra en negrita. Los hilos se pueden “EXTENDER” con lo cual
vemos el total de mensajes del hilo en una sola página. También podemos pulsar en un mensaje en
concreto, o movernos entre los mensajes
Hay que señalar que los links “anterior” y “siguiente” de un mensaje nos permiten navegar por el
listado de mensajes que no tiene por qué coincidir con el listado del hilo. Si provenimos de un listado
relacionado sí coincidirá, pero también podemos venir de un listado al que se le ha aplicado un filtro,
por ejemplo.
Si lo que deseamos es navegar entre los mensajes del hilo , podemos hacerlo clicando en cualquiera
de los enlaces del hilo. En este caso accedemos a una página similar a la anterior, pero que tiene como
121
título “Recorrido del hilo”. En ese caso, al pulsar “anterior “ o “siguiente” sí nos moverá entre los
mensajes de dicho hilo. Cuando queramos volver al modo anterior, pulsar en “volver”.
Listado archivos
Desde la página de listado de mensajes, haciendo click sobre “archivos”
El panel de búsqueda de los registros es similar al que se encuentra en el listado de mensajes, por lo
que no merece más comentarios que el señalar que al buscar por “nombre” o “tamaño”, nos
referimos a los atributos del adjunto, y no del mensaje.
Para cada archivo, tenemos dos enlaces, el de más a la izquierda permite la descarga del archivo, y el
de la derecha acceder al mensaje que adjuntaba el archivo.
122
9. IMPLEMENTACIÓN EN SOPORTE FÍSICO
En CD-ROM se incluye:
•
todo lo necesario para la instalación bajo Windows.
•
archivo .WAR comprimido y compilado.
•
directorio PFC_Web_Struts, que es el WAR descomprimido y con el código fuente en su
directorio src.
•
este manual.
123

Documentos relacionados