5. Arquitectura de la librería
Puesto que a fecha de realización del presente documento los servicios que se ofrecen para acceder a la información no permiten acceder a todo el catálogo de entidades almacenadas, la única forma de acceder actualmente a dicha información es haciendo uso de Réplicas de base de datos.
Ya que el acceso a la información a través de réplicas de base de datos no está aconsejado por la gran dependencia que genera entre diferentes productos, la librería de acceso a la Callejero se ha desarrollado siguiendo un modelo de API/Implementación que permite exponer a los usuarios de la librería una API única que debe ser usada y una serie de implementaciones de dicha API, las cuales serán las verdaderas encargadas de acceder a la información.
Siguiendo este patrón se ha iniciado el desarrollo con una única implementación haciendo uso de réplicas (por ser la única forma posible actualmente), esperando que en un futuro se generen nuevas implementaciones que hagan uso de distintos métodos de acceso (SOAP, REST, etc.). Los productos que estén ya desarrollados y haciendo uso de la API estándar podrán cambiar fácilmente de implementación si que el producto se vea afectado.
Requerimientos
| UI Expand |
|---|
|
Siguiendo la normativa vigente para desarrollo de aplicaciones Java en el SAS, la librería se ha implementado con Java 7 y ha sido testada en Oracle Weblogic 12.1.3, donde se ha creado proyectos de prueba que incorporan la librería a través de Maven. |
| UI Expand |
|---|
|
Siguiendo la normativa vigente para desarrollo de aplicaciones Java en el SAS, la librería se ha implementado con Java 21, Jakarta 10 y Microprofile 6.1 y ha sido testada en Openliberty 24.X.X.X, donde se ha creado proyectos de prueba que incorporan la librería a través de Maven. |
Instalación
La librería desarrollada se encuentra desplegada en el repositorio de artefactos corporativo pudiendo ser incorporada en nuestro proyecto haciendo uso de maven:
| UI Expand |
|---|
|
| Bloque de código |
|---|
| language | xml |
|---|
| title | Pom Padre |
|---|
| collapse | true |
|---|
| <dependencyManagement>
<dependencies>
<dependency>
<groupId>es.ja.csalud.sas.componentescomunes.callejeroApiClient</groupId>
<artifactId>callejeroApiClient</artifactId>
<version>${callejeroapi.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependencies>
<dependencyManagement> |
| Bloque de código |
|---|
| language | xml |
|---|
| title | Pom módulo uso |
|---|
| collapse | true |
|---|
| <!-- Añadir en caso de hacer uso de la interfaz-->
<dependencies>
<dependency>
<groupId>es.ja.csalud.sas.componentescomunes.callejeroApiClient</groupId>
<artifactId>callejeroApiClient-api</artifactId>
<version>${callejeroapi.version}</version>
</dependency>
<!-- Añadir en caso de hacer uso de la implementación-->
<dependency>
<groupId>es.ja.csalud.sas.componentescomunes.callejeroApiClient</groupId>
<artifactId>callejeroApiClient-jpa</artifactId>
<version>${callejeroapi.version}</version>
</dependency>
<dependencies>
|
|
Configuración
Antes de comenzar a configurar nuestro proyecto, conviene recordar que la implementación de la API desarrollada con la que se cuenta actualmente se basa en acceso a la información a partir de un origen de datos específico para el acceso a sus datos, mientras que por otro lado la aplicación podrá tener otro origen de datos distinto para acceder a sus datos, de esta forma la aplicación puede estar en una base de datos mientras que la información sea recuperada de otra distinta.
Dicho esto, y siendo consciente de que existen diferentes formas de hacer lo mismo, a continuación se expone una serie de instrucciones a seguir para configurar un proyecto web que haga uso de esta librería y que se ejecutará en un contenedor Weblogic:
Configurar origen de datos
| UI Expand |
|---|
|
En Weblogic: El primer paso a seguir será configurar el origen de datos en Weblogic, donde debemos crear un origen de datos que tenga visibilidad con las tablas de réplicas alojados en un esquema llamado REP_PRO_XXX. Por ejemplo, nuestro origen de datos podría llamarse "jdbc/Diraya-Callejero-DS" |
| UI Expand |
|---|
|
En Openliberty >= 24.X.X.X:
| Bloque de código |
|---|
| language | xml |
|---|
| title | server.xml |
|---|
| collapse | true |
|---|
| <server>
....
<include location="persistence-config-oracle-callejero.xml" /> <!-- Se puede modificar el nombre del fichero por el que resulte más adecuado para el ejemplo usaremos este -->
....
</server> |
| Bloque de código |
|---|
| language | xml |
|---|
| title | persistence-config-oracle-estructura.xml |
|---|
| collapse | true |
|---|
| <server>
<!-- Oracle driver -->
<jdbcDriver id="oracle19-driver" libraryRef="oracle19-library" />
<!-- Oracle driver library -->
<library id="oracle19-library">
<fileset dir="${server.config.dir}/lib/oracle" includes="ojdbc*.jar" />
</library>
<!-- Datasource -->
<dataSource id="oracle" jndiName="jdbc/Diraya-Bdu-DS" queryTimeout="20s">
<jdbcDriver libraryRef="oracle19-library"/>
<properties.oracle URL="${jdbc.url}" user="${jdbc.user}" password="${jdbc.password}" /> <!-- queda a criterio del programador determinar las variables correctas. En caso de contenerizar el servidor, se deberá hacer uso de las secret y configmap descritos en el helm de despliegue -->
</dataSource>
</server> |
Para que funcione la configuración de conexión a la bbdd se deben seguir las pautas del readme.md del arquetipo. En resumen: | Bloque de código |
|---|
| language | xml |
|---|
| title | pom.xml del boot |
|---|
| collapse | true |
|---|
| <plugins>
<plugin>
<groupId>io.openliberty.tools</groupId>
<artifactId>liberty-maven-plugin</artifactId>
<configuration>
<copyDependencies>
<dependencyGroup>
<location>lib/oracle</location>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<version>${oracle.version}</version>
</dependency>
</dependencyGroup>
</copyDependencies>
</configuration>
</plugin> |
|
Configurar persistence.xml: Configurar el fichero persistence.xml de nuestro proyecto web para añadir el orígen de datos configurado previamente. En este fichero se le asignara un nombre a la unidad de persistencia que posteriormente usará nuestro código a través de JPA. En el siguiente extracto puede verse como se crea una unidad de persistencia llamada "Diraya-Callejero-Persistence-Unit" y que es mapeada con el origen de datos que creamos previamente:
| Bloque de código |
|---|
|
<persistence-unit name="Diraya-Callejero-Persistence-Unit" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/Diraya-Callejero-DS</jta-data-source>
<mapping-file>META-INF/callejero-bd-replica.xml</mapping-file>
<class>es.ja.csalud.sas.componentescomunes.callejero.impl.*</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
</persistence-unit> |
Es importante destacar que para aislar la unidad de persistencia del resto de la aplicación y evitar posibles conflictos, es recomendable añadir la etiqueta "class" y "exclude-unlisted-classes" con el valor que puede verse en el ejemplo para que la unidad de persistencia sólo actúe sobre el paquete indicado.
En cuanto al fichero de mapeo de entidades, pueden usarse cualquiera de los siguientes mapeos:
- META-INF/callejero-bd-replica.xml: Cuando nuestra cadena de conexión apunte a una base de datos donde existe una réplica en el esquema REP_PRO_XXX. Este será la configuración usada en la mayoría de los casos
- META-INF/callejero-bd-original.xml: Cuando nuestra cadena de conexión apunte directamente a la base de datos
- Cualquier otra configuración requerirá que el fichero xml sea redefinido por la aplicación que hace uso de la librería
Asignar EntityManager a la librería : Una vez configurada la unidad de persistencia sólo nos quedaría indicarle a la librería cuál va a ser el contexto de persistencia que queremos que use, ya que como se ha mencionado previamente, nuestra aplicación puede tener varios orígenes de datos distintos. Para ello nuevamente existen diferentes formas de hacerlo, a continuación se muestra una manera muy simple consistente en crear una clase que es ejecutada al iniciar nuestro servidor y se encarga de asignarle a la librería el contexto de persistencia a usar. A partir de este momento nuestra librería es completamente funcional.
| UI Expand |
|---|
|
| Bloque de código |
|---|
| language | java |
|---|
| title | Callejero EntityManager Config |
|---|
| collapse | true |
|---|
| @Singleton
@Startup
public class DaoEntityManagerConfig {
@PersistenceContext(unitName = "Diraya-Callejero-Persistence-Unit")
private EntityManager callejeroEntityManager;
@PostConstruct
public void init() {
EntityManagerContainer.setEntityManager(callejeroEntityManager);
}
} |
|
| UI Expand |
|---|
|
| Bloque de código |
|---|
| language | java |
|---|
| title | Callejero EntityManager Config |
|---|
| collapse | true |
|---|
| import es.ja.csalud.sas.componentescomunes.callejero.impl.jpa.control.config.EntityManagerContainer;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.Initialized;
import jakarta.enterprise.event.Observes;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
@ApplicationScoped
public class EntityManagerProducer {
@PersistenceContext(unitName = "Diraya-Callejero-Persistence-Unit")
private EntityManager callejeroEntityManager;
public void init(@Observes @Initialized(ApplicationScoped.class) Object pointless) {
EntityManagerContainer.setEntityManager(callejeroEntityManager);
}
} |
|
Generar configuración de la API : El componente funciona en base a Futures, se hace necesario el uso de un Executor encargado de gestionar los hilos que se vayan lanzando en el sistema. Para ello bastará con añadir un Produces en nuestro proyecto como el siguiente:
| UI Expand |
|---|
|
| Bloque de código |
|---|
| language | java |
|---|
| title | Productor Estructura Api Config |
|---|
| collapse | true |
|---|
| @Produces
@Singleton
public CallejeroApiConfig producerCallejeroApiConfig() {
return new CallejeroApiConfigBuilder().executorPoolSize(20).build();
} |
|
| UI Expand |
|---|
|
| Bloque de código |
|---|
| language | java |
|---|
| title | Productor Estructura Api Config |
|---|
| collapse | true |
|---|
| import es.ja.csalud.sas.componentescomunes.callejero.impl.jpa.control.config.CallejeroApiConfig;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Singleton;
import org.eclipse.microprofile.context.ManagedExecutor;
import org.eclipse.microprofile.context.ThreadContext;
@ApplicationScoped
public class CallejeroContext {
@Produces
@Singleton
public CallejeroApiConfig producerCallejeroApiConfig() {
ManagedExecutor executor = ManagedExecutor.builder()
.propagated(ThreadContext.CDI, ThreadContext.APPLICATION)
.maxAsync(20)
.maxQueued(20)
.build();
return new CallejeroApiConfig.CallejeroApiConfigBuilder().executor(executor).executorPoolSize(20).build();
}
} |
|
| Nota |
|---|
|
Es especialmente importante ser consciente de la forma de funcionar de un Produces, ya que si en cada inyección se realiza una llamada al Produces se creará en cada llamada un Executor diferente, generando un problema de rendimiento en el servidor por acumulación de hilos. Por tanto, queda a responsabilidad del programador que hace uso de la librería el asegurar que sólo se genere un Executor para toda la librería o por servicio. En el presente ejemplo esto se ha conseguido haciendo uso de @Singleton, pero igualmente podría conseguirse mediante variables estáticas, etc. |