b3t6 Java
b3t6 Java
Bloque 3 - Tema 6
ARQUITECTURA JAVA EE/JAKARTA EE Y
PLATAFORMA .NET: COMPONENTES,
PERSISTENCIA Y SEGURIDAD. CARACTERÍSTICAS,
ELEMENTOS, LENGUAJES Y FUNCIONES DE AMBOS
ENTORNOS. DESARROLLO DE INTERFACES
PREPARACIÓN OPOSICIONES
TÉCNICOS AUXILIARES DE INFORMÁTICA
B3T6 JAKARTA EE Y .NET TAI
ÍNDICE
ÍNDICE ............................................................................................................................................................ 2
1. ARQUITECTURA JAKARTA EE ..................................................................................................................... 3
1. Arquitectura ......................................................................................................................................... 5
2. Servidor Jakarta EE y contenedores ..................................................................................................... 8
3. Componentes ..................................................................................................................................... 12
4. Servicios.............................................................................................................................................. 24
5. Persistencia ........................................................................................................................................ 29
6. Seguridad ........................................................................................................................................... 47
7. Empaquetamiento y despliegue de aplicaciones................................................................................ 50
8. Frameworks y otras APIs .................................................................................................................... 51
2. PLATAFORMA .NET.................................................................................................................................. 54
1. .NET Framework ................................................................................................................................. 56
2. Arquitectura ....................................................................................................................................... 61
3. Persistencia ........................................................................................................................................ 71
4. Seguridad ........................................................................................................................................... 81
5. Administrador de paquetes ................................................................................................................ 83
6. Frameworks y otras APIs .................................................................................................................... 84
1. ARQUITECTURA JAKARTA EE
Las arquitecturas web han revolucionado el panorama del desarrollo de software en los
últimos años. Esta revolución se ha debido a diferentes causas de entre las que destacan
poderosamente la explosión de Internet y sus protocolos, y el apoyo por parte de la industria
a este nuevo paradigma de aplicación. El desarrollo de sistemas corporativos basados en una
arquitectura Web es algo relativamente reciente.
Durante los años 90, los desarrollos de aplicaciones corporativas se diseñaban con
tecnología cliente/servidor. La implantación de la tecnología cliente/servidor no se hizo sin
problemas ya que dieron lugar a entornos heterogéneos y distribuidos que eran muy difíciles
de integrar y sobre todo de gestionar.
El objetivo inicial de alcanzar flexibilidad, acceso rápido y seguro a los datos corporativos, a
un precio razonable, seguía siendo una meta por conseguir. El coste de gestión de estos
sistemas era enorme y las corporaciones seguían buscando una nueva tecnología que
resolviese al menos algunos de estos problemas.
A finales de los 90, gran número de desarrollos corporativos empezaron a aprovechar los
estándares, lenguajes y protocolos surgidos alrededor de la Web, creándose el concepto de
las arquitecturas multicapa, que se presentaban como alternativa a la arquitectura
cliente/servidor clásica, que permitiría utilizar un entorno cliente ligero y, por lo tanto, evitar
el problema de la distribución y mantenimiento del software de los PCs cliente.
Indudablemente estos inicios fueron duros ya que la tecnología que se estaba utilizando no
había sido inicialmente pensada para lo que ahora se quería utilizar. Las empresas de
software iniciaron una carrera para conseguir adaptar los protocolos, lenguajes y estándares
de Internet, que parecían claramente asentados en un tipo de aplicaciones con gran
cantidad de información estática e interfaces de usuario sencillas, a las necesidades de los
desarrollos corporativos estratégicos. Java es uno de estos lenguajes que aparecieron
alrededor de Internet y ha impulsado el desarrollo de aplicaciones con arquitectura Web
como ningún otro lenguaje.
La complejidad de las arquitecturas web seguía siendo bastante importante, poco a poco se
definieron recomendaciones y estándares que intentaron simplificarlo. Con la publicación de
las especificaciones J2EE (Java 2 Enterprise Edition) se dio el impulso definitivo para la
entrada de esta tecnología en el ámbito empresarial, con muchas menos dudas, ya que estos
estándares sí fueron pensados para la problemática de complejos desarrollos corporativos y
se ha convertido en la base para los próximos años de la arquitectura de desarrollo para la
Web con tecnología Java.
NOVEDAD
La plataforma Java EE 8 es la última versión especificada por Oracle en el año 2017. A partir
de ese momento la organización Eclipse Foundation es la nueva encargada. Como Java es
una marca registrada por Oracle, en 2018 Eclipse cambió el nombre de Java EE a Jakarta EE.
Actualmente, versión 10.
Jakarta EE modifica el nombre de los JCP a Eclipse [Link] Working Group ([Link]).
1. Arquitectura
Los desarrollos basados en arquitecturas multicapa, como es el caso de Jakarta EE, utilizan
dos conceptos que conviene aclarar:
- Capa: una capa es una funcionalidad de la aplicación separada del resto. Por tanto, desde
un punto de vista lógico, una aplicación se puede dividir en varias capas.
- Nivel: un nivel es un entorno físico donde residen una o varias capas. Es un enfoque
desde un punto de vista físico.
Jakarta EE Jakarta EE
Application 1 Application 2
Client
Client Machine
Tier
Application Web
Client Pages
Jakarta Server
Pages
Faces Web
Tier
Jakarta EE
Server
Enterprise Enterprise
Beans Beans Business
Tier
EIS Database
Database Database Server
Tier
Por lo general, las aplicaciones de varias capas tienen una capa de cliente, una capa de
negocio y una capa de datos. El nivel de cliente consta de un programa de cliente que realiza
solicitudes al nivel de servidor. Éste se divide en una capa web y una capa de lógica de
negocio, que manejan las solicitudes de los clientes y procesan los datos de la aplicación,
almacenándolos en un almacén de datos permanente en el nivel de datos. El desarrollo de
aplicaciones Jakarta EE se concentra en la capa web y de negocio.
Los clientes pueden ser un navegador web, una aplicación independiente u otros
servidores, y se ejecutan en una máquina diferente del servidor Jakarta EE.
Algunas de las principales tecnologías Jakarta EE que se utilizan en la capa son (en la imagen,
todas las APIs):
- Jakarta Faces (JSF): un marco de componentes de interfaz de
usuario para aplicaciones web que le permite incluir
componentes de IU (como campos y botones) en una página
HTML, llamada página Facelets; convierten y validan datos de
componentes de la interfaz de usuario, guardan datos de
componentes de la IU en almacenes de datos del lado del
servidor y mantienen el estado del componente.
- Jakarta Servlets: clases del lenguaje de programación Java que
procesan dinámicamente solicitudes y construyen respuestas,
generalmente para páginas HTML.
- Jakarta Server Pages (JSP): nos permite incrustar en el código
HTML código Java para generar las partes dinámicas.
En esta capa se encuentran las siguientes tecnologías Jakarta EE (en la imagen, todas las
APIs):
- Componentes Jakarta Enterprise Beans (versión actual 4.0) (en Java
EE, EJB).
- Jakarta RESTful Web Services (en Java EE, JAX-RS, Java API for RESTful
Web Services): API para desarrollo de servicios web RESTful.
- Jakarta XML Web Services (en Java EE, JAX-WS, Java API for XML Web
Services): provee funcionalidad para servicios web que utilizan
mensajes XML y que siguen el estándar SOAP.
- Jakarta SOAP with Attachments (en Java EE, SAAJ, SOAP with
Attachments API for Java): API que permite la producción y el
consumo de mensajes que cumplen con las especificaciones
SOAP.
Los servidores Jakarta EE que cumplen las especificaciones Jakarta EE se les denomina
servidores de aplicaciones certificados.
PRODUCTO COMPAÑÍA
GlassFish Server Open Source Código abierto
Eclipse GlassFish Eclipse Foundation
WebSphere IBM
WebLogic Oracle
Java EE
JOnAS ObjectWeb
JBoss Red Hat
TongWeb Application Server TongTech
WildFly WildFly
Apusic AAS Apusic
BES Application Server BES
Eclipse GlassFish Eclipse Foundation
Software Enterprise Application Platform Fujitsu
WebSphere Liberty IBM
Jakarta EE 10
InforSuite Application Server Infors
PLATFORM
Open Liberty Open Liberty
Server Community y Server Enterprise Payara
JBoss Enterprise Application Platform Red Hat
TongWeb Application Server TongTech
WildFly WildFly
Eclipse GlassFish Eclipse Foundation
- El contenedor EJB es la interfaz entre los beans empresariales, que proporciona la lógica
empresarial de una aplicación Jakarta EE, y se ubica en el servidor Jakarta EE. El
contenedor EJB se ejecuta en el servidor Jakarta EE y gestiona la ejecución de los beans
empresariales de una aplicación.
Interoperabilidad
Muchas de las API proveen interoperabilidad con componentes que no forman parte de la
plataforma Jakarta EE, como servicios web externos o CORBA. Jakarta EE Interoperability
ofrece las facilidades de interoperabilidad que pueden estar disponibles en la plataforma
Jakarta EE.
HTT P
IIOP IIOP HTT P
SSL SSL
SOAP SOAP
JRMP JRMP EJB / IIOP / SSL
HTT P HTT P
Web EJB
Container Container Database
Application
Client
Container
Jakarta EE Platform
JRMP IIOP
SOAP HTT P
HTT P SSL
Java RMI (RMI, Remote Method Invocation) es una tecnología que proporciona
comunicación remota entre programas escritos en el lenguaje Java, permitiendo tener los
objetos distribuidos en diversas máquinas, esto es, que un objeto que se ejecuta en una JMV
(máquina virtual Java) invoque métodos en un objeto que se ejecuta en
otra JVM. Anterior a esta tecnología, para realizar llamadas a funciones y
procedimientos remotos se usaba (RPC, Remote Procedure Calls).
Cada servicio RMI (objeto remoto) se define mediante una interface, que especifica los
métodos que se pueden invocar en el objeto remoto. Esta interface debe estar disponible en
el cliente y en el servidor. Además, se puedan pasar argumentos al método remoto y recibir
los datos que devuelve (tipos primitivos u objetos de clases que sean serializables).
Java IDL (IDL, Interface Description Language) es una implementación CORBA que permite
que dos objetos interactúen sobre diferentes plataformas a través de una red. Al ser una
interfaz, posibilita que objetos escritos con diferentes lenguajes (a diferencia de Java RMI)
interactúen entre sí.
3. Componentes
Los componentes se despliegan y ejecutan en contenedores especializados.
(1) Servlets
Un servlet es una clase de lenguaje de programación Java que se utiliza para ampliar las
capacidades de los servidores que alojan aplicaciones a las que se accede mediante un
modelo de programación de petición/respuesta. Se utilizan en los servidores web
proporcionando contenido dinámico al usuario. Para este tipo de aplicaciones, la tecnología
Java Servlet define clases de servlet específicas de HTTP.
Los servlets son pequeños programas escritos en Java que admiten peticiones a través del
protocolo HTTP. Por lo tanto, los servlets pueden recibir peticiones desde un navegador
web, procesarlas, y devolver una respuesta al navegador, normalmente en HTML. Para
realizar estas tareas podrán utilizar las clases incluidas en el lenguaje Java.
- La clase a implementar debe extender un servlet del API. Como las aplicaciones a
desarrollar son aplicaciones web utilizaremos como clase base el servlet HttpServlet,
que implementa el comportamiento de un servlet capaz de trabajar con el protocolo
http:
public class MiClase extends HttpServlet { ... }
La clase HttpServlet es una clase abstracta de la que heredarán todos los servlets
destinados a dar servicios desde un contenedor web. Los métodos más interesantes y
que un servlet puede sobrecargar son los siguientes:
o doGet(): se ejecuta cuando se recibe una petición HTTP GET.
o doPost(): se ejecuta cuando se recibe una petición HTTP POST.
o doPut(): se ejecuta cuando se recibe una petición HTTP PUT.
o doDelete(): se ejecuta cuando se recibe una petición HTTP DELETE.
o init() y destroy(): gestionan el ciclo de vida del servlet, ejecutándose en la creación
y destrucción del servlet.
o getServletInfo(): lo utiliza el servlet para proporcionar información acerca de sí
mismo.
o service(): maneja la petición HTTP para redirigir al método doXXX que corresponda.
- Finalmente se sobrescriben los métodos doXXX según los tipos de peticiones que se vayan
a tratar.
Ejemplo:
<html>
<body>
<form action="ArgumentosPost" method="post">
<label for="nombre">Nombre<label/>
<input type="text" name="nombre" size="25" maxlength="50"><br/>
<label for="apellidos">Apellidos<label/>
<input type="text" name="apellidos"
size="35" maxlength="100"><br/>
<input type="submit" value="Enviar"/>
<input type="reset" value="Borrar"/>
</form>
</body>
</html>
import [Link].*;
import [Link].*;
import [Link].*;
Ejemplo: aplicación web que cuenta el número de veces que accedemos o recargamos una
página mientras la sesión está activa.
import [Link].*;
import [Link].*;
import [Link].*;
public class Contador extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = [Link]();
HttpSession session = [Link](true);
Integer contador;
if ([Link]()) {
[Link]("Hola. ");
contador = new Integer(0);
} else {
[Link]("Hola de nuevo. ");
contador = (Integer)[Link]("valor");
}
Integer nuevoValor = new Integer([Link]()+1);
[Link]("valor", nuevoValor);
[Link]("En la sesión: "+[Link]()+
" el contador vale " + contador + "\n");
}
}
(2) Faces
Jakarta Faces es un framework IU para aplicaciones web Java. Está diseñado para reducir
significativamente la carga de escribir y mantener aplicaciones que se ejecutan en un
servidor de aplicaciones Java. Jakarta Faces:
- Facilita la construcción de IU a partir de un conjunto de componentes de interfaz de
usuario reutilizables.
- Simplifica la migración de los datos de la aplicación hacia y desde la IU.
- Ayuda a gestionar el estado de la IU en todas las solicitudes del servidor.
- Proporciona un modelo sencillo para comunicar eventos generados por el cliente al
servidor.
- Permite crear y reutilizar fácilmente los componentes de IU personalizados.
La página web [Link] está construida utilizando etiquetas de componente JSF, las
cuales se utilizan para agregar componentes a la vista (myView), que es la representación de
la página en el lado del servidor. La página web también puede hacer referencia a objetos,
como eventos, validadores y conversores que estén registrados en los componentes, y
también a los componentes JavaBeans que capturan los datos y procesan la funcionalidad
específica de la aplicación de los componentes.
Por último, recordamos que tanto Jakarta Faces como JSF son una especificación, por lo que
necesitamos de un framework que implemente dicha especificación. Entre las
implementaciones destacamos:
- Eclipse MojarraTM (incluido en Eclipse GlassFish) es una implementación que define un
marco MVC para crear IU para aplicaciones web, incluidos los componentes de la IU, la
gestión del estado, la entrega de eventos, la validación de entradas, la navegación por
páginas y el soporte para la internacionalización y la accesibilidad.
- Apache MyFaces.
(3) JSP
JSP es un lenguaje que permite insertar etiquetas de distintos tipos que añaden
comportamiento dinámico a nuestras páginas. JSP se considera un nivel de abstracción por
encima de los servlets, ya que las páginas JSP se transforman en servlets para ejecutarse.
Ejemplo:
<%@page import="[Link].*"%>
<%! String cadena="Hola Mundo!!!"; %>
<html>
<body>
<%= cadena %>
</body>
</html>
Salvo por algunos detalles, el código incluido entre las etiquetas <%...%> es código Java
normal y corriente: podemos definir variables, mostrar su contenido, debemos incluir
paquetes, etc.
Se puede incluir código Java dentro de las páginas JSP de 3 formas distintas:
- Expresiones: que se evalúan y el resultado se muestra en el navegador. Pueden ser tan
sencillas como <%= cadena %> incluida en el ejemplo anterior o pueden contener
concatenaciones y acceso a atributos estáticos de clases de java.
Ejemplo:
<%@page import="[Link].*"%>
<html>
<body>
<%= "El valor del número Pi es: "+[Link] %>
</body>
</html>
- Scriptlets: son fragmentos de código Java entre las etiquetas <% ... %>. Para poder
mostrar cosas en el navegador debemos utilizar el objeto implícito out.
Ejemplo:
<%@page import="[Link].*"%>
<html>
<body>
<%
[Link]("<table border=\"1\">");
for(int i='a', j=0; i<='z'; i++, j++) {
[Link]("<tr>");
[Link]("<td>"+j+"</td>");
[Link]("<td>"+(char)i+"</td>");
[Link]("</tr>");
}
[Link]("</table>");
%>
</body>
</html>
- Declaraciones: que se encuentran entre los símbolos <%! ... %>. Las variables
declaradas se consideran globales. En el ejemplo “hola mundo”, podemos ver cómo se
declara una variable global de tipo String que luego se utiliza.
Ejemplo:
<%! String cadena="Hola Mundo!!!"; %>
- <%@include ... %>: nos permite incluir un fichero dentro de otro. Simplemente copia el
contenido de un fichero dentro de otro.
- <%@taglib ... %>: se utiliza en el uso de JSTL1 (JavaServer Pages Standard Tag Library).
Las acciones tienen diversos usos, como por ejemplo incluir la salida resultante de ejecutar
un fichero JSP en otro. Podemos escribir un fichero [Link] de la forma.
Ejemplo:
<html>
<body>
<jsp:include page="[Link]"/>
</body>
</html>
En JSP existen los denominados objetos implícitos. Estos objetos no necesitan ser
instanciados y nos permitirán realizar multitud de acciones. Normalmente serán objetos que
en los servlets se recibían como argumentos de los métodos.
- request: Es un objeto de tipo HttpServletRequest que nos ofrece, fundamentalmente,
acceso a los parámetros de la petición realizada al servlet.
1
Extiende JSP proporcionando cuatro bibliotecas de etiquetas: core, xml, sql y fmt.
- out: el objeto out, instancia de la clase JspWriter, permite escribir la salida que recibirá
el navegador.
- session: objeto de la clase HttpSession que nos permite trabajar con sesiones.
La gestión de errores en páginas JSP se realiza mediante excepciones. JSP incluye dos
directivas para el tratamiento de excepciones: errorPage y isErrorPage. Para indicar en una
página JSP que página se va a encargar de tratar la excepción debemos utilizar la directiva:
<%@page errorPage="..." %>
Ejemplo: Si el parámetro es un número no hay problema, pero si se para algo que no pueda
transformarse en un entero se creará una excepción y nos redirige a la página de errores.
<%@page errorPage="[Link]" %>
<html>
<body>
<p>
Número: <%= [Link]([Link]("numero")) %>
</p>
</body>
</html>
El único problema es que podemos mostrar una nueva web en caso de error, pero no
podemos trabajar con la excepción generada. Para eso debemos utilizar isErrorPage:
<%@page isErrorPage = "true"%>
Ejemplo:
<%@ page isErrorPage = "true"%>
<% if (exception != null) {
[Link](new [Link](out));
} %>
Para trabajar con sesiones lo primero es indicar en la página web que se va a usar una
sesión:
<%@page session="true" %>
Después se trabajará con el objeto implícito session, que nos permitirá añadir y eliminar
atributos de la sesión. También nos permitirá eliminar la sesión.
Ejemplo:
<%@page session="true" %>
<%
Por último, al definir una página JSP nos interesa indicar mediante la directiva @page la
codificación de la propia página y tipo de contenido del resultado de la ejecución de dicha
página. Para ello, utilizamos:
<%@page pageEncoding="UTF-8" contentType="text/html;charset=UTF-8"%>
(4) EJB
La arquitectura se define en Jakarta Enterprise Beans. Escrito en el lenguaje de
programación Java, un Enterprise Java Bean es, por tanto, una clase, un componente del
lado del servidor que encapsula la lógica de negocios de una aplicación. La lógica de negocios
es el código que cumple el propósito de la aplicación.
Ejemplo: en una aplicación de control de inventario, los beans pueden implementar la lógica
de negocio en métodos llamados checkInventoryLevel y orderProduct. Al invocar estos
métodos, los clientes pueden acceder a los servicios de inventario proporcionados por la
aplicación.
Debemos considerar el uso de EJB si la aplicación tiene alguno de los siguientes requisitos:
- La aplicación debe ser escalable. Para dar cabida a un número creciente de usuarios, es
posible que haya que distribuir los componentes de una aplicación en varias máquinas.
Los beans empresariales de una aplicación no solo pueden ejecutarse en diferentes
máquinas, sino que también su ubicación permanecerá transparente para los clientes.
- Las transacciones deben garantizar la integridad de los datos. Los beans admiten
transacciones, los mecanismos que administran el acceso concurrente de objetos
compartidos.
- La aplicación tendrá una variedad de clientes. Con solo unas pocas líneas de código, los
clientes remotos pueden localizar fácilmente beans empresariales. Estos clientes pueden
ser diversos y numerosos.
o Stateful (con estado): el estado de un objeto consiste en los valores de sus variables
de instancia. En un bean de sesión con estado, las variables de instancia representan
el estado de una sesión única del bean. Debido a que el cliente interactúa ("habla")
con su bean, este estado a menudo se denomina estado de conversación.
@Remote
public interface Cart {
public void initialize(String person) throws BookException;
public void initialize(String person, String id)
throws BookException;
public void addBook(String title);
public void removeBook(String title) throws BookException;
public List<String> getContents();
public void remove();
}
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Stateful
public class CartBean implements Cart {
String customerId;
String customerName;
List<String> contents;
@Override
public void initialize(String person) throws BookException {
if (person == null) {
throw new BookException("Null person not allowed.");
} else {
customerName = person;
}
customerId = "0";
contents = new ArrayList<>();
}
@Override
public void initialize(String person, String id)
throws BookException {
if (person == null) {
throw new BookException("Null person not allowed.");
} else {
customerName = person;
}
@Override
public void addBook(String title) {
[Link](title);
}
@Override
public void removeBook(String title) throws BookException {
boolean result = [Link](title);
if (result == false) {
throw new BookException("\"" + title + " not in cart.");
}
}
@Override
public List<String> getContents() {
return contents;
}
@Remove
@Override
public void remove() {
contents = null;
}
}
Desde la clase CartClient se podrían hacer las siguientes invocaciones de
métodos:
[Link]("Pablo Arellano", "123");
[Link]("Bel Canto");
List<String> bookList = [Link]();
[Link]("Pensando en Java");
Debido a que pueden admitir múltiples clientes, los beans de sesión sin estado
pueden ofrecer una mejor escalabilidad para aplicaciones que requieren un gran
número de clientes. Por lo general, una aplicación requiere menos beans de sesión
sin estado que beans de sesión con estado para admitir la misma cantidad de
clientes.
Un bean de sesión sin estado puede implementar un servicio web, pero un bean de
sesión con estado no puede.
@Stateless // Anotaciones
public class ConverterBean {
private BigDecimal yenRate = new BigDecimal("108.393");
private BigDecimal euroRate = new BigDecimal("0.00842769");
o Singleton: un bean de sesión singleton se instancia una vez por aplicación y existe
para el ciclo de vida de la aplicación. Los beans de sesión Singleton están diseñados
para circunstancias en las que una única instancia de Enterprise Bean es compartida y
accedida simultáneamente por los clientes.
Los beans de sesión Singleton ofrecen una funcionalidad similar a los beans de sesión
sin estado, pero difieren de ellos en que solo hay un bean de sesión Singleton por
aplicación, a diferencia de un grupo de beans de sesión sin estado, cualquiera de los
cuales puede responder a una solicitud del cliente. Al igual que los beans de sesión
sin estado, los beans de sesión singleton pueden implementar puntos finales de
servicio web.
Las aplicaciones que usan un bean de sesión singleton pueden especificar que el
singleton se debe instanciar al inicio de la aplicación, lo que permite que el singleton
realice tareas de inicialización para la aplicación. El singleton también puede realizar
tareas de limpieza en el cierre de la aplicación, porque el singleton operará durante
todo el ciclo de vida de la aplicación.
Un bean controlado por mensajes es un bean que permite a las aplicaciones Jakarta EE
procesar mensajes de forma asincrónica. Este tipo de bean normalmente actúa como un
listener de mensajes JMS, que es similar a un listener de eventos pero recibe mensajes
JMS en lugar de eventos. Los mensajes pueden ser enviados por cualquier componente
Jakarta EE (un cliente de aplicación, otro bean empresarial o un componente web) o por
una aplicación o sistema JMS que no utiliza la tecnología Jakarta EE. Los beans
controlados por mensajes pueden procesar mensajes JMS u otros tipos de mensajes.
- Bean de ENTIDAD (entity): (opcional) es un objeto de entidad que forma parte del modelo
de dominio, proporcionando una vista de los datos de la base de datos.
4. Servicios
En este apartado se relacionan las APIs y servicios de la arquitectura:
- Jakarta Activation (en Java EE, JAF, JavaBeans Activation Framework): define un conjunto de
servicios estándar para determinar el tipo de datos, encapsular el acceso a ellos,
descubrir las operaciones disponibles en ellos y crear el componente JavaBeans
apropiado para realizar esas operaciones.
- Jakarta Batch: especifica una API de Java más un lenguaje de especificación de trabajos
basado en XML, que permite componer trabajos por lotes en XML a partir de artefactos
de aplicaciones Java reutilizables y parametrizar convenientemente diferentes
ejecuciones en un solo trabajo.
- Jakarta Debugging Support for Other Languages: mecanismo mediante el cual los
programas ejecutados en la JVM pero escritos en lenguajes distintos a Java se pueden
depurar con referencias a la fuente original (por ejemplo, referencias de archivos fuente
y números de línea).
- JNDI (Java Naming and Directory Interface): API para servicios de directorio
o nombrado (LDAP, DNS, RMI, CORBA, sistema de ficheros…).
Capa de presentación
- Jakarta Faces.
- Jakarta Pages.
- Jakarta Servlet.
- Jakarta Standard Tag Library (en Java EE, JSTL, JavaServer Pages Standard Tag Library): bibliotecas
de etiquetas que encapsula como etiquetas simples la funcionalidad principal común a
muchas aplicaciones web. JSTL tiene soporte para tareas comunes y estructurales como
iteración y condicionales, etiquetas para manipular documentos XML, etiquetas de
internacionalización y etiquetas SQL.
Capa de negocio
- Jakarta Enterprise Beans.
- Jakarta Bean Validation: define un modelo de metadatos y API para Java Bean y
validación de métodos.
Mensajes y comunicaciones
- Jakarta Mail (en Java EE, JavaMail): API para enviar notificaciones por correo electrónico.
- Jakarta Messaging (en Java EE, JMS, Java Messages Service): API que permite a las aplicaciones
crear, enviar, recibir y leer mensajes. Define un conjunto común de interfaces y
semánticas asociadas que permiten que los programas escritos en lenguaje Java se
comuniquen con otras implementaciones de mensajería.
JSON
- Jakarta JSON Binding (JSON-B): proporciona una capa de enlace para convertir objetos
Java hacia y desde mensajes JSON.
- Jakarta JSON Processing (JSON-P): API para analizar, transformar y consultar datos JSON.
Persistencia
- Jakarta Data: ofrece acceso a datos, como bases de datos relacionales y no relacionales,
servicios de datos basados en la nube…
- Jakarta Persistence (en Java EE, JPA, Java Persistence API): proporciona una función de mapeo
de objetos/relacionales para administrar datos relacionales en aplicaciones Java.
- Jakarta Transactions (en Java EE, JTA, Java Transaction API): proporciona una interfaz estándar
para delimitar las transacciones.
- JDBC (Java Database Connectivity): API que permite acceder a las bases de datos
utilizando objetos.
Interoperabilidad
- Jakarta Connectors (en Java EE, Java EE Connector): define una arquitectura estándar para
conectar la plataforma Jakarta EE a sistemas de información empresarial (ERP)
heterogéneos.
- Jakarta XML RPC (en Java EE, JAX-RPC, Java API for XML-based RPC): permite la llamada a
procedimientos remotos utilizando un protocolo basado en XML, es decir, la conexión de
un programa Java con un web service aunque éste no esté desarrollado en Java.
Seguridad
- Jakarta Security (en Java EE, Java EE Security): define un estándar para crear aplicaciones
seguras de Jakarta EE en paradigmas de aplicaciones modernos.
- Jakarta Authentication (en Java EE, JASPIC, Java Authentication Service Provider Interface for
Containers): define una interfaz de proveedor de servicios (SPI) mediante la cual los
proveedores de autenticación que implementan mecanismos de autenticación de
mensajes pueden integrarse en contenedores.
- Jakarta Authorization (en Java EE, JACC, Java Authorization Contract for Containers): especificación
que define un contrato entre un servidor de aplicaciones Jakarta EE y un proveedor de
políticas de autorización.
Servicios web
- Jakarta Enterprise Web Services: define los servicios web para la arquitectura de Jakarta
EE.
- Jakarta XML Registries (en Java EE, JAXR, Java API for XML Registries): encargada de facilitar el
acceso a UDDI para acceder a los registros de negocio.
- Jakarta RESTful Web Services (en Java EE, JAX-RS, Java API for RESTful Web Services): API para
desarrollo de servicios web RESTful.
- Jakarta XML Web Services (en Java EE, JAX-WS, Java API for XML Web Services): provee
funcionalidad para servicios web que utilizan mensajes XML y que siguen el estándar
SOAP.
- Jakarta SOAP with Attachments (en Java EE, SAAJ, SOAP with Attachments API for Java): API que
permite la producción y el consumo de mensajes que cumplen con las especificaciones
SOAP.
Procesamiento XML
- Jakarta XML Binding (en Java EE, JAXB, Java Architecture for XML Binding): proporciona una API y
herramientas que automatizan el mapeo entre documentos XML y objetos Java.
- JAXP (Java API for XML Processing): admite el procesamiento de documentos XML
mediante el modelo DOM o el modelo SAX (API simple para XML). Esta API permite que
las aplicaciones analicen y transformen documentos XML independientemente de una
implementación particular de procesamiento de XML.
El modelo SAX procesa los documentos en serie (hacia delante), convirtiendo los
elementos de un documento XML en una serie de eventos. Cada elemento del
documento XML genera un evento concreto. El desarrollador proporciona los métodos
manejadores para esos eventos que realizarán las acciones deseadas. El procesamiento
con SAX es más rápido por su modo de acceso y menor utilización de memoria.
- StAX (Streaming API for XML): alternativa a SAX y DOM para el procesamiento de
documentos XML.
5. Persistencia
En la capa de lógica de negocio tendremos una “subcapa” dedicada al acceso de los datos
ubicados en el nivel de datos. La subcapa de acceso a los datos se puede llevar a cabo de 2
formas diferentes:
- JDBC: como ya se ha comentado, las aplicaciones pueden utilizar el API JDBC para
acceder a los datos en un sistema de gestión de bases de datos relacionales (RDBMS).
- ORM: mediante el mapeo objeto/relacional a través de frameworks que implementen
JPA.
- JNDI: se utiliza este API para acceder a datos en directorios, tipo LDAP.
JDBC
Para conectarnos con una base datos y trabajar con ella hacemos uso de los paquetes:
import [Link].*;
import [Link].*;
Así pues, para clase del modelo (por ejemplo: persona, venta, factura, expediente, profesor,
alumno…) crearemos un DAO específico.
Ejemplo: si tenemos un sistema que trabaja con alumnos, comentamos las clases a definir
para acceder a los datos de asignaturas. El sistema gestor de base de datos es MySQL. En BD,
se supone creada la tabla asignaturas:
CREATE TABLE asignaturas (
idasignatura int(11) NOT NULL AUTO_INCREMENT,
nombre varchar(100),
PRIMARY KEY (idasignatura) );
public Asignatura() {}
@Override
public String toString() {
return idAsignatura + " - " + nombre;
}
}
Clase AsignaturaDAO: clase de servicio que se encarga del acceso y manipulación de las
asignaturas en la base datos.
import [Link];
import [Link].*;
public class AsignaturaDAO {
private Connection conexion;
private String driver = "[Link]";
private String url = "jdbc:mysql://localhost:3306/";
private String nombreBD = "academia";
private String user = "pruebas";
private String pass = "pruebas";
public AsignaturaDAO {
try {
[Link](driver);
conexion = [Link](url + nombreBD,
user, pass);
} catch (SQLException e) {
[Link]();
}
}
if ([Link]()) {
aux = new Asignatura([Link](1), [Link](2)));
}
return aux;
}
while ([Link]()) {
[Link](new Asignatura([Link](1),
[Link](2)));
}
return lista;
}
}
Con lo visto hasta ahora, el desarrollo nos vincula a una fuente de datos concreta, MySQL.
Sin embargo, podemos generalizar e independizar (desacoplar) el uso de un DAO en función
de la fuente de datos. Esto significa, que podemos tener almacenados los datos en fuentes
de datos diferentes y que afecta a nuestra aplicación el cambio. Así publicamos una interfaz
genérica de acceso a los datos (InterfazDAO) que especifique los servicios que se pueden
consumir y, por otro lado, creamos una implementación concreta de acceso a los datos
(ImplementacionDAOmysql, ImplementacionDAOsqlserver…) para cada fuente de datos
diferente.
public Asignatura() {}
@Override
public String toString() {
return idAsignatura + " - " + nombre;
}
}
Interfaz IAsignaturaDAO: interfaz con las declaraciones de los métodos para poder manipular
objetos Asignatura.
import [Link];
public interface IAsignaturaDAO {
public void add(String nombre);
public void update(Asignatura a);
public void delete(Asignatura a);
public Asignatura getAsignatura(int id);
public ArrayList<Asignatura> list(String nombre);
}
public AsignaturaDAOMySqlImpl() {
//Igual que constructor AsignaturaDAO
try {
[Link](driver);
conexion = [Link](url + nombreBD,
user, pass);
} catch (SQLException e) {
[Link]();}
if ([Link]()) {
aux = new Asignatura([Link](1), [Link](2)));
}
return aux;
}
while ([Link]()) {
[Link](new Asignatura([Link](1), [Link](2)));
}
return lista;
}
}
En el caso de que cambie la fuente de datos bastará con crear una nueva clase de servicio
AsignaturaDAONuevaFuenteImpl para el acceso concreto al nuevo sistema de base de datos
que implemente la interfaz IAsignaturaDAO.
import [Link];
import [Link].*;
public class AsignaturaDAOOracleImpl implements IAsignaturaDAO {...}
private Connection conexion;
private String driver = "[Link]";
private String url = "jdbc:oracle:thin:@localhost:1521:oracl";
private String user = "pruebas";
private String pass = "pruebas";
public AsignaturaDAOOracleImpl {
try {
[Link](driver);
conexion = [Link](url, user, pass);
} catch (SQLException e) {
[Link]();
}
}
// Resto igual que la implementación para MySQL
}
Notar que para cambiar el proveedor de datos basta con modificar una línea de código
IAsignaturaDAO dao = new AsignaturaDAOMySQLImpl();
por
IAsignaturaDAO dao = new AsignaturaDAOOracleImpl();
import [Link].*;
public class AddAsignatura extends HttpServlet {
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = [Link]();
IAsignaturaDAO dao = new AsignaturaDAOMySQLImpl();
[Link]([Link]("nombre"));
[Link]("La asignatura se ha guardado correctamente!");
ORM
Jakarta Persistence (JPA) es una especificación que proporciona a los desarrolladores de Java
un recurso de mapeo de objeto/relacional (ORM) para administrar datos relacionales en
aplicaciones Java mediante el uso de objetos regulares, denominados POJOs.
Un POJO (Plain Old Java Object) es una clase simple que tiene atributos privados,
constructores y métodos getters y setters para devolver los valores de los atributos o para
asignarles un valor. Para persistir una clase ésta debe cumplir una serie de requisitos:
- Debe tener un constructor público sin argumentos.
- Cada uno de los atributos a persistir debe tener un método get y otro set asociado.
- Debe implementar la interfaz Serializable (paquete [Link]).
public Empresa() { }
Podemos establecer una relación entre una tabla y una clase POJO y entre un registro de la
tabla y un objeto de la clase POJO.
En Java solucionamos problemas de negocio a través de objetos, los cuales tienen estado y
comportamiento. Sin embargo, las bases de datos relacionales almacenan la información
mediante tablas, filas, y columnas, de manera que para almacenar un objeto hay que realizar
una correlación entre el sistema orientado a objetos de Java y el sistema relacional de
nuestra base de datos. JPA es una abstracción sobre JDBC que nos permite realizar dicha
correlación de forma sencilla, realizando por nosotros toda la conversión entre nuestros
objetos y las tablas de una base de datos. Esta conversión se llama ORM (Object Relational
Mapping, Mapeo Relacional de Objetos), y puede configurarse a través de metadatos
mediante:
- Documento XML: se genera un fichero para clase entidad indicando la tabla con la que
se corresponde la clase, la correlación entre cada una de las variables miembro y los
- Anotaciones: el resultado es igual que en el caso anterior, pero sin necesidad de crear un
fichero XML, ya que las correspondencias se establecen en la propia definición de la
clase.
@Column(name="nombre")
private String nombre;
o @OneToOne: para establecer una relación de uno a uno entre clases. Dispone de los
atributos:
§ cascade: tipo de operación de cascada a realizar. Los valores posibles que admite
el enumerador CascadeType son REMOVE, REFRESH, PERSIST, MERGE, DETACH y
ALL.
§ fetch: forma en que se consultarán las entidades asociadas. El enumerador
FetchType admite los valores EAGER y LAZY.
o @OneToMany: para establecer una relación de uno a muchos entre clases. Dispone de
los atributos:
§ mappedBy: contiene el nombre de la propiedad Java de la clase hija (en el extremo
muchos) que enlaza con la clase padre (en el extremo uno).
§ cascade: tipo de operación de cascada a realizar.
o @ManyToOne: para establecer una relación de muchos a uno entre clases. Esta
anotación es acompañada de la anotación @JoinColumn en la que se indica mediante
el atributo name el nombre de la columna que en la tabla hija contiene la clave ajena
de la tabla padre.
Ejemplo: Clases con anotaciones relación uno a muchos. Una asignatura es impartida por un
profesor y un profesor puede impartir una o varias asignaturas. Se establece una relación
uno a muchos entre profesores y asignaturas.
A nivel de base de datos tenemos 2 tablas:
CREATE TABLE asignaturas (
idasignatura int(11) NOT NULL AUTO_INCREMENT,
nombre varchar(100) NOT NULL,
idprofesor varchar(100),
PRIMARY KEY (idasignatura),
FOREIGN KEY idprofesor REFERENCES profesores;
import [Link];
import [Link].*;
@Entity
@Table(name="profesores")
public class Profesor implements Serializable {
@Id
@GeneratedValue(strategy=[Link])
@Column(name="idprofesor")
private int idProfesor;
@Column(name="nombre")
private String nombre;
@Column(name="mail")
private String mail;
@OneToMany(mappedBy="profesor" cascade="[Link])
private List<Asignatura> listaAsignaturas;
public Profesor() {}
public Profesor(String nombre, String mail) {
[Link] = nombre;
[Link] = mail;}
public int getIdProfesor() { return idProfesor; }
public void setIdProfesor(int idProfesor) {[Link] = idProfesor;}
public String getNombre() {return nombre;}
public void setNombre(String nombre) {[Link] = nombre;}
public String getMail() {return mail;}
public void setMail(String mail) {[Link] = mail;}
public List<Asignatura> getListaAsignaturas() {return listaAsignaturas;}
public void setListaAsignaturas(List<Asignatura> a) {listaAsignaturas = a;}
}
import [Link].*;
@Entity
@Table(name="asignaturas")
public class Asignatura implements Serializable {
@Id
@GeneratedValue(strategy=[Link])
@Column(name="idasignatura")
@Column(name="nombre")
private String nombre;
@ManyToOne
@JoinColumn(name="idprofesor")
private Profesor profesor;
public Asignatura() {}
public Asignatura(String nombre, Profesor p) {
[Link] = nombre;
profesor = p;}
public int getIdAsignatura() {return idAsignatura;}
public void setIdAsignatura(int idAsignatura) {
[Link] = idAsignatura;}
public String getNombre() {return nombre;}
public void setNombre(String nombre) {[Link] = nombre;}
public Profesor getProfesor() {return profesor;}
public void setProfesor(Profesor p) {profesor = p;}
}
Ejemplo: Clases con anotaciones relación muchos a muchos. Un profesor da clases en uno o
varios cursos y en un curso puede dar clases uno o varios profesores. Se establece una
relación muchos a muchos entre profesores y cursos.
@Entity
@Table(name="profesores")
public class Profesor implements Serializable {
@Id
@GeneratedValue(strategy=[Link])
@Column(name="idprofesor")
private int idProfesor;
@Column(name="nombre")
private String nombre;
@Column(name="mail")
private String mail;
@ManyToMany(cascade="[Link])
@JoinTable(name="profesorescursos",
JoinColumns={@JoinColumn(name="idprofesor")},
inverseJoinColumns={@JoinColumn(name="idcurso")})
private Set<Curso> cursos;
public Profesor() {}
public Profesor(String nombre, String mail) {
[Link] = nombre;
[Link] = mail;}
public int getIdProfesor() { return idProfesor; }
public void setIdProfesor(int idProfesor) {[Link] = idProfesor;}
public String getNombre() {return nombre;}
public void setNombre(String nombre) {[Link] = nombre;}
public String getMail() {return mail;}
public void setMail(String mail) {[Link] = mail;}
public Set<Curso> getCursos() {return cursos;}
public void setCursos(Set<Curso> c) {cursos = c;}
}
import [Link];
import [Link].*;
@Entity
@Table(name="cursos")
public class Curso implements Serializable {
@Id
@GeneratedValue(strategy=[Link])
@Column(name="idcurso")
private int idCurso;
@Column(name="nombre")
private String nombre;
@ManyToMany(mappedBy="cursos")
private Set<Profesor> profesores;
public Curso() {}
public int getIdCurso() { return idCurso; }
public void setIdCurso(int idCurso) {[Link] = idCurso;}
public String getNombre() {return nombre;}
public void setNombre(String nombre) {[Link] = nombre;}
public Set<Profesor> getProfesores() {return profesores;}
public void setProfesores(Set<Profesor> p) {profesores = p;}
}
Para completar el uso JPA nos queda ver cómo persistir de forma efectiva los objetos en la
base de datos. Para ello utilizamos un EntityManager:
EntityManagerFactory emfactory = [Link]("JPA");
EntityManager entitymanager = [Link]( );
[Link]( ).begin( );
//CREACIÓN DEL OBJETO A PERSISTIR
[Link](OBJETO);
[Link]().commit();
[Link]();
[Link]();
De otra parte, JPA también nos permite seguir el sentido inverso, creando objetos a partir de
las tablas de una base de datos, y también de forma transparente.
De la misma forma que sucede en JDBC, para una clase de entidad tendremos que diseñar
una clase de servicio para que persista los objetos de la clase entidad en la base de datos.
Esta clase de servicio implementará el patrón DAO (Data Acces Object). De esta manera
independizamos nuestra aplicación del framework concreto de persistencia que utilicemos.
Es decir, si cambiamos de framework bastará adaptar las clases de servicio DAO sin que
afecte al resto de nuestro sistema.
Ejemplo: clase de servicio UserDAO en Hibernate para persistir objetos de la clase User. El
mapeo se hace con anotaciones en la clase User o mediante fichero XML. Aprovechamos el
ejemplo para ver los métodos de consulta y persistencia y el uso del objeto Session.
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
try {
[Link]();
String query = "FROM User WHERE user='"
+[Link]()+"' AND password='"
+[Link]()+"'";
} catch (HibernateException e) {
if ([Link]()!=null) {
[Link]().rollback(); }
}
finally { [Link](); }
return acceso;
}
} catch (HibernateException e) {
if ([Link]()!=null) {
[Link]().rollback();}
}
finally { [Link](); }
return usuario;
}
try {
[Link]();
String query = "FROM User WHERE user='"+username+"'";
List lista = [Link](query).list();
if([Link]()>0) acceso=true;
[Link]().commit();
} catch (HibernateException e) {
if ([Link]()!=null) {
[Link]().rollback();}
}
finally { [Link](); }
return acceso;
}
try {
[Link]();
String query = "FROM User";
lista = [Link](query).list();
[Link]().commit();
} catch (HibernateException e) {
if ([Link]()!=null) {
[Link]().rollback();}
}
finally { [Link](); }
return lista;
}
try {
[Link]();
[Link](user);
[Link]().commit();
} catch (HibernateException e) {
if ([Link]()!=null) {
[Link]().rollback();
}
}
finally { [Link](); } }
try {
[Link]();
[Link](user);
[Link]().commit();
} catch (HibernateException e) {
if ([Link]()!=null) {
[Link]().rollback();}
}
finally { [Link](); }
}
try {
[Link]();
[Link](user);
[Link]().commit();
} catch (HibernateException e) {
if ([Link]()!=null) {
[Link]().rollback();}
}
finally { [Link](); }
}
}
Por último, recordamos que JPA es una especificación de persistencia por lo que
necesitamos de un framework de persistencia que implemente dicha especificación. Entre
los frameworks de persistencia destacamos:
- Hibernate: ORM mediante archivos XML o anotaciones. Actualmente disponible en su
versión 6, distribuido bajo licencia LGPL. Dispone de un lenguaje propio de consultas
denominado HQL (Hibernate Query Language). Es el framework de persistencia por
excelencia, el más utilizado. Tiene una variante, Hibernate OGM, que ofrece persistencia
sobre bases de datos NoSQL.
- EclipseLink (de Eclipse Foundation).
- Apache OpenJPA.
- Apache Cayenne.
- MyBatis (antes iBATIS).
- jOOQ.
- Ebean (también para Kotlin).
- Spring Data.
JNDI
Para trabajar con directorios de nombres, se requiere el uso de clases e interfaces para
acceder a dichos servicios de nombres, necesitándose el paquete:
import [Link].*;
6. Seguridad
Toda organización que tenga recursos confidenciales a los que puedan acceder muchos
usuarios o recursos que atraviesen redes abiertas sin protección, como Internet, necesita
protección.
La capa de negocio y web están formadas por componentes que se implementan en varios
contenedores. Estos componentes se combinan para crear una aplicación empresarial de
multicapa. La seguridad de los componentes es proporcionada por sus contenedores. Un
contenedor proporciona 2 tipos de seguridad: declarativa y programática.
Bouncy Castle es un proyecto de software libre que desarrolla una serie de APIs
criptográficas libres y, entre otros, ofrece un proveedor (provider) para el JCA de Java.
También, disponible para C#.
- Java Generic Security Services (Java GSS-API) es una API basada en token utilizada para
intercambiar mensajes de forma segura entre aplicaciones que se comunican. El GSS-API
ofrece acceso uniforme a servicios de seguridad además de una variedad de mecanismos
de seguridad subyacentes, incluido Kerberos.
- Java Secure Sockets Extension (JSSE) proporciona un marco y una implementación para
una versión Java de los protocolos TLS y DTLS (Datagram Transport Layer Security) e
incluye funcionalidad para el cifrado de datos, la autenticación del servidor, la integridad
del mensaje y la autenticación opcional del cliente para habilitar comunicaciones seguras
de Internet.
- Simple Authentication and Security Layer (SASL) es un estándar de Internet (RFC 2222)
que especifica un protocolo para la autenticación y el establecimiento opcional de una
capa de seguridad entre las aplicaciones cliente y servidor. SASL define cómo se
intercambiarán los datos de autenticación, pero no especifica el contenido de esos datos.
SASL es un marco en el que pueden encajar mecanismos de autenticación específicos
que especifican el contenido y la semántica de los datos de autenticación.
activa desde el momento en que los datos salen del cliente hasta que llega a su destino, o
viceversa, incluso a través de intermediarios. El problema es que los datos no están
protegidos una vez que llegan al destino. Una solución es cifrar el mensaje antes de enviarlo.
Las tecnologías que nos ayudan a implementar la seguridad en una aplicación Jakarta EE son:
- Jakarta Security.
- Jakarta Authentication.
- Jakarta Authorization.
Una aplicación Jakarta EE está compuesta, en principio, por componentes EJB, componentes
web (servlets y/o JSP), clases con utilidades de servidor, componentes de cliente y ficheros
HTML. Todos estos componentes se deben empaquetar junto con unos ficheros de
configuración conocidos como descriptores de despliegue o deployment descriptors.
- Jersey: framework de Eclipse con soporte para servicios web RESTful en Java.
- Google Web Toolkit (GWT): framework de código abierto desarrollado por Google para
crear y optimizar aplicaciones web de alto rendimiento basadas en navegador (JS, AJAX a
través de XMLHttpRequest) sin que el desarrollador tenga que ser un experto.
- Grails: framework escrito en Groovy orientada a crear aplicaciones web de forma sencilla
que adopta el principio DRY.
- JHipster: framework de código abierto que se utiliza para desarrollar aplicaciones web y
microservicios.
- Spring Boot: subproyecto de Spring MVC que permite el desarrollo de aplicaciones web
autocontentidas que llevan embebido el contenedor de servlets y también de
aplicaciones basadas en microservicios.
Librerías y herramientas
- Ant: herramienta de Apache para compilación y construcción.
- DBUnit: extensión de JUnit para realizar pruebas del funcionamiento de las operaciones
de base de datos.
- SLF4J (Simple Logging Facade for Java): ofrece una fachada para varios frameworks de
loggin.
- Spring Data: encargado del acceso a los datos. Uso asociado al framework Spring.
- Thymeleaf: motor de plantillas Java del lado del servidor que permite la
creación de páginas web con representación. Tiene un uso frecuente en
combinación con el framework Spring.
2. PLATAFORMA .NET
.NET es una plataforma de desarrollo de uso general, multiplataforma (Android, Apple, Linux
y Windows) y de código abierto (licencia MIT) para crear tipos diferentes de aplicaciones.
.NET Standard es una especificación formal de las API (biblioteca) de .NET que son comunes
en todas las implementaciones de .NET (.NET Framework, .NET Core, Mono, Xamarin, UWP y
Unity).
.NET Standard permite que las bibliotecas se compilen con el conjunto acordado de API
comunes, lo que garantiza que se puedan usar en cualquier aplicación .NET: móvil,
escritorio, IoT, web…
La última versión de .NET Standard es la 2.1 y Microsoft no publicará ninguna versión más.
.NET y .NET 5 y versiones posteriores se convierten en la mejor forma de compartir código
adoptando un enfoque diferente para establecer la uniformidad que elimine la necesidad de
.NET Standard. El motivo de abandonar .NET Standard en favor de .NET es no separar la
especificación de la implementación de las API y, también, la ampliación rápida de nuevas
funcionalidades a la API evitando procesos previos de revisión de propuestas.
- Permite a los desarrolladores generar bibliotecas portables que se pueden usar en las
implementaciones de .NET con este mismo conjunto de API.
- .NET 9 (antes .NET Core): de código abierto, multiOS (Windows, macOS y Linux). El
runtime utilizado es coreCLR.
Microsoft en los últimos años ha hecho un esfuerzo para otorgar más protagonismo a su
comunidad de desarrollo y al software libre. Fruto de ello es la creación de .NET Core
(actual .NET 9), implementación de .NET Standard, pero orientada desde el principio a la
portabilidad entre plataformas (Windows, Linux y MacOS, y también con Docker), sin
dependencias específicas de Windows.
Por último, destacamos UNITY, una plataforma de desarrollo 3D en tiempo real para
compilar aplicaciones 2D y 3D, como juegos y simulaciones, con .NET y el lenguaje de
programación C#.
Cada implementación tiene su propio runtime: CLR es el clásico para .NET Framework,
CoreCLR es el de .NET 9, Mono runtime el de Mono y .Net Native para UWP.
1. .NET Framework
.NET Framework es el núcleo de la plataforma y ofrece la infraestructura necesaria para
desarrollar y ejecutar aplicaciones .NET. Consta de 2 componentes principales:
- Common Language Runtime (CLR): es el motor de ejecución que controla las
aplicaciones en ejecución.
- Biblioteca de clases de .NET Framework: proporciona una biblioteca de clases
reutilizable al que pueden llamar los desarrolladores desde sus propias aplicaciones.
Los servicios que ofrece .NET Framework a las aplicaciones en ejecución son los siguientes:
- Administración de la memoria. En muchos lenguajes de programación, los
programadores son responsables de asignar y liberar memoria y de administrar la vida
útil de los objetos. En las aplicaciones de .NET Framework, CLR proporciona estos
servicios en nombre de la aplicación.
CLR
Common Language Runtime es el entorno donde se ejecutan todas las aplicaciones .NET.
La herramienta [Link] notifica todas las versiones instaladas de CLR en el equipo. Esta
herramienta se instala automáticamente con Visual Studio.
AOT (Ahead Of Time) es un compilador similar a JIT, que convierte IL en código de máquina.
A diferencia de la compilación JIT, la compilación AOT ocurre antes de que la aplicación se
ejecute y, normalmente, se realiza en un equipo diferente.
Servicios de CLR:
- Compilador de CIL a nativo.
CLR admite un modelo de seguridad denominado seguridad de acceso del código o CAS
(Code Access Security) para el código administrado. En este modelo se conceden permisos a
los ensamblados basados en la identidad del código.
Ensamblados
Los ensamblados son las unidades de creación de las aplicaciones .NET Framework
(concepto específico de este framework). Son la unidad fundamental de implementación,
control de versiones, reutilización, ámbitos de activación y permisos de seguridad.
Elementos de un ensamblado:
- Manifiesto del ensamblado, que contiene los metadatos del
ensamblado (es el único elemento obligatorio):
o Nombre ensamblado.
o Referencia cultural: información sobre la referencia cultural o
idioma que admite el ensamblado.
o Nº versión.
o Lista de archivos del ensamblado: código hash de cada
archivo que contiene el ensamblado y nombre de archivo.
o Información sobre otros ensamblados a los que hace referencia.
- Metadatos de tipos.
- Código CIL, el sign code permite firmar el ejecutable para garantizar la integridad.
- Conjunto de recursos.
Como en cualquier biblioteca de clases orientada a objetos, las clases de .NET Framework
permiten realizar diversas tareas de programación comunes, como son la administración de
cadenas, la recolección de datos, la conectividad de bases de datos y el acceso a archivos.
Además de estas tareas habituales, la biblioteca de clases incluye tipos adecuados para
diversos escenarios de desarrollo especializados, como:
- [Link] para aplicaciones web.
- [Link] para el acceso a los datos.
- Windows Communication Foundation (WCF) para las aplicaciones orientadas a servicios.
- Windows Presentation Foundation (WPF) para las aplicaciones de escritorio de
Windows. Windows Forms como alternativa.
- Windows Workflow Foundation (WF): para flujos de trabajo.
2. Arquitectura
A continuación, se muestra la arquitectura detallada de una aplicación en .NET:
Aplicación cliente
Podemos crear aplicaciones basadas en Windows mediante:
- Windows Presentation Foundation (WPF): permite crear aplicaciones de cliente de
escritorio para Windows. El núcleo de WPF es un motor de representación basado en
vectores e independiente de la resolución que está diseñado para sacar partido al
moderno hardware gráfico. WPF amplía el núcleo con un conjunto completo de
características de desarrollo de aplicaciones que incluyen XAML (Extensible Application
Markup Language), controles, enlace de datos, diseño, gráficos en 2D y 3D, animación,
estilos, plantillas, documentos, elementos multimedia, texto y tipografía. WPF es parte
de. NET, así que permite compilar aplicaciones que incorporan otros elementos de la API
de .NET.
Ejemplo:
<Window
xmlns="[Link]
Title="Window with Button"
Width="250" Height="100">
Ejemplo:
<Window xmlns="[Link]
xmlns:x="[Link]
x:Class="[Link]"
Title="Layout with the DockPanel" Height="143" Width="319">
<DockPanel> <!--DockPanel to layout four text boxes-->
<TextBox [Link]="Top">Dock = "Top"</TextBox>
<TextBox [Link]="Bottom">Dock = "Bottom"</TextBox>
<TextBox [Link]="Left">Dock = "Left"</TextBox>
<TextBox Background="White">
This TextBox "fills" the remaining space.
</TextBox>
</DockPanel>
</Window>
Sin embargo, con la llegada de Core, se definió un framework llamado “[Link] Core”,
extremadamente similar a [Link] clásico, pero multiplataforma y de código abierto con la
finalidad de compilar aplicaciones tanto en local como destinadas a la nube, y que formó
parte de .NET Core. De esta manera se pueden desarrollar aplicaciones de [Link] que sean
portable entre los diferentes entornos que soporta .NET Core. Para el desarrollo de nuevas
aplicaciones se debe usar [Link] Core.
Modelos/marcos de programación
El hecho de elegir uno de los modelos de programación al comenzar un proyecto de [Link]
no excluye necesariamente a los otros, sino que es posible tener aplicaciones “híbridas” y en
muchos casos tendrá todo el sentido desarrollar ciertas partes de la aplicación con un
modelo de programación y otras partes con otro modelo distinto.
- [Link] Web Forms fue el primero de los modelos de programación en existir
proporcionando un gran nivel de abstracción. Está basado en eventos y controles que
favorecen la productividad mediante la programación declarativa, reduciendo la
cantidad de código necesaria para implementar una determinada funcionalidad. El
código se ejecuta en el servidor y genera dinámicamente la salida de la página web
(HTML) al navegador o al dispositivo cliente.
de desarrolladores web sin experiencia previa con [Link], cuya iniciación en [Link]
Web Forms o MVC les suponía una inversión inicial de tiempo demasiado grande. Web
Pages proporciona un modelo de programación más simple y rápido de aprender, sin
renunciar a toda la funcionalidad y flexibilidad de [Link]. Cada página de Razor se
compone de un par de archivos:
o .cshtml: contiene el marcado HTML con código C# que usa la sintaxis Razor.
o .[Link]: contiene código C# que controla los eventos de página.
- Las llaves {} encierran un bloque de código Razor si el código tiene más de una línea. Las
llaves indican a [Link] dónde se inicia y finaliza el código para ese bloque.
- Los caracteres // marcan un comentario, es decir, una parte del código que no se
ejecutará.
- Puede almacenar valores en variables, que declare con la palabra reservada var. Cuando
se crea una variable, se le asigna un nombre, que puede incluir letras, números y
subrayados. Los nombres de variable no pueden comenzar con un número y no pueden
usar el nombre de una palabra reservada del lenguaje.
- Las cadenas de caracteres (como "[Link]" y "páginas web") se delimitan entre comillas
dobles.
- Las estructuras condicionales permitidas son @if, else if, else y @switch. Notar que
else if y else no necesitan @.
- Las estructuras repetitivas soportadas son @for, @foreach, @while, y @do while.
Ejemplo:
@foreach (var person in people){
<p>Name: @[Link]</p>
<p>Age: @[Link]</p>
}
Ejemplo:
@{
// Working with numbers
var a = 4;
var b = 5;
var theSum = a + b;
<!DOCTYPE html>
<html lang="en">
<head>
<title>Testing Razor Syntax</title><meta charset="utf-8" />
</head>
<body>
<h1>Testing Razor Syntax</h1>
<form method="post">
<div>
<p>The value of <em>a</em> is @a. The value of <em>b</em> is @b.</p>
<p>The sum of <em>a</em> and <em>b</em> is
<strong>@theSum</strong>.
</p>
<p>The product of <em>a</em> and <em>b</em> is
<strong>@(a*b)</strong>.
</p>
</div>
<div>
<p>The technology is @technology, and the product is @product.</p>
<p>Together they are
<span class="bright">@(technology + " " + product)</span>
</p>
</div>
<div>
<p>The current date and time is: @rightNow</p>
<p>The URL of the current page is<br/><br/>
<code>@[Link]</code>
</p>
</div>
</form>
</body>
</html>
Las directivas se representan con la palabra reservada en cuestión antecedido por el símbolo
@. Vamos a nombrar las directivas más destacables:
Respecto al manejo de sesiones, podemos configurar el estado de una sesión. Para ello, se
utiliza el paquete [Link]. Se puede configurar la creación de
cookies o el tiempo de inactividad de una sesión antes de ser cerrada.
El objeto Request es una colección (lista) de valores. Para obtener un valor individual de la
colección, especificamos su nombre:
var someValue = Request["name"];
Ejemplo:
@{
var db = [Link]("WebPagesMovies");
var selectCommand = "SELECT * FROM Movies";
var searchTerm = "";
if(![Link]["searchGenre"].IsEmpty() ) {
selectCommand = "SELECT * FROM Movies WHERE Genre = @0";
searchTerm = [Link]["searchGenre"]; }
if(![Link]["searchTitle"].IsEmpty() ) {
selectCommand = "SELECT * FROM Movies WHERE Title LIKE @0";
searchTerm = "%" + Request["searchTitle"] + "%";}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" /><title>Movies</title>
<style type="text/css">
.grid { margin: 4px; border-collapse: collapse; width: 600px; }
.grid th, .grid td { border: 1px solid #C0C0C0; padding: 5px; }
.head { background-color: #E8E8E8; font-weight: bold; color: #FFF;
.alt { background-color: #E8E8E8; color: #000; }
</style>
</head>
<body>
<h1>Movies</h1>
<form method="get">
<div>
<label for="searchGenre">Genre to look for:</label>
<input type="text" name="searchGenre"
value="@[Link]["searchGenre"]" />
<input type="Submit" value="Search Genre" /><br/>
(Leave blank to list all movies.)<br/>
</div>
<div>
<label for="SearchTitle">Movie title contains
the following:</label>
<input type="text" name="searchTitle"
value="@[Link]["searchTitle"]" />
<input type="Submit" value="Search Title" /><br/>
</div>
</form>
<div>
@[Link](
tableStyle: "grid",
headerStyle: "head",
alternatingRowStyle: "alt",
columns: [Link](
[Link]("Title"),
[Link]("Genre"),
[Link]("Year")
)
)
</div>
</body>
</html>
Capa de servicios
En esta capa tenemos los siguientes componentes:
- Interfaz de servicios: es como un servicio web, expone los servicios para que
otro servicio web lo use. Son elementos tipo fachada que controlan los
servicios de asignación y transformación para permitir la comunicación con
un servicio. Implementados mediante WCF (Windows Communication
Foundation), los servicios web pueden ser SOAP o REST.
Las siglas “ABC” son claves para WCF porque coinciden con aspectos básicos
de cómo están compuestos los End-Points de un Servicio WCF. Los End-
Points son básicamente los extremos en las comunicaciones basadas en
WCF y por lo tanto también los puntos de entrada a los servicios. Un End-
Point es internamente bastante complejo pues ofrece diferentes posibilidades de
comunicación, direccionamiento, etc. Un EndPoint está compuesto por “ABC”, es decir:
o “A” para “Address” (Dirección): ¿Dónde está el servicio situado? La
dirección se proporciona para los protocolos HTTP, TCP, MSMQ.
o “B” para “Binding” (Enlace): ¿Cómo hablo con el servicio? El enlace
especifica cómo acceder al servicio, definiendo el protocolo de
transporte empleado, la codificación de los mensajes y los
protocolos WS-Security utilizados.
o “C” para “Contract” (Contrato): ¿Qué me ofrece el servicio? Es la interfaz al exterior
del servicio, especificándose los métodos, tipos y operaciones a exponer.
Conviene resaltar gRPC, un marco alternativo a WCF basado en HTTP/2 que ofrece sobre
WCF un mayor rendimiento y escalabilidad.
- Intercambio de mensajes.
Capa empresarial
En esta capa tenemos los siguientes componentes:
- Entidades de Negocio: representan los datos que se pasan entre los componentes. Las
entidades empresariales se pueden implementar en .NET mediante [Link] Entity
Framework. Permite utilizar clases POCO2 (Plain Old ClrObjects), que son clases del
modelo de dominio que ignoran la persistencia.
Servidores empresariales:
Microsoft BizTalk Server permite conectar software diverso. Es una arquitectura
de publicación y suscripción que usa adaptadores para recibir y enviar mensajes,
implementa procesos empresariales a través de la orquestación e incluye la
administración y el seguimiento de estas distintas partes. BizTalk Server incluye
también la administración de socios comerciales para mensajería de negocio a
negocio, alta disponibilidad para maximizar el tiempo de actividad, una
plataforma de desarrollo para crear sus propios componentes, una consola de
administración para administrar los artefactos y la supervisión de la actividad
empresarial para administrar agregaciones, alertas y perfiles.
2
Es una estructura de datos de .NET que solo contiene propiedades o campos públicos. Un POCO no debe
contener ningún otro miembro, como métodos, eventos o delegados. Un POCO no hereda de otra clase ni
implementa una interfaz. Es habitual que los POCO se usen con la serialización.
3. Persistencia
Los dos componentes principales de [Link] para tener acceso a los datos y manipularlos
son:
- Los proveedores de datos .NET Framework.
- El DataSet.
Podemos utilizar los siguientes proveedores de datos .NET Framework según el origen de
datos:
- SQL Server: usa su propio protocolo para comunicarse con SQL Server. Es
ligero y funciona bien porque está optimizado para tener acceso a una SQL
Server directamente sin agregar una capa de conectividad de base de datos
(ODBC) OLE DB o abierta.
- Oracle: permite el acceso a los datos de los orígenes de datos de Oracle a través del
software de conectividad de cliente de Oracle.
- EntityClient: proveedor de datos especial que se usa para obtener acceso a datos
basándose en un Entity Data Model (EDM). A diferencia de otros proveedores de datos
.NET Framework, no interactúa directamente con ningún origen de datos. En su lugar,
usa Entity SQL para comunicarse con el proveedor de datos subyacente.
o Oracle: OracleConnection.
o EntityClient: EntityConnection.
Ejemplo:
OdbcConnection connection = new OdbcConnection(connectionString);
- El objeto Command permite tener acceso a comandos de base de datos para devolver
datos, modificar datos, ejecutar procedimientos almacenados y enviar o recuperar
información sobre parámetros. Lo utilizamos una vez la conexión esté abierta.
- DataReader lee un flujo de datos de solo avance y solo lectura hacia delante de alto
rendimiento desde el origen de datos. Los resultados se devuelven cuando se ejecuta la
consulta y se almacenan en el búfer de red en el cliente hasta que se solicitan mediante
el método Read del DataReader. El uso de DataReader puede aumentar el rendimiento de
la aplicación al recuperar los datos tan pronto como estén disponibles y, de forma
predeterminada, almacenar solo una fila a la vez en la memoria, lo que reduce la
sobrecarga del sistema.
Ejemplo:
using System;
using [Link];
using [Link];
class Program {
static void Main() {
string connectionString =
"Data Source=(local);Initial Catalog=Northwind;"
+ "Integrated Security=true";
[Link]();
SqlDataReader reader = [Link]();
while ([Link]()){
[Link]("\t{0}\t{1}\t{2}",
reader[0], reader[1], reader[2]);}
[Link]();
}
catch (Exception ex) {[Link]([Link]);}
[Link]();
}
}
El método Fill de DataAdapter se usa para rellenar un objeto DataSet con los resultados
del elemento SelectCommand de DataAdapter. Fill toma como argumentos un elemento
DataSet que se debe rellenar y un objeto DataTable.
Ejemplo:
// connection es un objeto SqlConnection
string queryString = "SELECT CustomerID, CompanyName FROM [Link]";
SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);
Ejemplo:
private static DataSet SelectRows(DataSet dataset,
string connectionString,string queryString) {
using (SqlConnection connection = new SqlConnection(connectionString)) {
SqlDataAdapter adapter = new SqlDataAdapter();
[Link] = new SqlCommand(queryString, connection);
[Link](dataset);
return dataset; }
}
(2) DataSet
DataSet de [Link] representa una caché de datos en memoria y está expresamente
diseñado para el acceso a datos independientemente del origen de datos. Como resultado,
se puede utilizar con múltiples y distintos orígenes de datos, con datos XML o para
administrar datos locales de la aplicación.
DataSet contiene una colección de uno o más objetos DataTable formados por filas y
columnas de datos, así como información sobre claves principales, claves externas,
restricciones y de relación relacionada con los datos incluidos en los objetos DataTable.
Ejemplo:
using System;
using [Link];
using [Link];
namespace [Link] {
class NorthwindDataSet {
static void Main() {
string connectionString = GetConnectionString();
ConnectToData(connectionString);
}
// 2. Query creation.
// numQuery is an Ienumerable<int>
var numQuery =
from num in numbers
where (num % 2) == 0
select num;
// 3. Query execution.
Foreach (int num in numQuery) {
[Link](“{0,1} “, num);
}
Parallel LINQ (PLINQ) es una variante de LINQ que permite la ejecución paralela de
consultas.
- Entity Framework Core (EF Core) para .NET Core: es un ORM de código abierto y
multiplataforma para .NET, más moderno, ligero y extensible que EF6. Admite consultas
LINQ, seguimiento de cambios, actualizaciones y migraciones de esquemas. EF Core
funciona con, entre otras, SQL Server o SQL Azure, SQLite, Azure Cosmos DB, MySQL y
PostgreSQL.
Ejemplo:
MODELO
using [Link];
using System;
using [Link];
public BloggingContext() {
var folder = [Link];
var path = [Link](folder);
DbPath = [Link](path, "[Link]");
}
PROGRAMA
using System;
using [Link];
// Create
[Link]("Inserting a new blog");
[Link](new Blog { Url = "[Link] });
[Link]();
// Read
[Link]("Querying for a blog");
var blog = [Link]
.OrderBy(b => [Link])
.First();
// Update
[Link]("Updating the blog and adding a post");
[Link] = "[Link]
[Link](
new Post { Title = "Hello World", Content = "I wrote an app using EF Core!"
});
[Link]();
// Delete
[Link]("Delete the blog");
[Link](blog);
[Link]();
4. Seguridad
La seguridad en .NET incluye las siguientes áreas:
- Seguridad de tipos: los programas de tipos seguros hacen referencia únicamente a la
memoria que ha sido asignada para su uso, y acceden a objetos únicamente a través de
sus interfaces expuestas. Desde el punto de vista de seguridad, al hacer referencia
únicamente a la memoria asignada se permite que múltiples objetos compartan de
manera segura un espacio de dirección único. Al acceder a los objetos únicamente a
través de sus interfaces expuestas garantiza que las revisiones de seguridad relacionadas
con interfaces específicas no sean evitadas. CLR garantiza la seguridad de tipos al
requerir la verificación antes de permitir ejecutarse.
- Evidencia: existen únicamente dos formas para que un código sea ejecutable. La
primera, a través del cargador de clases, la segunda a través de los servicios de
interoperabilidad. Estos dos servicios son proporcionados por CLR y son parte del
perímetro de seguridad. Por ejemplo, el cargador de clases mantiene información acerca
de la fuente para cada implementación que carga. Por lo tanto, el cargador de clases
puede proporcionar de manera confiable alguna evidencia sobre la que basar la
identidad del código. La evidencia puede incluir información como zona de Internet y
sitio del que el código fue originado, su nombre compartido, y la identidad del
publicador. Utilizando esta información, la política de seguridad puede controlar los
privilegios proveídos a una aplicación especifica o conjunto de aplicaciones relacionadas.
El objeto Principal representa el contexto de seguridad bajo el cual se ejecuta código. Las
aplicaciones que implementan seguridad basada en roles conceden derechos tomando
como base el rol asociado a un objeto Principal. El correspondiente principal encapsula la
identidad, junto con la información del rol. Esto puede o no relacionarse con una noción
del sistema operativo como los grupos.
confidencialidad e integridad son críticos, de manera que .NET proporciona soporte para
estos mecanismos a fin de que sea compatible con los protocolos de red existentes, y los
integra firmemente en la infraestructura de ejecuciones remotas. Esto es más simple
para incorporar estas características en sus aplicaciones. Los mecanismos de
autenticación son adecuados para la identificación de usuarios, así como aplicaciones o
entidades de negocios. Una infraestructura de identidad basada en claves se proporciona
para administrar tales entidades e integrarlas con los protocolos de autenticación
basados en claves. Los servicios de confidencialidad e integridad aprovechan las técnicas
criptográficas. Es posible utilizar mecanismos de punto a punto tales como TLS/SSL e
IPSec. Tecnologías de encriptación de la capa de la aplicación, integridad y de firma
digital en el nivel de mensajería también son soportadas por el entorno .NET.
5. Administrador de paquetes
NuGet es un administrador de paquetes para el ecosistema de. NET y es la principal forma
que tienen los desarrolladores para detectar y adquirir bibliotecas de código abierto de .NET.
[Link], un servicio gratuito proporcionado por Microsoft para hospedar paquetes
NuGet, es el host principal para los paquetes NuGet públicos, pero también es posible
publicar en los servicios de NuGet personalizados, como MyGet y Azure Artifacts.
Un paquete NuGet (*.nupkg) es un archivo ZIP que contiene los ensamblados de .NET y los
metadatos asociados.
- dotnet list package: lista las referencias y versiones de los paquetes del proyecto.
- dotnet nuget push: publica un paquete en un servidor NuGet ([Link], Azure Artifacts
o servidores NuGet de terceros).
.NET MAUI proporciona un único marco para compilar las IU para aplicaciones móviles y
de escritorio.
En una aplicación MAUI de .NET, se escribe código que interactúa principalmente con los
controles .NET MAUI y la capa de API (1). A continuación, esta capa consume
directamente las API de plataforma nativas (3). Además, el código de la aplicación puede
ejecutar directamente las API de plataforma (2), si es necesario.
Librerías y herramientas
- AutoMapper: mapeador objeto-objeto basado en convenciones.
- NSwag: librería de código abierto que permite diseñar, documentar y consumir servicios
REST.
- PostSharp Loggin: extensión para registro que se integra con librerías de log.