arquitectura software sistema integral de asignación de … · 2018-10-17 · arquitectura...
Post on 12-Apr-2020
4 Views
Preview:
TRANSCRIPT
-
ARQUITECTURA SOFTWARE
Sistema Integral de Asignación de Recursos
(SIAR)
CONTROL DOCUMENTAL
Elaborado por:
Objeto:
Descripción de información relevante que permita comprender la arquitectura,
diseño y construcción de la aplicación, orientado al mantenimiento por parte de
los desarrolladores.
Versión Descripción
1.0 Primera versión del documento
Lista de distribución:
CONTROL DE CAMBIOS
Fecha Versión Autor Página Cambio
Primera versión del documento
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
2/59
INDICE DE CONTENIDO
1. OBJETIVO DEL DOCUMENTO .................................................... 3
2. DESCRIPCIÓN FUNCIONAL DE LA APLICACIÓN. ...................... 3
3. ARQUITECTURA Y DISEÑO ....................................................... 3
3.1. Repositorio de documentación y modelado .............................. 25
3.2. Diagramas de arquitectura .................................................... 25
3.3. Diagramas y patrones de diseño ............................................ 25
3.4. Decisiones arquitecturales y de diseño .................................... 29
3.5. Módulos/componentes: funcionalidad y relaciones.................... 33
3.6. Frameworks, librerías y tecnologías utilizadas .......................... 34
3.7. Prototipado de pantallas ....................................................... 34
4. CONSTRUCCIÓN, DESPLIEGUE Y EJECUCIÓN ......................... 35
4.1. Requisitos del puesto del desarrollador ................................... 35
4.2. Repositorios de código y gestión de versiones ......................... 37
4.3. Puesta en funcionamiento en el puesto del desarrollador .......... 38
4.4. Pruebas unitarias y de integración ......................................... 57
4.5. Generación de librerías ......................................................... 58
4.6. Logs y trazas de la aplicación ................................................ 58
4.7. Otros sistemas externos ....................................................... 58
4.8. Best practices ...................................................................... 58
5. INCIDENCIAS Y PARTICULARIDADES TÉCNICAS ................... 59
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
3/59
1. OBJETIVO DEL DOCUMENTO
El objetivo del documento es reflejar toda información relevante que permita
asimilar la arquitectura, diseño y construcción de una aplicación, orientado a
los arquitectos y desarrolladores que pasen a realizar el mantenimiento de dicha
aplicación.
A partir de este documento también deben entenderse las principales decisiones
tomadas en dichos ámbitos.
Así mismo, con la información aquí contenida un desarrollador cualquiera debería
ser capaz de poner en funcionamiento dicha aplicación en su propio PC (con
aisladas excepciones que habría que justificar a Metro).
Por último, indicar que parte de la información que interesa para el
mantenimiento del desarrollador es común con la información que le pueda
interesar a otras áreas. En ese caso, desde este documento se deberá referenciar
el lugar en el que se encuentra dicha información, evitando su duplicación.
Únicamente si no es información que afecta exclusivamente al desarrollador
podrá incluirse fuera del presente documento, y en todo caso siempre
validándolo con Metro.
2. DESCRIPCIÓN FUNCIONAL DE LA
APLICACIÓN.
Información incluida en el manual común de arquitectura.
3. ARQUITECTURA Y DISEÑO
Las tecnologías con las que cuenta SIAR son diversas y en cada capa se usan
distintas de ellas. Además, SIAR de divide en 2 aplicaciones: una aplicación
basada en Web (cliente ligero) y otra aplicación de Escritorio (cliente pesado).
El lenguaje de programación principal de la aplicación es Java aunque se juntan
otros lenguajes como SQL, XML, HTML, CSS, Javascript y C++.
Un Mapa de las tecnologías usadas en la parte Web se puede ver a continuación:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
4/59
Y el mapa de las tecnologías del cliente pesado es:
Spring
La arquitectura tiene como eje central Spring Framework, que proporciona una
gran cantidad de funcionalidades y sobre todo nos permite integrar los diferentes
frameworks de una manera cómoda. La mayor parte de los objetos creados
dentro de la arquitectura son tratados como beans de Spring que serán
declarados mediante anotaciones (@Service).
Spring (2.5.6) –
http://static.springsource.org/spring/docs/2.0.x/reference/index.html
Capa de Presentación
La tecnología en la que se basa la capa de presentación del cliente Web es JSF
apoyada en Facelets, que permite uso de plantillas y la posibilidad de creación
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
5/59
de componentes “a medida”, y la librería de componentes Richfaces, que
proporcionan soporte Ajax incorporado.
Además, JSF se encuentra totalmente integrado mediante Spring por lo que los
managed beans son tratados como beans de Spring.
JSF (1.2_12) - http://java.sun.com/javaee/javaserverfaces/reference/api/
Facelets (1.1.14) - https://facelets.dev.java.net/nonav/docs/dev/docbook.html
Richfaces (3.3.3 Final) –
http://docs.jboss.org/richfaces/latest_3_3_X/en/devguide/html/
Por otro lado, para el cliente Pesado (cliente Escritorio) se utiliza la tecnología de
Java Swing. Esta tecnología proporciona unos componentes de escritorio
gráficos y un control sobre la forma de presentarlos (según Look&Feel) y los
eventos que se producen desde las pantallas (Event Dispatcher Thread).
Además se apoya en una librería extendida de componentes SwingX de
SwingLabs y AppFramework.
Java Swing (versión JDK 1.6.0_XX) –
http://docs.oracle.com/javase/tutorial/uiswing/index.html
SwingX SwingLabs (1.0) – http://swingx.java.net/
AppFramework (1.03) – http://java.net/projects/appframework/
Capa de Negocio
La capa de negocio engloba, como su propio nombre indica, toda la lógica de
negocio por lo que aquí es donde residirán los BS o servicios de negocio. Estos
BS serán tratados como beans de Spring y serán declarados mediante la
anotación @Service. Toda esta capa de BS es usada por el cliente Web.
El Motor de Asignación tiene su propia capa de negocio que invoca a las reglas y
las librerías dinámicas de CP, CPLEX y la propia de SIAR mediante Java Native
Interfaces (JNI).
Aparte, existe un proyecto de negocio común (siar-negocioComún) que tiene la
lógica de negocio necesaria tanto para la parte Web como la parte cliente
Pesado/Motor.
En la capa de negocio se Realizan invocaciones a las reglas de JRules que son
las que determinarán el flujo de negocio a seguir en cada petición,
comunicándose ésta a su vez con el negocio.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
6/59
ILOG JRules (7.1.1) – http://www-01.ibm.com/software/integration/business-
rule-management/jrules/
JNI (version JDK 1.6.0_XX) –
http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html
Capa de acceso a datos
La capa de acceso a datos es la encargada de la comunicación con las diferentes
bases de datos de las que dispone la aplicación. En nuestro caso serán dos, SIAR
y Cognos. Los objetos encargados de acceder a ellas son los DAOs (Data Acces
Object) apoyados en la tecnología Hibernate que permite realizar mapeos entre
entidades de bases de datos (ORM- Object Relational Mapping) y objetos.
Además, con esta capa se consigue abstraer a los desarrolladores de problemas
como las conexiones, la transaccionalidad, etc.
Hibernate (3.2.6GA) –
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/
Capa de Seguridad
Esta capa está integrada en la capa de Presentación, pero por su magnitud e
importancia se explica como si de una capa se tratara.
Para su implementación se ha usado una Spring Security y una librería
propietaria de Metro que integra AccessManager con Spring Security.
El agente de AccessManager es un software externo a SIAR que intercepta las
peticiones Web a SIAR y se comunica con SIAR a través de la librería de Metro.
Spring Security se encarga de filtrar las acciones en la aplicación según las
autorizaciones disponibles para el usuario registrado.Spring Security
(2.0.5.RELEASE) – http://static.springsource.org/spring-security/site/
Librería Metro AccessManager-Spring Security (1.0.0) –
https://ciserver.metromadrid.net/xwiki/bin/view/Proceso%20Desarrollo%20Soft
ware/SpringSecuritySunAM
Conexión entre capas
La conexión entre capas se realiza mediante inyección de dependencias. Este
mecanismo está proporcionado por Spring al que solo tenemos que indicarle los
atributos del objeto que queremos que sean inyectados con una instancia. Para
indicar esta necesidad se antepone la anotación @Resource al atributo.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
7/59
En los proyectos que no están en contexto Spring, la obtención de un objeto de
Spring se realiza mediante una utilidad implementada en SIAR
(ApplicationContextProvider).
A continuación, se presentan una serie de diagramas que facilitarán el
entendimiento de ciertas partes de la aplicación que son complejas.
Además, viene una tabla de referencia a los diversos diagramas mostrados en
este apartado para facilitar su búsqueda.
Tabla de Diagramas
Diagrama 1: Fábrica Periodos ....................................................................... 8
Diagrama 2: Gestor de Conexiones, Manejador Gestores y cacheo .................. 10
Diagrama 3: Cálculo de Vacaciones ............................................................. 11
Diagrama 4: "Proxy" beans de Spring y el TransactionInterceptor. .................. 13
Diagrama 5: Interceptores de BS y DAO para la gestión de Excepciones. ......... 14
Diagrama 6: Ejecución Asíncrona (Cola JMS). ............................................... 15
Diagrama 7: Anotación @ReadOnly. ............................................................ 16
Diagrama 8: Diagrama Clases Procesado de Eventos de Condición del Agente .. 17
Diagrama 9: Diagrama representando la conexión con JRules ........................ 19
Diagrama 10: Diagrama de la carga del Contexto Spring en Cliente Pesado ..... 20
Diagrama 11: Acceso a Datos del Cliente Pesado y Transaccionalidad.............. 21
Diagrama 12: JNI Motor Asignación ............................................................ 23
Diagrama 13: Comandos del Motor de Asignación. ........................................ 25
Factorías de objetos Motor
Estas factorías obedecen al patrón Factory Method y se utilizan para construir
objetos de determinadas entidades que usa el Motor de Asignación.
Entre los objetos que se crean son IPeriodo, IIntervalo, IAsignacionPuestos, etc.
El patrón Factory Method usado en SIAR sirve para crear distintos tipos de
objetos con fábricas distintas pero encapsulando su creación por medio de una
interfaz IFactoria. La diferencia con el patrón original es que el aplicado tiene
más niveles de herencia debido a la gran diversidad de entidades que tiene SIAR.
Aparte su utiliza una interfaz en vez de una clase abstracta como entidad padre
de la fábrica.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
8/59
En el diagrama de a continuación, se puede ver un ejemplo de cómo se utilizan
las fábricas en SIAR. Para ejemplo, se ha utilizado la fábrica de periodos debido
que además añade una mayor complejidad al heredar los periodos de los
intervalos. El diagrama no muestra ciertos métodos que no añaden información
sobre lo que se quiere mostrar:
Diagrama 1: Fábrica Periodos
Gestor de Conexiones, Manejador Gestores y cacheo
Esta utilidad tiene un funcionamiento difícil de ver debido a la cantidad de
dependencias y herencias que existen. A través del diagrama que se presenta se
puede apreciar la funcionalidad que cumple.
Las interfaces/clases más importantes son:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
9/59
- IGestorConexiones: se encarga de inicializar el manejador de gestores y
de proporcionar un acceso a dicho manejador. Este objeto suele crearse
una única vez y se pasa por parámetro en muchos métodos y
constructores de las clases del Motor, entre ellos los propios gestores de
cada entidad.
- IGestor: interfaz que debe implementar todos los gestores de cada
entidad.
- IManejadorGestores: maneja las instancias de los gestores haciendo uso
de una caché que verifica que el gestor demandado no está pedido.
Devuelve un gestor a partir de su java.lang.Class. Además, realiza lo
mismo para las factorías.
- CacheInstanciasGestor: clase utilidad que se vale del manejador para
obtener un gestor. Internamente, esta clase mira si tiene el gestor
cacheado, sino lo tiene se lo pide al GestoresFactory.
- GestoresFactory: fábrica de gestores a partir de la clase y una serie de
parámetros usados para la creación del gestor. Todos sus métodos son
estáticos y su constructor privado, por lo que se evita su instanciación.
- IFactoriaCacheInstanciasGestor: fábrica de la caché de las instancias de
los gestores que es usado para crear su propia instancia de la caché del
manejador de gestores. La caché la puede crear dependiendo de los
parámetros que se le pase ya que tiene sobrecarga del método de creación
propio de caché.
El diagrama queda así:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
10/59
class Gestor Conexiones
«interface»
IGestorConexiones
+ cerrarConexion() : void
+ getId() : long
+ resetManejadorGestores() : void
+ getManejadorGestores() : IManejadorGestores
+ setManejadorGestores(IManejadorGestores) : void
+ manejadorGestoresInicializado() : boolean
+ inicial izarManejadorGestores(IPeriodo, ICategoria, boolean) : void
+ inicial izarManejadorGestores(IPeriodo, List, boolean) : void
+ inicial izarManejadorGestores() : void
+ inicial izarManejadorGestores(IPeriodo) : void
+ inicial izarManejadorGestores(IPeriodo, boolean) : void
+ inicial izarManejadorGestores(IPeriodo, ICategoria) : void
+ inicial izarManejadorGestores(IPeriodo, List) : void
+ inicial izarManejadorGestores(ITipoAsignacion, IPeriodo, ICategoria, boolean) : void
+ getCacheoCondicionAgente() : boolean
+ setCacheoCondicionAgente(boolean) : void
«interface»
IManejadorGestores
+ getGestor(Class) : IGestor
+ getGestor(Class, boolean) : IGestor
+ getFactoria(Class) : IFactoria
+ getPeriodo() : IPeriodo
+ resetCacheGestores() : void
+ resetRelaciones() : void
+ reinicializarCacheInstanciasGestor(IGestorConexiones, IPeriodo) : void
«interface»
IGestor
+ iterator() : java.util.Iterator
+ get(IEntidadBase.IKey) : IEntidadBase
+ getGestorConexiones() : IGestorConexiones
«interface»
java.io.Serializable
GestorConexiones
+ cerrarConexion() : void
+ getId() : long
+ resetManejadorGestores() : void
+ getManejadorGestores() : IManejadorGestores
+ setManejadorGestores(IManejadorGestores) : void
+ manejadorGestoresInicial izado() : boolean
+ inicial izarManejadorGestores(IPeriodo, ICategoria, boolean) : void
+ inicial izarManejadorGestores(IPeriodo, List, boolean) : void
+ inicial izarManejadorGestores() : void
+ inicial izarManejadorGestores(IPeriodo) : void
+ inicial izarManejadorGestores(IPeriodo, boolean) : void
+ inicial izarManejadorGestores(IPeriodo, ICategoria) : void
+ inicial izarManejadorGestores(IPeriodo, List) : void
+ inicial izarManejadorGestores(ITipoAsignacion, IPeriodo, ICategoria, boolean) : void
+ getCacheoCondicionAgente() : boolean
+ setCacheoCondicionAgente(boolean) : void
ManejadorGestoresBasico
# _gestores: CacheInstanciasGestor
# _factoriaCacheInstanciasGestor: IFactoriaCacheInstanciasGestor
- _relaciones: CacheRelaciones
- _periodo: IPeriodo
- _cacheargestores: boolean
- _gestorConexiones: IGestorConexiones
+ ManejadorGestoresBasico(GestorConexiones, IPeriodo, boolean)
+ getGestor(Class) : IGestor
+ getGestor(Class, boolean) : IGestor
+ getFactoria(Class) : IFactoria
+ getPeriodo() : IPeriodo
+ resetCacheGestores() : void
+ resetRelaciones() : void
+ reinicializarCacheInstanciasGestor(IGestorConexiones, IPeriodo) : void
ManejadorGestoresFSC
+ ManejadorGestoresFSC(GestorConexiones, IPeriodo, ICategoria, boolean)
CacheInstanciasGestor
- MAPEOS_EXPLICITOS: Object[][] {readOnly}
- _gestorConexiones: IGestorConexiones
- _periodo: IPeriodo
- _categorias: List
- _classLoader: ClassLoader
- _gestores: java.util.Map
- _gestoresPorVo: java.util.Map
+ CacheInstanciasGestor(IGestorConexiones, IPeriodo, ICategoria, ClassLoader)
+ getGestorConexiones() : IGestorConexiones
+ getPeriodo() : IPeriodo
+ getGestor(String, boolean) : IGestor
# creaGestor(String, boolean) : void
«interface»
IFactoriaCacheInstanciasGestor
+ creaCacheInstanciasGestor(IGestorConexiones, IPeriodo, ClassLoader) : CacheInstanciasGestor
+ creaCacheInstanciasGestor(IGestorConexiones, IPeriodo, ICategoria, ClassLoader) : CacheInstanciasGestor
+ creaCacheInstanciasGestor(IGestorConexiones, IPeriodo, List, ClassLoader) : CacheInstanciasGestor
«final»
GestoresFactory
- GestoresFactory()
+ getGestor(Class, IPeriodo) : IGestor
+ getGestor(Class, GestorConexiones, ICategoria, IPeriodo) : IGestor
+ getGestor(Class, GestorConexiones, IPeriodo) : IGestor
+ getGestor(Class, GestorConexiones) : IGestor
+ getGestor(Class) : IGestor
+ getGestorGenerico(Class, Class[], Object[]) : IGestor
FactoriaCacheInstanciasGestor
+ FactoriaCacheInstanciasGestor()
+ creaCacheInstanciasGestor(IGestorConexiones, IPeriodo, ClassLoader) : CacheInstanciasGestor
+ creaCacheInstanciasGestor(IGestorConexiones, IPeriodo, ICategoria, ClassLoader) : CacheInstanciasGestor
+ creaCacheInstanciasGestor(IGestorConexiones, IPeriodo, List, ClassLoader) : CacheInstanciasGestor
Diagrama 2: Gestor de Conexiones, Manejador Gestores y cacheo
Cálculo de Vacaciones
Para la funcionalidad del cálculo de vacaciones se ha implementado un patrón
Observer para la ejecución asíncrona.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
11/59
La particularidad que tiene este cálculo es que puede ser invocado desde el
aplicativo Web o desde el Motor de Asignación por lo que tiene que presentar
comportamientos distintos, ya que en Web su ejecución es asíncrona mientras
que en Motor su ejecución es síncrona.
Como punto común está el método de siar-negocioComun
calculoVacaciones.calcularVacaciones. Este método es invocado desde Motor y
Web con la única diferencia que desde la parte de negocio de Web se le invocará
con un Observer informado. El objeto observable notificará a su observador
cuando establece un nuevo mensaje al proceso asíncrono. Si no tiene observador
(caso ejecución desde el Motor) no se realizará la escritura del mensaje en
BBDD.
El diagrama se presenta a continuación: class Cálculo Vacaciones
«interface»
CalculoVacacionesBS
+ calcularVacaciones(ConsultaCalculoVacacionesVo) : void
ConsultaCalculoVacacionesVo
- categoriaVo: ICategoriaVo
- fechaInicio: java.util .Date
- fechaFin: java.uti l.Date
+ ConsultaCalculoVacacionesVo()
+ getCategoriaVo() : ICategoriaVo
+ setCategoriaVo(ICategoriaVo) : void
+ getFechaInicio() : java.uti l.Date
+ setFechaInicio(java.uti l.Date) : void
+ getFechaFin() : java.util .Date
+ setFechaFin(java.util .Date) : void
CalculoVacacionesBSImpl
+ calcularVacaciones(ConsultaCalculoVacacionesVo) : void
CalculoVacaciones
+ calcularVacaciones(ConsultaCalculoVacacionesVo, java.util .Observer, java.lang.Long) : boolean
- calcularVacacionesAsincrono(ConsultaCalculoVacacionesVo, java.uti l.Observer, java.lang.Long) : boolean
CalculoVacacionesObserv er
+ udpate(java.util .Observable, Object) : void
CalculoVacacionesObserv able
- mensajeRegistroAsignacionAsincronoVo: IMensajeRegistroAsignacionAsincronoVo
+ getMensajeRegistroAsignacionAsincronoVo() : IMensajeRegistroAsignacionAsincronoVo
+ setMensajeRegistroAsignacionAsincronoVo(IMensajeRegistroAsignacionAsincronoVo) : void
jav a.util.Observ able
+ addObserver(java.uti l.Observer) : void
+ setChanged() : void
+ notifyObservers() : void
«interface»
java.util.Observer
+ udpate(java.util .Observable, Object) : void
«interface»
RegistroAsignacionAsincronoBS
+ crearMensajeAsignacionAsincrono(String, String) : int
Diagrama 3: Cálculo de Vacaciones
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
12/59
Spring y Transaccionalidad Web
SIAR cuenta con gran cantidad de beans de Spring. En este apartado se explica
como funcionan los beans de los BS, que son similares a los beans de los DAOs,
excepto que el tipo de atributo para la transacción es distinto, es decir, los BS
crean las transacciones y los DAOs sólo pueden unirse a una transacción ya
existente.
Al arrancar la aplicación Web se inicia la carga del contexto de Spring. Durante
esta carga se van creando los beans de los BS y DAOs.
Cuando se crea un bean de Spring se crea una instancia de una clase “Proxy”
que internamente tiene la instancia del objeto bean. Esta instancia del objeto
bean es única en toda la aplicación (“singleton”).
Este “Proxy” contiene todos los métodos públicos que provee la interfaz del bean
de Spring. Esto es porque el tipo de “Proxy” que se usa en SIAR son los
JdkDynamicProxy.
La clase “Proxy” almacena la instancia del bean en un objeto
JdkDynamicAopProxy, que tiene la implementación para invocar a un método de
un bean pasando por los interceptores. Para ello utiliza un objeto de la clase
AdvisedSupport donde están almacenados los interceptores (advisors) y una
instancia de SingletonTargetSource (targetSource), donde ya se encuentra la
instancia del objeto bean.
Cada vez que desde una ManagedBean invoca a un BS, realmente está
invocando a su “Proxy” que se encarga de pasar por todos los interceptores,
entre ellos el interceptor de la transacción.
El Interceptor de la transacción (SiarTransactionInterceptor) envuelve la
invocación al método del BS, invocando previamente al TransactionManager para
crear la transacción (si no existe) y controlando la salida del método para que en
caso de excepción realice un rollback. Si todo ha ido correctamente realiza un
commit.
Se puede apreciar toda la estructura de clases anteriormente mencionada en la
siguiente imagen, que servirá para futuros diagramas ya que recoge la parte de
creación de los beans de Spring:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
13/59
class Transaccionalidad Web
managedbeans BusinessServ ices
jav a.lang.reflect.Proxy
- h: java.lang.reflect.InvocationHandler
«interface»
java.lang.reflect.InvocationHandler
+ invoke(Object, Method, Object[]) : Object
«interface»
java.lang.Serializable
«interface»
AopProxy
«final»
JdkDynamicAopProxy
- advised: AdvisedSupport {readOnly}
+ invoke(Object, Method, Object[]) : Object
Adv isedSupport
~ targetSource: TargetSource
- advisors: java.util .List
- interfaces: java.util .List
ProxyCreatorSupport
- listeners: java.util .List
«interface»
TargetSource
+ getTargetClass() : Class
+ isStatic() : boolean
+ getTarget() : Object
+ releaseTarget(Object) : void
ProxyConfig
~ exposeProxy: boolean = false
- proxyTargetClass: boolean = false
- active: boolean = true
ProxyFactory
+ getProxy() : Object
SingletonTargetSource
- target: Object {readOnly}
+ getTargetClass() : Class
+ isStatic() : boolean
+ getTarget() : Object
+ releaseTarget(Object) : void
«interface»
MethodInterceptor
+ invoke(MethodInvocation) : Object
TransactionAspectSupport
- transactionInfoHolder: TheadLocal {readOnly}
- transactionManager: PlatformTransactionManager
- transactionAttributeSource: TransactionAttributeSource
# createTransactionIfNecessary(TransactionAttribute, String) : TransactionInfo
# commitTransactionAfterReturning(TransactionInfo) : void
# completeTransactionAfterThrowing(TransactionInfo, Throwable) : void
TransactionInterceptor
+ invoke(MethodInvocation) : Object
SiarTransactionInterceptor
+ invoke(MethodInvocation) : Object
«invocación interceptada»
Diagrama 4: "Proxy" beans de Spring y el TransactionInterceptor.
Gestión Excepciones
Para la gestión de excepciones se utilizan interceptores en los BS y en los DAOs.
Estos interceptores tienen una doble funcionalidad: envolver la invocación al
método del BS o DAO en un try-catch para transformar la excepción a una
TecnicaException en el caso de los DAOs; y crear los logs de entrada y salida a
los métodos.
Con ello se consigue que todas las excepciones ocurridas durante la ejecución de
un DAO sean de tipo TecnicaException puesto que se realiza una transformación
a una de ese tipo.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
14/59
Para el caso de los BS, simplemente tira la excepción capturada, por lo tanto las
excepciones posibles pueden ser de tipo NegocioException o TecnicaException.
Estas excepciones llegan a los ManagedBeans que deben realizar un tratamiento
dependiendo del tipo de la excepción capturada.
A continuación se presenta el diagrama para mayor comprensión:
class Gestion Excepciones
«interface»
MethodInterceptor
+ invoke(MethodInvocation) : Object
«interface»
MethodInvocation
+ getMethod() : Method
BSMethodInterceptor
- C_1000000F: float = 1000000f {readOnly}
- LOGGER: Log {readOnly}
- DECIMAL_FORMAT: DecimalFormat = "0.0" {readOnly}
+ BSMethodInterceptor()
+ invoke(MethodInvocation) : Object
ProxyConfig
Adv isedSupport
~ targetSource: TargetSource
- advisors: java.util .List
- interfaces: java.uti l.List
DaoMethodInterceptor
- C_1000000F: float = 1000000f {readOnly}
- LOGGER: Log {readOnly}
- DECIMAL_FORMAT: DecimalFormat = "0.0" {readOnly}
+ DaoMethodInterceptor()
+ invoke(MethodInvocation) : Object
Diagrama 5: Interceptores de BS y DAO para la gestión de Excepciones.
Asincronía y JMS
Para el asincronismo se utiliza una cola JMS proporcionada por el servidor de
aplicaciones Weblogic Server 11g.
Además, Spring proporciona una serie de clases que facilitan esta integración, en
concreto JmsTemplate102 que es una clase que crea la conexión y sesión con la
cola JMS. También es la encargada de enviar la información a la cola.
Para la implementación en SIAR, se ha hecho uso de un interceptor,
AsynchronousInterceptor, que solo aplica a los BS. Este interceptor comprueba
que el método a ejecutar tenga la anotación @Asynchronous, en tal caso usa la
clase AsyncMessageSender para enviar un mensaje. Este mensaje tiene toda la
información necesaria para que luego, cuando la lea el listener
(AsyncMessageListener), pueda ejecutar el mismo método del BS pero esta vez
de forma síncrona. Entre los datos que envía el mensaje es el nombre de la clase
BS, el nombre del método, los tipos de los parámetros y los valores de los
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
15/59
parámetros. De esta forma, por reflexión, puede volver a crear el método a
invocar.
Por último, el listener se queda escuchando a que le lleguen mensajes, cuando le
llega decodifica el mensaje para crear el objeto y método a invocar y lo ejecuta.
Durante esta invocación se hace un tratamiento especial de las posibles
excepciones producidas por la ejecución para establecer estados consistentes en
Base de Datos para el proceso ejecutado.
El diagrama facilita el entendimiento de la comunicación a la cola JMS y la
ejecución asíncrona:
class Asincronia y JMS
«interface»
MethodInterceptor
+ invoke(MethodInvocation) : Object
«interface»
MethodInvocation
+ getMethod() : Method
AsynchronousInterceptor
+ invoke(MethodInvocation) : Object
- isMethodAynchronous(MethodInvocation) : boolean
- getBeanName(MethodInvocation) : String
- doInvoke(MethodInvocation) : Object
AsyncMessageSender
- jmsTemplate: org.springframework.jms.core.JmsTemplate
+ sendMessage(String, String, String[], Object[], UsuarioSIARVo, boolean) : void
org.springframework.jms.core.JmsTemplate
# createConnection() : Connection
# createSession(Connection) : Session
# doCreateProducer(Session, Destination) : MessageProducer
# doSend(MessageProducer, Message) : void
org.springframework.jndi.JndiTemplate
- environment: Properties
+ getEnvironment() : Properties
+ setEnvironment(Properties) : void
+ lookup(String) : Object
+ execute(JndiCallback) : Object
org.springframework.jndi.JndiObjectFactoryBean
- jndiTemplate: org.springframework.jndi.JndiTemplate
- jndiName: String
# lookup() : Object
org.springframework.jms.core.JmsTemplate102
- connectionFactory: org.springframework.jndi.JndiObjectFactoryBean
- defaultDestination: org.springframework.jndi.JndiObjectFactoryBean
- receiveTimeout: long
# createConnection() : Connection
# createSession(Connection) : Session
# doCreateProducer(Session, Destination) : MessageProducer
# doSend(MessageProducer, Message) : void
«interface»
MessageListener
+ onMessage(Message) : void
AsyncMessageListener
- methodsCache: Map {readOnly}
+ onMessage(Message) : void
- getBsMethod(Object, String, String, String[]) : Method
- createBsMethod(Object, String, String, String[]) : Method
- createMethodKey(String, String[]) : String
- matchMethod(Method, String, String[]) : String
DefaultMessageListenerContainer
- connectionFactory: org.springframework.jndi.JndiObjectFactoryBean
- destination: org.springframework.jndi.JndiObjectFactoryBean
- messageListener: MessageListener
- concurrentConsumers: int
Diagrama 6: Ejecución Asíncrona (Cola JMS).
@ReadOnly
La anotación @ReadOnly sirve para notificar que un método de un BS se ejecuta
en una transacción de solo lectura. Cuando se realiza esto se reduce el tiempo de
ejecución puesto que la conexión con la Base de Datos sólo permitirá consultas e
Hibernate a su vez mejorará la gestión de la caché además de evitar el flush de
los datos.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
16/59
En la clase SiarNameMatchTransactionAttributeSource es donde se establecen los
atributos de la transacción. En esta clase se comprueba si el método
interceptado lleva la anotación @ReadOnly para establecer el valor readonly de
la transacción a true.
class @ReadOnly
«interface»
MethodInterceptor
+ invoke(MethodInvocation) : Object
«interface»
MethodInvocation
+ getMethod() : Method
TransactionAspectSupport
- transactionInfoHolder: TheadLocal {readOnly}
- transactionManager: PlatformTransactionManager
- transactionAttributeSource: TransactionAttributeSource
# createTransactionIfNecessary(TransactionAttribute, String) : TransactionInfo
# commitTransactionAfterReturning(TransactionInfo) : void
# completeTransactionAfterThrowing(TransactionInfo, Throwable) : void
TransactionInterceptor
+ invoke(MethodInvocation) : Object
SiarTransactionInterceptor
+ invoke(MethodInvocation) : Object
«interface»
TransactionAttributeSource
+ getTransactionAttribute(Method, Class) : TransactionAttribute
«interface»
Serializable
NameMatchTransactionAttributeSource
- nameMap: java.uti l .Map
+ getTransactionAttribute(Method, Class) : TransactionAttribute
+ setProperties(Properties) : void
+ addTransactionalMethod(String, TransactionAttribute) : void
+ getTransactionAttribute(Method, Class) : TransactionAttribute
# isMatch(String, String) : boolean
SiarNameMatchTransactionAttributeSource
+ getTransactionAttribute(Method, Class) : TransactionAttribute
+ getTransactionAttribute(Method, Class) : TransactionAttribute
+ setProperties(Properties) : void
+ addTransactionalMethod(String, TransactionAttribute) : void
- isMethodReadOnly(Method, Class) : boolean
«@interface»
ReadOnly
Diagrama 7: Anotación @ReadOnly.
Procesador Eventos CONDAG
Dentro de la funcionalidad del Cálculo de la Condición del Agente (y Puesto), el
gran núcleo del cálculo se encuentra en el procesamiento de eventos.
El cálculo de la Condición del Agente consta de 2 posibilidades: cálculo por
periodo o cálculo por día, este último tiene una precisión en la información
mayor. Cualquier de las 2 posibilidades realizan un procesado de eventos.
El procesado de eventos está implementado en la clase ProcesadorEventos del
cual se ejecuta el método procesar() para la colección de eventos. Internamente
invoca al método observa() para cada evento que aplique. Luego, se recurre toda
la lista de observadores dado el método getObservadores(), que es
implementado según sea por periodo o día (ProcesadorEventosPeriodo y
ProcesadorEventosDia).
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
17/59
Los observadores tienen una doble funcionalidad, son observadores y además
son visitadores1. Al observar llaman al método accept() del elemento (evento
tipificado). Cada elemento2 en su método accept() invoca al método visit()
correspondiente al tipo de evento que sea.
Al final se consigue que para un evento, según la perspectiva, se haga una serie
de ejecuciones encapsulando el algoritmo en las perspectivas. Cada perspectiva
tiene su funcionalidad, por ejemplo, preparar la solución o invocar a las reglas. class Procesador Ev entos CONDAG
ProcesadorEventos
- _logger: ILogger
- _condicionesSeleccion: CondicionesDeSeleccion
+ ProcesadorEventos(CondicionesDeSeleccion, ILogger)
+ procesar(java.uti l.Collection) : void
# getObservadores() : java.util .List
- observa(IEvento) : void
- chequeaParada(IEvento) : boolean
- aplica(IEvento) : boolean
ProcesadorEv entosPeriodo
- observadores: java.uti l.List
+ ProcesadorEventosPeriodo(ContenedorCondicionesPeriodo, DatosCondicionAgentePeriodo, CondicionesDeSeleccion, ILogger)
# getObservadores() : java.uti l.List
ProcesadorEv entosDia
- observadores: java.util .List
+ ProcesadorEventosDia(ContenedorCondicionesDia, DatosCondicionAgenteDia, CondicionesDeSeleccion, ILogger)
# getObservadores() : java.util .List
«interface»
IObservadorEventos
+ observa(IEvento) : void
«interface»
IEvento
+ accept(IVisitadorEventos) : void
«interface»
IVisitadorEventos
+ visit(IAsociacionPuestos) : void
+ visit(IAsociacionPlanesDeTrabajo) : void
+ visit(IIncidenciaAgente) : void
+ visit(ICambioServicioPeriodo) : void
+ visit(ICambioServicioDia) : void
+ visit(ICambioDiasLibresConsigoMismo) : void
+ visit(ICambioDiasLibresAgentes) : void
Perspectiva
+ observa(IEvento) : void
EventoVo
+ accept(IVisitadorEventos) : void
AsociacionPuestoAgenteVo
+ accept(IVisitadorEventos) : void
«interface»
IAsociacionPuestos
Perspectiv aHistoricoPlanDeTrabajoPeriodo
+ PerspectivaHistoricoPlanDeTrabajoPeriodo(ContenedorCondicionesPeriodo, DatosCondicionAgentePeriodo)
+ observa(IEvento) : void
+ visit(IAsociacionPuestos) : void
+ visit(IAsociacionPlanesDeTrabajo) : void
+ visit(IIncidenciaAgente) : void
+ visit(ICambioServicioPeriodo) : void
+ visit(ICambioServicioDia) : void
+ visit(ICambioDiasLibresConsigoMismo) : void
+ visit(ICambioDiasLibresAgentes) : void
Diagrama 8: Diagrama Clases Procesado de Eventos de Condición del Agente
Invocación Reglas JRules
1 En el diagrama únicamente se ha representado PerspectivaHistoricoPlanDeTrabajoPeriodo, pero hay más clases que son
observadores y visitadores, pero por simplicidad del diagrama sólo se muestra una.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
18/59
En la invocación de reglas de JRules de la parte Web y de Condag se ha
empleado un bean de Spring para centralizar el acceso.
JRulesInvoker es la encarga de ejecutar una de regla de negocio Web, condición
del agente periodo o condición agente por día especificándole el tipo de servicio a
ejecutar, es decir, el flujo de regla.
Internamente utiliza la factoría RuleSessionFactorySingleton, que sirve para
realizar la conexión con el motor de JRules y mantenerlo vivo durante toda la
JVM, de este modo, si se vuelve a invocar JRules no es necesario volver a crear
la conexión con el motor de JRules.
Con ello podemos crear la petición IlrSessionRequest, a la que se le especifica la
regla a ejecutar y los parámetros de entrada, y la sesión sin estado
IlrStatelessSession.
Con ello ya se puede invocar a la regla dando como resultado una respuesta
IlrSessionResponse de la que se extrae los parámetros de salida donde va el
resultado de la ejecución.
2 En el diagrama únicamente se ha representado un tipo de evento (elemento) que es AsociacionPuestoAgenteVo por
simplicidad del diagrama pero hay tantos como métodos visit() distintos existen.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
19/59
class Inv ocación JRules
«interface»
JRulesInvoker
+ ejecutaReglaDC(TiposServiciosReglaSIAR, Map) : Map
+ ejecutaReglaCondagPeriodo(TiposServiciosDecisionPeriodo, Map) : Map
+ ejecutaReglaCondagDia(TiposServiciosDecisionDia, Map) : Map
JRulesInvokerImpl
+ ejecutaReglaDC(TiposServiciosReglaSIAR, Map) : Map
+ ejecutaReglaCondagPeriodo(TiposServiciosDecisionPeriodo, Map) : Map
+ ejecutaReglaCondagDia(TiposServiciosDecisionDia, Map) : Map
- ejecutaRegla(String, Map) : Map
RuleSessionFactorySingleton
- factory: RuleSessionFactorySingleton
- factoriaSesionJ2SE: IlrJ2SESessionFactory
+ getRuleSessionFactory() : RuleSessionFactorySingleton
+ getFactoriaSesionJ2SE() : IlrJ2SESessionFactory
IlrJ2SESessionFactory
- clientFactory: IlrCCIClientFactory
- output: PrintWriter
- classloader: ClassLoader
+ setOutput(PrintWriter) : void
+ createStatelessSession() : IlrStatelessSession
IlrSessionFactoryBase
+ createRequest() : IlrSessionRequest
+ createStatelessSession() : IlrStatelessSession
«interface»
IlrSessionFactory
+ createRequest() : IlrSessionRequest
+ createStatelessSession() : IlrStatelessSession
«interface»
IlrSessionRequest
+ setRulesetPath(IlrPath) : void
+ getRulesetPath() : IlrPath
+ setInputParameter(String, Object) : void
+ getInputParameter(String) : Object
«interface»
IlrStatelessSession
+ execute(IlrSessionRequest) : Il rSessionResponse
«interface»
IlrSession
«interface»
IlrSessionResponse
+ getOutputParameters() : Map
«interface»
Serializable
Diagrama 9: Diagrama representando la conexión con JRules
Contexto Ligero Cliente Pesado
El contexto ligero consiste en un contexto Spring con menos beans y que haga
que la aplicación arranque antes.
Sin embargo, el contexto ligero no es suficiente para la ejecución completa del
Motor de Asignación, por lo que hace falta cargar el contexto completo.
Para introducir la mejora del contexto ligero sin que perjudique a la ejecución
completa, se hace que el contexto ligero sólo se use en una parte de toda la
ejecución del Cliente Pesado. Esto son las 2 primeras pantallas de configuración
de la asignación y de los parámetros de la asignación.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
20/59
En cualquier main del Cliente Pesado se inicializa el contexto Spring usando la
utilidad LoadAppLite.init().
Esta utiliza inicia la carga del contexto ligero en primer plano y la carga del
contexto completo en segundo plano.
Durantes las 2 primeras pantallas se usa el contexto ligero aunque el contexto
completo ya esté cargado y es justo antes de la invocación al motor (método
lanzarAsignacion() de las clases MetroViewXXX) donde se cambia el contexto y
se cierran todas las sesiones de Base de Datos abiertas por el contexto ligero.
A partir de ahí continúa la ejecución habitual del Motor de Asignación.
El diagrama es muy sencillo:
class Contexto Ligero Cliente Pesado
MetroPrototypeAppXXXXX
+ main(String[]) : void
«final»
LoadAppLite
- springLoaded: boolean = false
- context: ApplicationContext
- SPRING_FILES: String[] {readOnly}
- SPRING_LITE_FILES: String[] {readOnly}
- LoadAppLite()
- initSpringLite() : void
- initSpring() : void
- setSpringLoaded() : void
+ isSpringLoaded() : boolean
+ waitForSpringLoaded() : void
+ init() : void
MetroViewXXX
- lanzarAsignacion() : List
Diagrama 10: Diagrama de la carga del Contexto Spring en Cliente Pesado
Acceso Datos y transaccionalidad Cliente Pesado
El acceso a datos desde el Cliente Pesado es distinto que en el aplicativo Web.
La gran diferencia reside en que las clases del Cliente Pesado y del Motor de
Asignación no están en Spring por lo que no se puede usar AOP para el control
de la transacción.
Por lo tanto hay que crear la transacción “manualmente” para poder acceder a
los datos.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
21/59
La clase AccesoDatos se usa para este motivo en las 2 primeras pantallas del
Cliente Pesado. Todos los métodos invocan al método startTx() y finalizan con un
endTx() dentro de un bloque finally. En el diagrama aparecen una serie de
métodos de obtención de datos representativos, pero no están todos.
TransactionBinder es la clase singleton que mantiene una instancia de un objeto
de la clase AccesoDatos. Todos las clases MetroViewXXX (son los JFrame o
JPanel de Swing) y las acciones acceder a través de ella.
Por otro lado, para la transaccionalidad durante la asignación se usa una única
transacción que se crea en el método lanzarAsignacion() de las clases
MetroViewXXX. Esta transacción se alarga su vida hasta la finalización de la
asignación.
Este inicio y fin de transacción se gestiona en los métodos initTxMotor() y
rollbackTxMotor() de la clase AbstractTransactionalFrame.
El siguiente diagrama representa el acceso a datos del Cliente Pesado: class Acceso Datos Cliente Pesado
AccesoDatos
- gestorPeriodoAnual: IGestorPeriodoAsignacionAnual
- gestorCategorias: IGestorCategorias
- gestorPeriodos: IGestorPeriodoAsignacion
- gestorTipoLocalizacion: IGestorTipoLocalizacion
- transactionManager: PlatformTransactionManager
- status: TransactionStatus
- definition: TransactionDefinition
- TRANSACTION_MANAGER_BEAN_NAME: String = "siarTransactio... {readOnly}
- startTx() : void
- endTx() : void
+ getParadasMotor(ICategoria, ITipoAsignacion) : List
+ getCategorias() : List
+ getPeriodos(ICategoria) : List
+ getPeriodosMensuales(IPeriodoAsignacionAnual, ICategoria) : List
+ getTiposLocalizacion(ICategoria, ITipoAsignacion) : Iterator
+ getTipoLocalizacionPorDefecto(ICategoria, ITipoAsignacion) : ITipoLocalicacion
+ getParametro(String, ICategoria, ITipoAsignacion) : IParametroAsignacion
«final»
TransactionBinder
- instance: TransactionBinder
- gestorConexiones: IGestorConexiones
- accesoDatos: AccesoDatos
+ getInstance() : TransactionBinder
+ setNullInstance() : void
+ getAccesoDatos() : AccesoDatos
# getBean(String) : void
+ inicializar(IPeriodo, ICategoria) : void
- inicializar() : void
+ getGestorConexiones() : IGestorConexiones
+ setGestorConexiones(long) : void
+ inicializar(IDiaExplotacion) : void
MetroViewXXX
- lanzarAsignacion() : List
j avax.swing.JFrame
AbstractTransactionalFrame
- transactionManager: PlatformTransactionManager
- status: TransactionStatus
- definition: TransactionDefinition
- TRANSACTION_MANAGER_BEAN_NAME: String = "siarTransactio... {readOnly}
- init() : void
+ doInit() : void
# initTxMotor() : void
# rollbackTxMotor() : void
MetroView
Diagrama 11: Acceso a Datos del Cliente Pesado y Transaccionalidad
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
22/59
Invocación JNI del Motor de Asignaciones
La invocación a las librerías de C++ (CPLEX, CP y librería de optimización del
Motor de Asignaciones) se invocan mediante JNI.
AlgoritmoJNIBase carga las librerías necesarias y luego las clases AlgoritmoJNI
son las encargadas en comunicarse con esas librerías de C++ mediante la réplica
del modelo en native Java. Realmente, las clases AlgoritmoJNI hacen la función
de interfaces hacia la implementación que está hecha en C++.
Hay 2 clases AlgoritmoJNI en distintos paquetes, una para planes de trabajo y
otra para puestos de trabajo.
La invocación desde la parte Java se realiza mediante la clase AlgoritmoNativo,
invocado desde JRules, que en su método resuelve() primero llama al método
nativo extrae() que convierte el modelo Java a C++ y devuelve el puntero de la
posición de memoria de la Heap de C++. Luego se llama al método nativo
resuelveNativo() pasándole el puntero de memoria anteriormente obtenida, con
ello se obtiene la Solucion.
Finalmente, se invoca al método nativo deleteModelo() para liberar la memoria
ocupada.
El diagrama se muestra a continuación:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
23/59
class JNI Motor Asignacion
AlgoritmoJNIBase
# _mensajeerror: String = null
+ getMensajeError() : String
es.metromadrid.siar.motorasignacion.planesdetrabajo.algoritmos
AlgoritmoJNI
+ extrae(Object) : long
+ deleteModelo(long) : void
+ resuelveNativo(long) : Object
es.metromadrid.siar.motorasignacion.puestos.algoritmos
AlgoritmoJNI
+ extrae(Object) : long
+ deleteModelo(long) : void
+ resuelveNativo(long) : Object
«interface»
Serializable
«interface»
IAnadible
+ getModelo() : ModeloAsignacion
Algoritmo
- _modelo: ModeloAsignacionPlanesDeTrabajo
+ Algoritmo(ModeloAsignacionPuestos)
+ getModeloPT() : ModeloAsignacionPlanesDeTrabajo
+ getModelo() : ModeloAsignacion
+ resuelve() : Solucion
AlgoritmoNativ o
+ AlgoritmoNativo(ModeloAsignacionPlanesDeTrabajo) : void
+ resuelve() : Solucion
- escribirErrorVerDatosModelo(Exception) : void
Algoritmo
- _modelo: ModeloAsignacionPuestos
+ Algoritmo(ModeloAsignacionPuestos)
+ getModeloP() : ModeloAsignacionPuestos
+ getModelo() : ModeloAsignacion
+ resuelve() : Solucion
AlgoritmoNativ o
+ AlgoritmoNativo(ModeloAsignacionPuestos) : void
+ resuelve() : Solucion
- resuelveGerenciaRaiz() : Solucion
- resuelvePorGerencia(IAgrupacionGestion) : Solucion
+ resuelvePorGerencias() : Solucion
- juntarSoluciones(Solucion, Solucion) : Solucion
Diagrama 12: JNI Motor Asignación
Comandos Motor Asignación
El diagrama de los comandos usados para ejecutar las acciones del Motor de
Asignación es complejo.
Se utiliza un patrón Command con gran cantidad de comandos y agrupaciones de
comandos en clases abstractas.
La interfaz común del patrón es IComando, la cual es implementada por la clase
abstracta ComandoAbstracto dando implementación a alguno de los métodos.
De ComandoAbstracto heredan 2 clases: ComandoSimple (que a su vez es clase
padre de todos los comandos) y Tarea.
El papel del Receiver está implementado en las clases EjecutorComandos y
IEstadoAsignacion.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
24/59
Por último, el papel del Invoker está implementado en las clases PoolComandos
junto con el GestorPersistenciaComandos y EjecutorComandos, que tiene una
doble función en el patrón.
En el flujo de ejecución, se crean una lista de tareas a realizar para la asignación,
las cuales consisten en una serie de comandos.
Se van ejecutando las tareas y para cada tarea se ejecuta los comandos
necesarios de la tarea.
Algunos de los comandos que hay son para ejecutar las reglas de la asignación,
ejecutar las reglas de consulta, reglas de eliminación, inserción,…
El siguiente diagrama muestra la implementación del patrón Command realizada
para el Motor de Asignación, en el diagrama se ha reducido atributos y
operaciones que no aportaban información para su comprensión:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
25/59
class Comandos Motor
«interface»
IComando
+ ejecutar(EjecutorComandos, IEstadoAsignacion) : boolean
+ deshacer(EjecutorComandos, IEstadoAsignacion) : boolean
+ almacenar(GestorPersistenciaComandos, long) : boolean
+ borrar() : boolean
+ getId() : long
+ getStringTipoComando() : String
EjecutorComandos
- _factory: Il rJ2SESessionFactory
- _session: Il rStatefulSession
- _sessionRequest: IlrSessionRequest
- _ruleApp: String
- _inicializado: boolean
- _idSesion: long
- _tareasEnEspera: HashMap
- _ultimaTareaEjecutada: long
- _context: IlrContext
- _ejecutores: HashMap
+ iterador() : Iterator
+ get(long) : EjecutorComandos
+ crear(long, String) : EjecutorComandos
+ borrar(long) : void
+ EjecutorComandos(long, String)
+ ejecutaTareaComandos(Tarea, IEstadoAsignacion) : boolean
- procesaTareasEnEspera(long, IEstadoAsignacion) : boolean
+ deshacerTareaComandos(Tarea, IEstadoAsignacion) : boolean
+ inicializaSessionEjecucionComandos() : boolean
+ endSessionEjecucionComandos() : boolean
+ ejecutar(Tarea, IEstadoAsignacion) : boolean
«interface»
IEstadoAsignacion
+ getIdSesion() : long
+ getTareaInicio() : int
+ setTareaInicio(int) : void
+ getTareaFinal() : int
+ setTareaFinal(int) : voidGestorPersistenciaComandos
- _sesionasignacionDao: SesionAsignacionDao
- _inicialciado: boolean
- _poolComandos: PoolComandos
- _categoria: ICategoria
+ GestorPersistenciaComandos(ICategoria, PoolComandos, long)
+ borrarSesionesAsignacion() : boolean
+ almacenarComando(ComandoSimple, long) : void
- isInicial izado() : boolean
+ crearComandoEliminacion(long, Col lection) : boolean
+ crearComandoInsercion(long, Collection) : boolean
+ crearComandoConsulta(long, String, String) : boolean
+ crearComandoEliminacion(long, String, String) : boolean
+ getComandosAsignacion(long, IPeriodo) : Col lection
+ getPoolComandos() : PoolComandos
«interface»
Serializable
ComandoAbstracto
- _ejecutado: boolean = false
- _almacenado: boolean = false
- _id: long
- _logger: ILogger
+ ejecutar(EjecutorComandos, IEstadoAsignacion) : boolean
+ deshacer(EjecutorComandos, IEstadoAsignacion) : boolean
+ almacenar(GestorPersistenciaComandos, long) : boolean
+ borrar() : boolean
+ getId() : long
+ getStringTipoComando() : String
+ getLogger() : ILogger
+ isEjecutado() : boolean
+ setEjecutado(boolean) : void
+ isAlmacenado() : boolean
+ setAlmacenado(boolean) : void
+ setId(long) : void
EntidadBase
«interface»
IEntidadBaseEntidadBaseVo
ComandoSimple
- _tarea: Tarea
+ almacenar(GestorPersistenciaComandos, long) : boolean
+ getTarea() : Tarea
+ setTarea(Tarea) : void
+ getDescripcionCorta() : String
+ getEntidadManejada() : Class
+ transformarClavesAEntidades(IGestor) : boolean
Tarea
- _tipocomando: TipoComando
- _comandos: Vector
- _espera: boolean
- _recuperadaDeReasignaciones: boolean
+ Tarea(long, ILogger, TipoComando)
+ ejecutar(EjecutorComandos, IEstadoAsignacion) : boolean
+ deshacer(EjecutorComandos, IEstadoAsignacion) : boolean
+ almacenar(GestorPersistenciaComandos, long) : boolean
+ getStringTipoComando() : String
+ getTipoComando() : T ipoComando
+ getComando(int) : ComandoSimple
+ getComandoPorTipo(Class) : ComandoSimple
+ getComandoPorId(IEntidadBase.IKey) : ComandoSimple
+ insertarComando(ComandoSimple) : void
+ eliminarComando(ComandoSimple) : void
+ inicial izarTarea(TipoComando) : boolean
+ getDescripcionCorta() : String
+ espera() : boolean
+ setEspera(boolean) : void
+ getEntidadManejada() : Class
+ transformarClavesAEntidades(IGestor) : boolean
+ esRecuperadaDeReasignaciones() : boolean
+ setRecuperadaDeReasignaciones(boolean) : void
TipoComando
- _nombre: String
+ ConsultaWM: TipoComando {readOnly}
+ Inicial izacion: TipoComando {readOnly}
+ InsercionWM: TipoComando {readOnly}
+ EliminacionWMConsulta: T ipoComando {readOnly}
+ EliminacionWMElementos: TipoComando {readOnly}
+ Ejecucion: T ipoComando {readOnly}
+ ModificacionWM: TipoComando {readOnly}
+ Indefinida: T ipoComando {readOnly}
+ TipoComando(String)
+ Inicial izaMapaClaseIntTipoComandos() : void
+ Inicial izaMapaStrIntTipoComandos() : void
+ Inicial izaMapaClaseStrIntTipoComandos() : void
+ GetIdTipoComando(ComandoSimple) : int
+ GetIdTipoComando(String) : int
+ GetStrTipoComando(ComandoSimple) : String
PoolComandos
- _ultimoIdComando: long = 0
- _ultimoIdTarea: long = 0
- _tareas: ArrayList
- _ultimaTareaEjecutada: Tarea
- _gestorAcceso: GestorAccesoWM
- _gestorPersistencia: GestorPersistenciaComandos
- _gestorEstado: GestorEstadoAsignacion
- _tipoAsignacion: ITipoAsignacion
- _gestorConexiones: IGestorConexiones
- _categoria: ICategoria
+ get(long) : PoolComandos
+ crear(long) : PoolComandos
+ borrar(long) : void
+ PoolComandos(long)
+ resetPoolComandos() : void
- insertarTarea(Tarea) : boolean
+ el iminarTarea(Tarea) : boolean
- borrarTareas() : boolean
+ getUltimaTareaEjecutada() : Tarea
+ getTarea(int) : Tarea
+ getNumeroTareas() : int
+ i teradorTareas() : IteratorComandoCommit ComandoConsultaWM ComandoEjecucionReglas
ComandoEliminacionWM ComandoInicializacion ComandoInsercionWM
ComandoModificacionWM
Diagrama 13: Comandos del Motor de Asignación.
3.1. Repositorio de documentación y modelado
Información incluida en el manual común de arquitectura.
3.2. Diagramas de arquitectura Información incluida en el manual común de arquitectura.
3.3. Diagramas y patrones de diseño Listado de patrones de diseño genéricos empleados:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
26/59
Nombre del patrón Modelo-Vista-Controlador (MVC) PAT-001
Propósito del patrón
Permite separar la aplicación en diferentes capas determinando a cada una de ellas
una funcionalidad.
Modelo: capa encargada de la lógica de negocio y acceso a datos. Opera con los datos
que vienen de la vista y controlador y otros datos.
Vista: capa de presentación de la información.
Controlador: capa que controla los eventos que se producen desde la vista y se
encarga de invocar al modelo y devolverle la respuesta a la vista.
Partes implicadas
Toda la aplicación (tanto Web como Cliente Pesado)
Representación del patrón
Toda la aplicación (tanto Web como Cliente Pesado)
Diagrama
Nombre del patrón Singleton PAT-002
Propósito del patrón
Patrón usado para mantener una única instancia de una clase en la aplicación.
Se utiliza para acceder a recursos únicos o recursos cuyo acceso o construcción sea
costosa.
Partes implicadas
Spring BS y DAO
ConfiguracionMensajes.java
Configuracion.java
ApplicationContextProvider.java
MensajesPantalla.java
Representación del patrón
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
27/59
Nombre del patrón Proxy PAT-003
Propósito del patrón
Se utiliza para encapsular objetos manteniendo una referencia al objeto real y además
le añade funcionalidades extra.
En el caso de la creación de beans de Spring, sirve entre otras cosas, para añadirle las
funcionalidades de los interceptores.
En el caso de consultas lazy de Hibernate, sirve para mantener la referencia a la
consulta hasta que se accede al objeto, en cuyo caso se ejecuta la consulta.
Los proxies son de referencias inteligentes.
Partes implicadas
Beans Spring (JDK Dynamic Proxy)
Lazy Hibernate (CGLIB Proxy)
Representación del patrón
Nombre del patrón Factory Method PAT-004
Propósito del patrón
Este patrón se utiliza para abstraer la creación de objetos para el Motor de Asignación.
De este modo, cada entidad del Motor tiene su propia fábrica de objetos cuyo acceso
queda factorizado.
Partes implicadas
Factorías de objetos del Motor
Gestor de Conexiones, Manejador Gestores y cacheo Representación del patrón
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
28/59
Nombre del patrón Observer PAT-005
Propósito del patrón
Este patrón se utiliza para que, de manera desacoplada, un objeto (observador) tenga
notificaciones cuando otro objeto (sujeto a observar) cambia su estado.
Partes implicadas
Cálculo de Vacaciones
Procesador de Eventos del Cálculo de Condición del Agente
Representación del patrón
Nombre del patrón Visitor PAT-006
Propósito del patrón
Este patrón sirve para poder separar a los elementos de la implementación del
algoritmo que se debe realizar para ese elemento.
Partes implicadas
Procesador de Eventos del Cálculo de Condición del Agente
Representación del patrón
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
29/59
Nombre del patrón Command PAT-007
Propósito del patrón
El patrón Command hace que las peticiones se encapsulen como objetos evitando de esta
forma conocer el contenido del mensaje.
Además proporciona mecanismos para deshacer los comandos ejecutados.
También permite crear listado de tareas a realizar.
Este patrón es fácilmente extensible a nuevas pericones/comandos.
Partes implicadas
Comandos Motor Asignación
Representación del patrón
3.4. Decisiones arquitecturales y de diseño • Cola JMS (Java Message Service)
La cola JMS es el mecanismo que se ha elegido como solución a los
procesos que deben ser asíncronos en SIAR.
Los procesos asíncronos son aquellos, que por su naturaleza, dura un
tiempo elevado su procesamiento, por tanto, en un entorno Web no podría
estar ejecutándose “inline”. Estos procesos, deben escribir su resultado en
Base de Datos para su posterior acceso a los datos generados.
Con la cola JMS se permite mandar el proceso a ejecutar mediante un
mensaje que es encolado y devuelto a la aplicación para que interprete ese
mensaje y sepa qué proceso ejecutar.
La implementación de la cola JMS es la que provee Weblogic Server 10.3.5
y se accede a ella mediante la clase de Spring Framework
JMSTemplate102.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
30/59
La diferencia entre ejecutarlo mediante la cola JMS o mediante un Thread
es que la cola JMS permite redirigir el mensaje a varios receptores,
balanceando las peticiones/mensajes que le lleguen. Las colas JMS en
Weblogic pueden estar sobre un cluster.
Para la implementación, es necesario un emisor (sender) y un receptor
(receiver). Este mecanismo puede hacer que el emisor y el receptor estén
en sitios distintos, no necesariamente en la misma JVM. La solución
mediante Threads se ejecutan sobre la misma JVM.
En contra, para el uso de JMS es necesario de librerías propietarias. En
este caso se usan las librerías de JMS de Oracle Weblogic.
• Apache CXF Es el framework elegido para la implementación de los WebServices que
publica SIAR.
Este framework simplifica la creación de endpoints abstrayendo de la API
de Java JAX-WS.
Es fácilmente configurable e integrable con Spring. Además, permite crear
WebServices incluyendo opciones de seguridad (publicar mediante https) o
login básico de HTTP.
Otra cuestión importante para su elección, es que se integra en el servidor
de aplicaciones que actualmente se usa en SIAR, Oracle Weblogic 10.3.5.
Acceso a BBDD Externas mediante SQL
SIAR se integra con otros sistemas como son el caso de VISA, Anden
Central, PAP, etc.
En muchos casos, se ha decidido por acceder a la BBDD del sistema
destino para extraer los datos que necesita SIAR.
Para crear la conexión con esas BBDD externas se ha decidido realizarlo
mediante SQL, sin usar ningún ORM (Hibernate). El motivo principal es el
consumo de memoria que tiene usar Hibernate para la construcción del
sessionFactory, cuando para los sistemas externos se usará únicamente 2-
3 entidades por sistema.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
31/59
• SpringSecurity y AccessManager Metro utiliza AccessManager como sistema de SSO (Single Sign-On).
Además, mediante una librería desarrollada por Metro, que integra el
Agente de AccessManager con SpringSecurity, la integración con SIAR es
más sencilla.
Esta combinación nos proporciona por un lado las propiedades de
AccessManager: SSO, LDAP con usuarios, roles y privilegios; y
propiedades de SpringSecurity: integración dentro de la aplicación de SIAR
de la información de roles y privilegios para permitir distintas
configuraciones de la aplicación según el usuario que ha hecho login.
• Planificador Procesos Periódicos con SAP/R3 Después de valorar distintas opciones para poder planificar, relanzar y
gestionar/consultar las ejecuciones periódicas que se deben realizar sobre
SIAR, finalmente se ha optado por usar el planificador de SAP/R3
invocando a WebServices de SIAR que ejecutan los procesos periódicos.
Los motivos han sido los siguientes:
o Es una herramienta que ya usa Metro en varias aplicaciones.
o Cumple con todos las características exigidas por Metro.
o No supone coste adicional de servidores o licencias de software.
Otras herramientas que se han valorado son:
o Quartz
o QuartzScheduler GUI
o Jenkins ejecutando los procesos como Main dentro de un JAR.
• WebServices en proyecto aparte Se ha decidido crear un proyecto aparte con todos los WebServices que
publica SIAR. De esta manera puede desplegarse como EAR en un servidor
distinto al aplicativo Web principal, consumiendo sus propios recursos de
memoria. Además, también separa la lógica y configuración de los
WebServices respecto el negocio y presentación de SIAR.
• Utilidad Operaciones Masivas Datos vs StatelessSession Para realizar operaciones masivas sobre Base de Datos de tipo insert,
update o delete, inicialmente se pensó en una conexión Stateless
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
32/59
(StatelessSession). Este tipo de conexiones crean una transacción nueva
con en la que no guardan el estado de cada operación y al realizar el
commit manda el flujo con todas las operaciones. Esto hace que las
modificaciones se realicen mucho más rápido en comparación con la forma
tradicional.
El problema de este tipo de conexiones es que utilizan otra transacción con
la Base de Datos, lo que puede provocar un interbloqueo en los procesos
que internamente usen conexiones Stateless. Además, en estos casos, al
no usar sesión, no cachea la información insertada por StatelessSession y
no opera de manera atómica, ya que si falla la transacción original
después de la llamada Stateless, no se haría rollback de esos datos y sí de
la original.
• Borrado Lógico Por seguridad en la gestión de los datos ante borrados accidentales o
malintencionados se ha implementado un sistema de borrado lógico para
todas las tablas de la BBDD.
La solución consiste en:
o Crear 2 columnas nuevas en todas las tablas que almacenan una
fecha de borrado y un usuario de borrado.
o Modificar todas las consultas de la aplicación para que comprueben
que los valores de la fecha y usuario de borrado sea nulo. Evita
traerse datos borrados lógicamente. Esto se ha hecho mediante la
condición where que ofrece Hibernate en los ficheros de
configuración .hbm.xml.
o Modificar la operación de borrado para que pase de un delete por un
update sobre los campos de borrado.
Se consideraron otras maneras de mantener un borrado lógico que se
descartaron por motivos diferentes:
o Triggers: no mantienen el usuario de aplicación, sólo el usuario de
BBDD.
o Oracle AUDIT: problemas de memoria si no se borran los datos
generados por esta herramienta.
o Interceptor Aplicación: posibles problemas de rendimiento en
borrados masivos y en el control de excepciones.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
33/59
• Excel Paradas Motor Las asignaciones de SIAR se ejecutan en un cliente pesado que corre sobre
en remoto sobre un servidor usando SGD (Sun Global Desktop).
Durante las distintas fases de las asignaciones se generan tablas que se
pueden exportar a un fichero Excel. La problemática que hubo con esto es
cómo recoger esos ficheros Excel, puesto que se generan en el servidor
donde corre el SGD.
Se valoraron las siguientes opciones:
o Acceder mediante un cliente FTP al servidor para descargarse los
ficheros generados.
o Instalar un servidor Apache para permitir el acceso vía Web (HTTP).
Esto permite acceder mediante login.
o Crear una tabla donde se guardan los ficheros Excel y luego se
puedan consultar en la aplicación Web de SIAR.
Finalmente, se decidió por guardar los ficheros Excel en BBDD por facilidad
en el uso. Se descartó el acceso FTP por temas de seguridad y valorando
el tiempo de aprendizaje de los usuarios. También se descartó instalar el
servidor Apache por seguridad y mantenimiento de los usuarios que
pueden acceder a estos recursos.
Los ficheros que se guardan en BBDD tienen un periodo de vigencia de una
semana, después se borrará mediante un job Oracle que revisa qué
registros se pueden borrar.
3.5. Módulos/componentes: funcionalidad y relaciones Información incluida en el manual común de arquitectura en el apartado 4.2
Diagrama de Componentes.
En ese apartado se puede ver el diagrama general de los módulos de los que
consta SIAR y luego se explica en más detalle cómo están compuestos
internamente.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
34/59
3.6. Frameworks, librerías y tecnologías utilizadas Tabla tecnológica con las diferentes frameworks, librerías y tecnologías utilizadas
para cada función, tanto propias de WLS, como de terceros o generadas en el
propio proyecto.
Nombre Versión Función Localización Despliegue JSF 1.2_12 Capa de presentación Maven WAR Richfaces 3.3.3.Final Capa de presentación Maven WAR Facelets 1.1.14 Capa de presentación Maven WAR Apache POI
3.6 Generación Ficheros Microsoft Office
Maven WAR
XStream 1.3.1 Tratamiento XML Maven EAR de la aplicación
Spring Security
1.0 Persistencia en Base de Datos
Maven EAR de la aplicación
Freemarker 2.3.16 Generación Ficheros mediante Plantillas Maven
EAR de la aplicación
JRules 7.1.1 BRMS Maven WAR y lib Cliente Pesado
Hibernate 3.2.6.ga Persistencia en Base de Datos Maven
WAR y lib Cliente Pesado
Spring Framework
2.5.6 Framework Negocio Maven WAR y lib Cliente Pesado
JXL 2.6.10 Generación Excels Maven Lib Cliente Pesado
SwingFX 1.0 Capa de presentación Maven Lib Cliente Pesado
SwingX 1.0 Capa de presentación Maven Lib Cliente Pesado
CXF 2.6.2 Framework WebServices Maven WAR WLS JMS Client 10.3.3.0 JMS Maven Interno WLS
3.7. Prototipado de pantallas Se han seguido una serie de pautas en las que intervinieron los usuarios de
SIAR.
Estas pautas sobre el diseño y funcionamiento de SIAR se encuentran en los
siguientes documentos:
Ruta Descripción
docexterna\SIARIB-DT-Componentes de
Pantalla SIARIB-v0.2.doc
Explica los componentes que
se utilizan en los formularios y
al final expone una tabla de la
relación de componentes
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
35/59
WebDynpro y JSF.
docexterna\Metro_DCU.ppt Presentación explicando el
layout de la interfaz gráfica
con ejemplos de uso.
docexterna\Metro_DCU_2.ppt Guía de construcción de los
principales componentes.
4. CONSTRUCCIÓN, DESPLIEGUE Y
EJECUCIÓN 4.1. Requisitos del puesto del desarrollador Requisitos de los equipos del personal de Mantenimiento. Se deberá concretar
las versiones y, en caso de haberse utilizado alguna herramienta no
homologada por Metro se deberá incluir la localización del SW para su
instalación (depositarla en una carpeta de red del proyecto).
• Hardware Los datos hardware expuestos a continuación son los requisitos mínimos para
el puesto de desarrollador, cualquier configuración inferior puede producir
mucha ralentización en servidores y entornos de desarrollo.
Características Hardware
Procesador Intel Core 2 Duo
Memoria RAM 3 Gb
HDD (Disco Duro) 100 Gb aprox.
• Software Características Software
Sistema Operativo Windows XP 32 bits
Lenguaje Programación Java 6 SE (JDK Sun)
Entorno Desarrollo Eclipse 3.5 (Galileo) / RuleStudio 7.1.1
(basado en Eclipse 3.4)
Servidor de Aplicaciones Apache Tomcat 6
Herramienta BBDD Toad for Oracle 9.5 (necesita cliente
Oracle instalado) / SQLDeveloper
Maven Maven 3+
Herramienta WebServices SoapUI 3.5+
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
36/59
• Configuración recomendada: por ejemplo para el arranque de la JVM del IDE o del servidor local, variables de entorno, configuraciones relacionadas
con Maven, con Eclipse, etc.
Configuraciones Recomendadas
Eclipse - Arranque del Eclipse con 700 MBytes
de Heap. Se recomienda que
inicialmente ya tenga esas 700 MBytes.
- Configurar UTF-8 como codificación
para los ficheros de texto.
- Usar la vista Navigator para explorar
los proyectos, consume menos
recursos.
- Enlazar con una instalación de Maven
externa (versión 3+), esto mejora la
versión que viene interna con el plugin
m2eclipse.
- Al realizar checkouts de varios
proyectos desde el SVN quitar la opción
de “Build Automatically”.
- En las opciones de comparación del
SVN, quitar de esta comparación la
carpeta target que genera Maven con
los binarios.
Servidor Tomcat
(dentro de Eclipse)
- Aumentar el tiempo de arranque (por
defecto viene en 45 segundos).
- Activar la opción “Serve modules
without publishing”.
- Cambiar las opciones arranque
aumentando la memoria. Especificar las
siguientes opciones mínimas: -
Xmx768m –Xms768m –
XX:MaxPermSize=200m
Maven Especificar el mismo directorio local donde
descargar las librerías, plugins u otros
artefactos que usa Maven, y que este
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
37/59
directorio local sea el mismo que se utiliza
en la configuración de Eclipse. De esta
forma se evitará mantener 2 repositorios
locales.
• Otros (e.g. comunicaciones…) N/A
4.2. Repositorios de código y gestión de versiones La ruta del repositorio de Subversion es:
https://ciserver.metromadrid.net/svn/siar
A su vez, el repositorio está dividido en 3:
• Trunk: https://ciserver.metromadrid.net/svn/siar/trunk • Branches: https://ciserver.metromadrid.net/svn/siar/branches • Tags: https://ciserver.metromadrid.net/svn/siar/tags
Trunk
El criterio de utilización del Subversion es que el Trunk es la rama principal
sobre la cual se desarrolla SIAR. Todos los desarrolladores están sincronizados
a esta rama, y las modificaciones que se realizan sobre el aplicativo se
actualizan aquí.
Branches
En esta carpeta se realizan réplicas del trunk pero etiquetadas con un nombre
claro que identifique para qué se usa.
Con ello se crea una línea paralela de desarrollo para tener un aplicativo libre
de los efectos de los cambios que se realizan en el trunk.
Hay que tener claro, que en caso de crear un branch paralelo, los cambios que
se realicen se deben replicar en el trunk cuando éstos sean definitivos.
Los branches que se han creado han sido tras la liberación en producción de
Anuales 2012 y Anuales 2013, entre otros, con los siguientes nombres:
- Anuales 2012: siar-1.0
- Anuales 2013: siar-anuales2013
Tags
Los tags son versiones de código congeladas. Estas versiones se realizan como
snapshot de versiones “importantes” del aplicativo.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
38/59
Sobre un tag no se debe trabajar.
Algún tag interesante es:
- Anuales 2012: siar-anual2012 versión definitiva con la que terminó
producción con Anuales 2012.
- Anuales 2013: siar-anual2013 versión definitiva con la que terminó
producción con Anuales 2013.
4.3. Puesta en funcionamiento en el puesto del desarrollador Esta guía sirve tanto para configurar el entorno de desarrollo para el Eclipse
“normal” como el Eclipse de reglas (RuleStudio).
Prerrequisitos
- Eclipse: Galileo o RuleStudio.
- JDK 1.6 o superior.
- Apache Maven 2.0.2 o superior. Preferiblemente la 3 o superior. Maven
debe estar configurado para que apunte a los repositorios de Metro.
- Apache Tomcat 6.0.20.
Una vez configurado los productos anteriores se procede de la siguiente forma:
1. Abrir Eclipse en un nuevo workspace.
Cuando se abre el Eclipse en un nuevo workspace por primera vez suele aparecer
de esta forma:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
39/59
El workspace es una carpeta donde se almacena todas las configuraciones que se
realiza sobre Eclipse (maven, svn, preferencia de editores, proyectos, y un largo
etc.).
2. Configurar Maven.
Para configurar Maven hay que acceder a Window Preferences:
En la ventana que se abre debe acceder a Maven Installations. Una vez allí
sebe pulsar sobre “Add…” para añadir Maven externo. Hay que seleccionar la
carpeta donde está el Maven en nuestro ordenador.
Al final, debe quedar así:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
40/59
El fichero que queda en el campo deshabilitado “Global settings from installation
directory” es el mismo que debe quedar en la ventana Maven User Settings
para el campo “User Settings”. Para configurarlo podemos buscarlo con el botón
“Browse…” o directamente copiando y pegando de la pantalla de Installations.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
41/59
Una vez configurado pulse el botón “OK” para guardar los cambios.
3. Configurar codificación de caracteres.
Para configurar Maven hay que acceder a Window Preferences:
En la ventana que se abre debe acceder a General Content Types. Una vez allí,
pulse sobre el valor “Text” del árbol que aparece y abajo, en el campo de texto
“Default encoding” introduzca el valor “UTF-8” sin comillas.
Al final, debe quedar así:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
42/59
Una vez configurado pulse el botón “OK” para guardar los cambios.
4. Configurar SVN.
Acceder a la perspectiva de “SVN Repository Exploring”:
Pulsando en el botón marcado en la imagen en rojo. Si no sale en el listado
pulsar sobre “Others…” y seleccionarle ahí.
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
43/59
Añadir el repositorio https://ciserver.metromadrid.net/svn/siar pulsando sobre el
botón que aparece marcado en rojo en la siguiente imagen:
Si al añadir pide autenticación, debe introducir el usuario y contraseña de
Subversion proporcionado por Metro.
Ahora se va a proceder explicar como realizar la instalación de la parte Web. La
parte Cliente Pesado es similar.
5. Checkout proyectos SIAR.
Realice un checkout sobre los siguientes proyectos, es recomendable deshabilitar
el “build automatically” para que esta tarea tarde menos:
- siar-web
- siar-negocio
- siar-negocioComun
- siar-core.
Para realizar checkout pulse botón derecho sobre uno o varios proyectos
seleccionados y haga clic en “Checkout…”.
Le saldrá una como la de a continuación, sobre ella pulse “Finish”:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
44/59
NOTA 1: el checkout puede ser sobre el trunk o sobre cualquier branch/tag que
haya creado. La forma de proceder es la misma.
NOTA 2: si no se ha instalado nunca el POM padre en el ordenador hay que
exportar el fichero pom.xml que está en la raíz del trunk/branch/tag a la carpeta
raíz del workspace de Eclipse. Este fichero debe ser modificado quitando las
líneas siguientes:
org.codehaus.mojo buildnumber-maven-plugin 1.0 validate create false false javasvn
6. Configurar Servidor Web.
Para añadir un servidor al Eclipse debe seleccionar File New … Other….
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
45/59
En la ventana que sale debe seleccionar Server y pulsar Next:
Se selecciona Tomcat v6.0 y se pulsa Next:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
46/59
Luego se pulsa sobre Browse y se selecciona la carpeta local donde se encuentra
el servidor Apache y se pulsa Next:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
47/59
Finalmente se añade el proyecto siar-web a la parte “Configured” y se pulsa
Finish:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
48/59
A esta altura ya está tenemos el servidor de aplicaciones Apache preparado, sin
embargo, hay que realizar unas configuraciones específicas de SIAR como son
evitar el publish, el tiempo de despliegue y opciones de memoria de la JVM.
Para realizar esto hay que abrir la configuración del servidor. La manera más
fácil es mostrar la vista “Servers” en Window Show View … Other… y buscar
“Servers”. En la vista “Servers” hacer doble clic sobre el servidor añadido en los
pasos anteriores y aparecerá la siguiente pantalla en la que debe quedar tal y
como se muestra en la imagen (guardar cambios):
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
49/59
Por último y para terminar de configurar el Servidor, hay que configurar las
opciones de memoria en la opción “Open launch configuration”, está marcado en
la imagen de arriba. Los valores deben quedar de la siguiente forma:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
50/59
Se ha añadido estas opciones de memoria a la JVM:
-XX:MaxPermSize=200m -Xmx768m -Xms768m
7. Compilación.
Vuelva a la perspectiva Java o JavaEE.
La primera vez que se compila el proyecto completo es recomendable que no
esté marcada la opción de “Build automatically”. (en la pestaña Project)
NOTA: si no se ha instalado nunca el POM padre en el ordenador hay que
instalarlo manualmente.
Primero hay que abrir la ventana de Run Configurations mediante el menú Run
Run Configurations …:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
51/59
Añadir un nuevo “Maven Build” y configurarlo se la siguiente forma:
-
Nombre Documento:
Arquitectura Software
Versión:
1.0
Página:
52/59
En Base directory hay que seleccionar la carpeta raíz del workspace, es decir,
donde está el fichero pom.xml padre.
Una vez finalizado la instalación del pom padre se comienza compilando los
proyectos. Run pom padre.
En cada uno de ellos se pulsa botón derecho y Maven Update Dependencies ….
top related