arquitectura software sistema integral de asignación de … · 2018-10-17 · arquitectura...

59
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

Upload: others

Post on 12-Apr-2020

3 views

Category:

Documents


0 download

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