commit d1a4e8c6e26fba810a839fd9a96cb91e767d6406 Author: Isidoro Nevares Martín Date: Mon Nov 10 10:08:51 2025 +0100 primer commit diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..8e75d71 --- /dev/null +++ b/.classpath @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f1d3ca --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target/ +*.class \ No newline at end of file diff --git a/.project b/.project new file mode 100644 index 0000000..7bdfc5a --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + EjemploAWS + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..2f5cc74 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..21efd3d --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# Estructura del bucket S3 : s3-objetos-proyecto + +| Identificador Proyecto | Número Hito | Nombre documento | +|-------------------------|-------------|---------------------------| +| 1 | 1 | Kingdom Town for Gods.pdf + +**Clave del documento S3**: "/1/1/Kingdom Town for Gods.pdf" + + + +# Estructura de la tabla de DynamoDb: ddb-hitos-proyecto + +| Campo | Tipo DynamoDB | Ejemplo de valor | +|------------------|---------------------|--------------------------------------------------------------------------| +| id_proyecto | Number | 1 | +| numero_hito | Number | 2 | +| fecha_hito | String (S) | "2025-06-01T18:30:22Z" | +| fecha_envio | String (S) | "2025-06-01T18:30:22Z" | +| alumno_envio | Number | 5 | +| clave_documento | String (S) | "/1/1/Kingdom Town for Gods.pdf" | +| resumen_entrega | String (S) | "En este hito se ha añadido el índice..." | +| estado | String (S) | "Enviado" | diff --git a/ficheros/Kingdom Town for Gods.pdf b/ficheros/Kingdom Town for Gods.pdf new file mode 100644 index 0000000..0b0b100 Binary files /dev/null and b/ficheros/Kingdom Town for Gods.pdf differ diff --git a/ficheros/hitos-proyecto.csv b/ficheros/hitos-proyecto.csv new file mode 100644 index 0000000..ea5c8f3 --- /dev/null +++ b/ficheros/hitos-proyecto.csv @@ -0,0 +1,9 @@ +id_proyecto|numero_hito|fecha_hito|fecha_envio|alumno_envio|url_documento|resumen_entrega|estado +1|1|"2025-03-10"||||| +1|2|"2025-04-10"||||| +1|3|"2025-05-10"||||| +1|4|"2025-06-15"||||| +2|1|"2025-03-15"||||| +2|2|"2025-04-15"||||| +2|3|"2025-05-20"||||| +2|4|"2025-06-20"||||| diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..0414e5f --- /dev/null +++ b/pom.xml @@ -0,0 +1,68 @@ + + 4.0.0 + EjemploIntegradorAWS + EjemploIntegradorAWS + 0.0.1-SNAPSHOT + + + + + com.opencsv + opencsv + 5.11 + + + + org.hibernate.orm + hibernate-core + 7.0.0.Final + + + + + org.mongodb + mongodb-driver-sync + 5.5.0 + + + + + software.amazon.awssdk + aws-core + 2.20.14 + + + + + software.amazon.awssdk + s3 + 2.20.14 + + + + + software.amazon.awssdk + dynamodb + 2.20.14 + + + + + software.amazon.awssdk + auth + 2.20.14 + + + + + org.projectlombok + lombok + 1.18.38 + provided + + + + + \ No newline at end of file diff --git a/src/main/java/org/lapaloma/proyectos/ClasePrincipal.java b/src/main/java/org/lapaloma/proyectos/ClasePrincipal.java new file mode 100644 index 0000000..56a0e57 --- /dev/null +++ b/src/main/java/org/lapaloma/proyectos/ClasePrincipal.java @@ -0,0 +1,311 @@ +/** + * + */ +package org.lapaloma.proyectos; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.net.URL; +import java.time.Duration; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.lapaloma.proyectos.util.ConversorTipos; +import org.lapaloma.proyectos.util.GestorClientesServiciosAWS; + +import com.opencsv.bean.CsvToBeanBuilder; + +import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; +import software.amazon.awssdk.services.dynamodb.DynamoDbClient; +import software.amazon.awssdk.services.dynamodb.model.AttributeValue; +import software.amazon.awssdk.services.dynamodb.model.DynamoDbException; +import software.amazon.awssdk.services.dynamodb.model.GetItemRequest; +import software.amazon.awssdk.services.dynamodb.model.GetItemResponse; +import software.amazon.awssdk.services.dynamodb.model.PutItemRequest; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; +import software.amazon.awssdk.services.s3.model.PutObjectResponse; +import software.amazon.awssdk.services.s3.model.S3Exception; +import software.amazon.awssdk.services.s3.presigner.S3Presigner; +import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest; + +/** + * Clase principal encargada de probar el acceso a datos con los servicios S3 y + * DynamoDb de AWS + * + * @author Programador: Isidoro Nevares Martín - Virgen de la Paloma + * @date 25 may 2025 + * @version: 1.0 + */ +public class ClasePrincipal { + private final static String NOMBRE_TABLA = "ddb-hitos-proyecto"; + private final static String NOMBRE_BUCKET = "s3-objetos-proyecto"; + + /** + * @param args + */ + public static void main(String[] args) { + ClasePrincipal cp = new ClasePrincipal(); + // Probar almacenamiento en DynamoDb (dentro se almacena documento en S3) + cp.almacenarEstructuraHitosDynamoDB(); + + // Ejemplo de hito obtenido de un interfaz gráfico. + Hito hito = new Hito(); + hito.setIdProyecto(1); + hito.setNumeroHito(2); + Date fechaHito = ConversorTipos.convertirStringADate("2025-04-15T14:30:00"); + hito.setFechaHito(fechaHito); + File documentoAEnviar = new File("ficheros//Kingdom Town for Gods.pdf"); + hito.setDocumento(documentoAEnviar); + Date fechaEnvio = new Date(); // Contiene la fecha y hora actuales + hito.setFechaEnvio(fechaEnvio); + hito.setIdAlumnoEnvio(1); // Identificador del Alumn@ que realizó la entrega. + hito.setResumenEntrega("Cambios en el Diagrama de Casos de Uso."); + hito.setEstado("Enviado con retraso"); + + // Almacenamiento de un documento/imagen en un Bucket de S3 + cp.almacenarDocumentacionHitoEnS3(hito); + + // Actualizar información en DynamoDb con información Hito + cp.actualizarHitoDynamoDb(hito); + + // Consultar hito en DynamoDB + hito = cp.obtenerHitoProyectoPorClave(hito.getIdProyecto(), hito.getNumeroHito()); + System.out.println(hito); + + // Obtener información de S3 + String urlDocumentoS3 = cp.obtenerURLObjetoS3(hito.getClaveDocumentoS3()); + System.out.println(urlDocumentoS3); + + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void almacenarEstructuraHitosDynamoDB() { + List listaHitos = null; + try { + listaHitos = new CsvToBeanBuilder(new FileReader("ficheros/hitos-proyecto.csv")).withType(Hito.class) + .withSeparator('|').build().parse(); + for (Hito hitoCSV : listaHitos) { + System.out.println(hitoCSV); + // Crear un registro en una tabla DynamoDB + crearHitoDynamoDb(hitoCSV); + } + } catch (IllegalStateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + private void crearHitoDynamoDb(Hito hito) { + // Crear el cliente de DynamoDB (usando SDK v2) + DynamoDbClient clienteDynamoDb = GestorClientesServiciosAWS.getClienteDynamoDB(); + + // Crear un ítem con los atributos de un Hito + String fechaHitoString = ""; + if (hito.getFechaHito() != null) + fechaHitoString = ConversorTipos.convertirDateAString(hito.getFechaHito()); + + PutItemRequest putItemRequest = PutItemRequest.builder().tableName(NOMBRE_TABLA) + .item(Map.of("id_proyecto", AttributeValue.builder().n(String.valueOf(hito.getIdProyecto())).build(), + "numero_hito", AttributeValue.builder().n(String.valueOf(hito.getNumeroHito())).build(), + "fecha_hito", AttributeValue.builder().s(fechaHitoString).build())) + .build(); + + // Insertar el ítem en DynamoDB + try { + clienteDynamoDb.putItem(putItemRequest); + System.out.println("Ítem agregado exitosamente."); + } catch (DynamoDbException e) { + System.err.println("No se pudo insertar el ítem: " + e.getMessage()); + e.printStackTrace(); + } finally { + clienteDynamoDb.close(); + } + } + + private void actualizarHitoDynamoDb(Hito hito) { + // Crear el cliente de DynamoDB (usando SDK v2) + DynamoDbClient clienteDynamoDb = GestorClientesServiciosAWS.getClienteDynamoDB(); + + // Crear un ítem con los atributos de un Hito + String fechaHitoString = ""; + if (hito.getFechaHito() != null) + fechaHitoString = ConversorTipos.convertirDateAString(hito.getFechaHito()); + + String fechaEnvioString = ""; + if (hito.getFechaEnvio() != null) + fechaEnvioString = ConversorTipos.convertirDateAString(hito.getFechaEnvio()); + + String sIdAlumno = ""; + if (hito.getIdAlumnoEnvio() != null) + sIdAlumno = String.valueOf(hito.getIdAlumnoEnvio()); + + // Información del bucket y del archivo a subir + String claveDocumento = hito.getIdProyecto() + "/" + hito.getNumeroHito() + "/" + hito.getDocumento().getName(); + + PutItemRequest putItemRequest = PutItemRequest.builder().tableName(NOMBRE_TABLA) + .item(Map.of("id_proyecto", AttributeValue.builder().n(String.valueOf(hito.getIdProyecto())).build(), + "numero_hito", AttributeValue.builder().n(String.valueOf(hito.getNumeroHito())).build(), + "fecha_hito", AttributeValue.builder().s(fechaHitoString).build(), + "fecha_envio", AttributeValue.builder().s(fechaEnvioString).build(), + "id_alumno_envio", AttributeValue.builder().s(sIdAlumno).build(), + "clave_documento", AttributeValue.builder().s(claveDocumento).build(), + "resumen_entrega", AttributeValue.builder().s(hito.getResumenEntrega()).build(), + "estado", AttributeValue.builder().s(String.valueOf(hito.getEstado())).build())) + .build(); + + // Insertar el ítem en DynamoDB + try { + clienteDynamoDb.putItem(putItemRequest); + System.out.println("Ítem agregado exitosamente."); + } catch (DynamoDbException e) { + System.err.println("No se pudo insertar el ítem: " + e.getMessage()); + e.printStackTrace(); + } finally { + clienteDynamoDb.close(); + } + } + + private void almacenarDocumentacionHitoEnS3(Hito hito) { + // Crear el cliente de S3 (usando SDK v2) + S3Client clienteS3 = GestorClientesServiciosAWS.getClienteBucketS3(); + + // Información del bucket y del archivo a subir + String claveDocumento = hito.getIdProyecto() + "/" + hito.getNumeroHito() + "/" + hito.getDocumento().getName(); + + // Solicitud para subir el archivo + PutObjectRequest putObjectRequest = PutObjectRequest.builder().bucket(NOMBRE_BUCKET).key(claveDocumento) + .build(); + + try { + // Realizar la carga del archivo + PutObjectResponse response = clienteS3.putObject(putObjectRequest, hito.getDocumento().toPath()); + + // Imprimir respuesta de éxito + System.out.println("Archivo subido correctamente. ETag: " + response.eTag()); + } catch (S3Exception e) { + System.err.println("No se pudo insertar el ítem: " + e.getMessage()); + e.printStackTrace(); + } finally { + clienteS3.close(); + } + + } + + public Hito obtenerHitoProyectoPorClave(int idProyecto, int numeroHito) { + Hito hito = null; + + // Crear el cliente de DynamoDB (usando SDK v2) + DynamoDbClient clienteDynamoDb = GestorClientesServiciosAWS.getClienteDynamoDB(); + + // Clave para la consulta + Map clave = new HashMap<>(); + clave.put("id_proyecto", AttributeValue.builder().n(String.valueOf(idProyecto)).build()); + clave.put("numero_hito", AttributeValue.builder().n(String.valueOf(numeroHito)).build()); + + // Construir la petición + GetItemRequest request = GetItemRequest.builder().tableName(NOMBRE_TABLA).key(clave).build(); + + // Realizar consulta + GetItemResponse response = clienteDynamoDb.getItem(request); + + if (response.hasItem()) { + hito = new Hito(); + + Map item = response.item(); + + // Recuperar valores + String sFechaHito = item.get("fecha_hito").s(); + String sFechaEnvio = item.get("fecha_envio").s(); + String idAlumnoEnvio = item.get("id_alumno_envio").s(); + String claveDocumento = item.get("clave_documento").s(); + String resumenEntrega = item.get("resumen_entrega").s(); + String estado = item.get("estado").s(); + + Date fechaHito = ConversorTipos.convertirStringADate(sFechaHito); + Date fechaEnvio = ConversorTipos.convertirStringADate(sFechaEnvio); + + hito.setIdProyecto(idProyecto); + hito.setNumeroHito(numeroHito); + hito.setFechaHito(fechaHito); + hito.setIdAlumnoEnvio(Integer.parseInt(idAlumnoEnvio)); + hito.setFechaEnvio(fechaEnvio); + hito.setResumenEntrega(resumenEntrega); + hito.setEstado(estado); + hito.setClaveDocumentoS3(claveDocumento); + + } else { + System.out.println("No se encontró el hito para la clave dada."); + } + + clienteDynamoDb.close(); + return hito; + } + + private String obtenerURLObjetoS3(String claveDocumento) { + String urlObjetoS3 = null; + // Crear el cliente de S3 (usando SDK v2) + S3Client clienteS3 = GestorClientesServiciosAWS.getClienteBucketS3(); + + // Usar el perfil `learnerlab-profile` (el nombre del perfil en + // `~/.aws/credentials`) + ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create("default"); + + // Crear el cliente presigner de S3 con el perfil específico + S3Presigner presigner = S3Presigner.builder().region(GestorClientesServiciosAWS.REGION_AWS) + .credentialsProvider(credentialsProvider) // Usar el perfil especificado + .build(); + + // Crear la solicitud de obtención de objeto + GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(NOMBRE_BUCKET).key(claveDocumento) + .build(); + + // Generar la URL firmada + PresignedGetObjectRequest presignedRequest = presigner.presignGetObject( + builder -> builder.getObjectRequest(getObjectRequest).signatureDuration(Duration.ofMinutes(60)) // Duración + // de la + // URL + // firmada + ); + + // Obtener la URL firmada + URL presignedUrl = presignedRequest.url(); + urlObjetoS3 = presignedUrl.toString(); + + // Cerrar el presigner + presigner.close(); + + return urlObjetoS3; + } + + private void almacenarDocumentacionoEnS3(String claveDocumento, File ficheroDocumentoS3) { + // Crear el cliente de S3 (usando SDK v2) + S3Client clienteS3 = GestorClientesServiciosAWS.getClienteBucketS3(); + + // Solicitud para subir el archivo + PutObjectRequest putObjectRequest = PutObjectRequest.builder().bucket(NOMBRE_BUCKET).key(claveDocumento) + .build(); + + try { + // Realizar la carga del archivo + PutObjectResponse response = clienteS3.putObject(putObjectRequest, ficheroDocumentoS3.toPath()); + + // Imprimir respuesta de éxito + System.out.println("Archivo subido correctamente. ETag: " + response.eTag()); + } catch (S3Exception e) { + System.err.println("No se pudo insertar el ítem: " + e.getMessage()); + e.printStackTrace(); + } finally { + clienteS3.close(); + } + + } + +} diff --git a/src/main/java/org/lapaloma/proyectos/Hito.java b/src/main/java/org/lapaloma/proyectos/Hito.java new file mode 100644 index 0000000..01bf8bc --- /dev/null +++ b/src/main/java/org/lapaloma/proyectos/Hito.java @@ -0,0 +1,40 @@ +/** + * + */ +package org.lapaloma.proyectos; + +import java.io.File; +import java.util.Date; + +import com.opencsv.bean.CsvBindByName; +import com.opencsv.bean.CsvDate; + +import lombok.Data; + +/** + * Clase encargada de recoger información de negocio de Hito + * + * @author Programador: Isidoro Nevares Martín - Virgen de la Paloma + * @date 24 may 2025 + * @version: 1.0 + */ +@Data +public class Hito { + @CsvBindByName(column = "id_proyecto", required = true) + private int idProyecto; + + @CsvBindByName(column = "numero_hito", required = true) + private int numeroHito; + + @CsvBindByName(column = "fecha_hito", required = true) + @CsvDate("yyyy-MM-dd") + private Date fechaHito; + + private Date fechaEnvio; + private Integer idAlumnoEnvio; + private File documento; + private String resumenEntrega; + private String estado; + private String claveDocumentoS3; + +} diff --git a/src/main/java/org/lapaloma/proyectos/util/ConversorTipos.java b/src/main/java/org/lapaloma/proyectos/util/ConversorTipos.java new file mode 100644 index 0000000..5733e54 --- /dev/null +++ b/src/main/java/org/lapaloma/proyectos/util/ConversorTipos.java @@ -0,0 +1,47 @@ +/** + * + */ +package org.lapaloma.proyectos.util; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +/** + * Clase de utilidad encargada de realizar conversión entre tipos. + * + * @author Programador: Isidoro Nevares Martín - Virgen de la Paloma + * @date 24 may 2025 + * @version: 1.0 + */ +public class ConversorTipos { + // Evita que pueda construirse un objeto de la clase. + private ConversorTipos() { + } + + public static String convertirDateAString(Date fecha) { + String fechaString = null; + SimpleDateFormat formato = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + fechaString = formato.format(fecha); + + return fechaString; + + } + + public static Date convertirStringADate(String fechaString) { + Date fecha = null; + // Definir el formato en que está la fecha en el String + SimpleDateFormat formato = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + + try { + // Convertir el String a Date + fecha = formato.parse(fechaString); + } catch (ParseException e) { + // Manejo de errores si el formato no es válido + System.err.println("Error al convertir la fecha: " + e.getMessage()); + } + + return fecha; + } +} diff --git a/src/main/java/org/lapaloma/proyectos/util/GestorClientesServiciosAWS.java b/src/main/java/org/lapaloma/proyectos/util/GestorClientesServiciosAWS.java new file mode 100644 index 0000000..ab5bd0c --- /dev/null +++ b/src/main/java/org/lapaloma/proyectos/util/GestorClientesServiciosAWS.java @@ -0,0 +1,40 @@ +/** + * + */ +package org.lapaloma.proyectos.util; + +import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.dynamodb.DynamoDbClient; +import software.amazon.awssdk.services.s3.S3Client; + +/** + * Clase asociada a la gestión de clientes para servicios de AWS + * + * @author Programador: Isidoro Nevares Martín - Virgen de la Paloma + * @date 16 may 2025 + * @version: 1.0 + */ +public class GestorClientesServiciosAWS { + public final static Region REGION_AWS = Region.US_EAST_1; + + // Evita que pueda construirse un objeto de la clase. + private GestorClientesServiciosAWS() { + } + + public static S3Client getClienteBucketS3() { + S3Client clienteS3 = S3Client.builder() + .credentialsProvider(ProfileCredentialsProvider.create()) + .region(REGION_AWS).build(); + return clienteS3; + + } + + public static DynamoDbClient getClienteDynamoDB() { + // Crear el cliente de DynamoDB (usando SDK v2) + DynamoDbClient dynamoDbClient = DynamoDbClient.builder() + .region(REGION_AWS) + .build(); + return dynamoDbClient; + } +}