se agregó parametrizacion para el controller de receta.

se comentó resultadoPaginado.
se eliminaron try catch de debugging en el lado de recetas.
This commit is contained in:
luc662 2025-07-12 21:00:03 +00:00
parent d416dc97f7
commit f5a896365f
6 changed files with 118 additions and 139 deletions

View file

@ -48,6 +48,17 @@
<artifactId>grpc-api</artifactId>
<version>1.59.0</version>
</dependency>
<!-- gRPC core -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-core</artifactId>
<version>1.59.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>

View file

@ -4,6 +4,8 @@ package com.code.hyperledger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import com.code.hyperledger.config.FabricConfigProperties;
import com.code.hyperledger.models.Receta;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@ -33,7 +35,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@EnableConfigurationProperties(FabricConfigProperties.class)
@SpringBootApplication
public class App {
/*private static final String MSP_ID = System.getenv().getOrDefault("MSP_ID", "Org1MSP");

View file

@ -120,9 +120,6 @@ public class RecetaController {
}
List<Receta> recetas = recetaService.obtenerRecetasPorIds(ids);
// 🔍 Log de los IDs obtenidos desde el service
System.out.println("Recetas obtenidas del service con los siguientes IDs:");
for (Receta receta : recetas) {
System.out.println(" - " + receta.getId());
}
@ -132,10 +129,19 @@ public class RecetaController {
recetasDto.add(mapToDto(receta));
}
System.out.println("Recetas obtenidas del service con los siguientes IDs:");
return new ResponseEntity<>(recetasDto, HttpStatus.OK);
// 🔍 Log de los IDs obtenidos desde el service
} catch (IOException | GatewayException e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
} catch (Exception e) {
System.err.println("Error en submitTransaction: " + e.getMessage());
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@ -159,6 +165,10 @@ public class RecetaController {
e.printStackTrace(); // este bloque rara vez se ejecutaría si ya atrapás las anteriores
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
catch (Exception e) {
e.printStackTrace(); // este bloque rara vez se ejecutaría si ya atrapás las anteriores
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@PutMapping("/firmar")
@ -182,9 +192,12 @@ public class RecetaController {
e.printStackTrace(); // este bloque rara vez se ejecutaría si ya atrapás las anteriores
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
catch (Exception e) {
e.printStackTrace(); // este bloque rara vez se ejecutaría si ya atrapás las anteriores
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@PostMapping("/borrar")
public ResponseEntity<RecetaDto> delete(@RequestBody Map<String, String> requestBody) {
try {
@ -205,6 +218,10 @@ public class RecetaController {
e.printStackTrace(); // este bloque rara vez se ejecutaría si ya atrapás las anteriores
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
catch (Exception e) {
e.printStackTrace(); // este bloque rara vez se ejecutaría si ya atrapás las anteriores
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
private RecetaDto mapToDto(Receta receta) {

View file

@ -1,4 +1,4 @@
package main.java.com.code.hyperledger.models;
/*package com.code.hyperledger.models;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -13,3 +13,4 @@ public class ResultadoPaginado<T> {
private List<T> recetas;
private String bookmark;
}
*/

View file

@ -1,28 +1,26 @@
package com.code.hyperledger.services;
import io.grpc.TlsChannelCredentials;
import io.grpc.Grpc;
import io.grpc.ManagedChannel;
import com.code.hyperledger.config.FabricConfigProperties;
import com.code.hyperledger.models.Receta;
import com.code.hyperledger.models.RecetaDto;
//import com.code.hyperledger.models.ResultadoPaginado;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.grpc.Grpc;
import io.grpc.ManagedChannel;
import io.grpc.TlsChannelCredentials;
import lombok.SneakyThrows;
import main.java.com.code.hyperledger.models.ResultadoPaginado;
import org.hyperledger.fabric.client.*;
import org.hyperledger.fabric.client.identity.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.Identity;
import java.io.Reader;
import java.nio.file.*;
import java.security.InvalidKeyException;
import java.security.Signer;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
@ -31,23 +29,20 @@ import java.util.concurrent.TimeUnit;
@Service
public class RecetaService {
private static final String MSP_ID = System.getenv().getOrDefault("MSP_ID", "Org1MSP");
private static final String CHANNEL_NAME = System.getenv().getOrDefault("CHANNEL_NAME", "mychannel");
private static final String CHAINCODE_NAME = System.getenv().getOrDefault("CHAINCODE_NAME", "basic");
private static final Path CRYPTO_PATH = Paths
.get("../../test-network/organizations/peerOrganizations/org1.example.com");
private static final Path CERT_DIR_PATH = CRYPTO_PATH.resolve("users/User1@org1.example.com/msp/signcerts");
private static final Path KEY_DIR_PATH = CRYPTO_PATH.resolve("users/User1@org1.example.com/msp/keystore");
private static final Path TLS_CERT_PATH = CRYPTO_PATH.resolve("peers/peer0.org1.example.com/tls/ca.crt");
private static final String PEER_ENDPOINT = "localhost:7051";
private static final String OVERRIDE_AUTH = "peer0.org1.example.com";
private final FabricConfigProperties config;
private Contract contract;
private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
private static Path getFirstFilePath(Path dirPath) throws IOException {
@Autowired
public RecetaService(FabricConfigProperties config) {
this.config = config;
}
private Path getPath(String relativePath) {
return Paths.get(config.getCryptoPath()).resolve(relativePath);
}
private Path getFirstFilePath(Path dirPath) throws IOException {
try (var keyFiles = Files.list(dirPath)) {
return keyFiles.findFirst().orElseThrow();
}
@ -58,47 +53,50 @@ public class RecetaService {
public void init() {
var channel = newGrpcConnection();
var builder = Gateway.newInstance()
var gateway = Gateway.newInstance()
.identity(newIdentity())
.signer(newSigner())
.connection(channel)
.evaluateOptions(options -> options.withDeadlineAfter(5, TimeUnit.SECONDS))
.endorseOptions(options -> options.withDeadlineAfter(15, TimeUnit.SECONDS))
.submitOptions(options -> options.withDeadlineAfter(5, TimeUnit.SECONDS))
.commitStatusOptions(options -> options.withDeadlineAfter(1, TimeUnit.MINUTES));
.commitStatusOptions(options -> options.withDeadlineAfter(1, TimeUnit.MINUTES))
.connect();
try (var gateway = builder.connect()) {
this.setContract(gateway);
this.initLedger();
}
this.setContract(gateway);
this.initLedger();
}
private static ManagedChannel newGrpcConnection() throws IOException {
private ManagedChannel newGrpcConnection() throws IOException {
var tlsCertPath = getPath(config.getTlsCertPath());
var credentials = TlsChannelCredentials.newBuilder()
.trustManager(TLS_CERT_PATH.toFile())
.trustManager(tlsCertPath.toFile())
.build();
return Grpc.newChannelBuilder(PEER_ENDPOINT, credentials)
.overrideAuthority(OVERRIDE_AUTH)
return Grpc.newChannelBuilder(config.getPeerEndpoint(), credentials)
.overrideAuthority(config.getOverrideAuth())
.build();
}
private Identity newIdentity() throws IOException, CertificateException {
try (var certReader = Files.newBufferedReader(getFirstFilePath(CERT_DIR_PATH))) {
Path certPath = getFirstFilePath(getPath(config.getCertPath()));
try (Reader certReader = Files.newBufferedReader(certPath)) {
var certificate = Identities.readX509Certificate(certReader);
return new X509Identity(MSP_ID, certificate);
return new X509Identity(config.getMspId(), certificate);
}
}
private Signer newSigner() throws IOException, InvalidKeyException {
try (var keyReader = Files.newBufferedReader(getFirstFilePath(KEY_DIR_PATH))) {
Path keyPath = getFirstFilePath(getPath(config.getKeyPath()));
try (Reader keyReader = Files.newBufferedReader(keyPath)) {
var privateKey = Identities.readPrivateKey(keyReader);
return Signers.newPrivateKeySigner(privateKey);
}
}
private void setContract(final Gateway gateway) {
var network = gateway.getNetwork(CHANNEL_NAME);
contract = network.getContract(CHAINCODE_NAME);
var network = gateway.getNetwork(config.getChannelName());
contract = network.getContract(config.getChaincodeName());
}
private void initLedger() throws EndorseException, SubmitException, CommitStatusException, CommitException {
@ -110,120 +108,56 @@ public class RecetaService {
try {
ObjectMapper objectMapper = new ObjectMapper();
String recetaJson = objectMapper.writeValueAsString(receta);
contract.submitTransaction("CreateReceta", recetaJson);
System.out.println("Receta creada correctamente");
} catch (Exception e) {
System.err.println("Error en submitTransaction: " + e.getMessage());
e.printStackTrace();
}
}
public Receta obtenerReceta(String recetaId) throws GatewayException, IOException {
System.out.println("[INFO] Iniciando obtención de receta con ID: " + recetaId);
try {
System.out.println("[DEBUG] Ejecutando transacción 'ReadReceta' con ID: " + recetaId);
var evaluateResult = contract.evaluateTransaction("ReadReceta", recetaId);
System.out.println("[DEBUG] Resultado de transacción recibido: " + new String(evaluateResult));
ObjectMapper objectMapper = new ObjectMapper();
Receta receta = objectMapper.readValue(evaluateResult, Receta.class);
System.out.println("[INFO] Receta parseada exitosamente para ID: " + recetaId);
return receta;
} catch (GatewayException e) {
System.err.println("[ERROR] GatewayException al obtener receta con ID: " + recetaId);
e.printStackTrace(System.err);
throw e;
} catch (IOException e) {
System.err.println("[ERROR] IOException al parsear receta con ID: " + recetaId);
e.printStackTrace(System.err);
throw e;
} catch (Exception e) {
System.err.println("[ERROR] Error inesperado al obtener receta con ID: " + recetaId);
e.printStackTrace(System.err);
throw new RuntimeException("Error inesperado al obtener la receta", e);
}
public Receta obtenerReceta(String recetaId) throws Exception {
var evaluateResult = contract.evaluateTransaction("ReadReceta", recetaId);
return new ObjectMapper().readValue(evaluateResult, Receta.class);
}
public List<Receta> obtenerTodasLasRecetas() throws GatewayException, IOException {
public List<Receta> obtenerTodasLasRecetas() throws Exception {
var evaluateResult = contract.evaluateTransaction("GetAllRecetas");
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(evaluateResult,
objectMapper.getTypeFactory().constructCollectionType(List.class, Receta.class));
return new ObjectMapper().readValue(evaluateResult,
new ObjectMapper().getTypeFactory().constructCollectionType(List.class, Receta.class));
}
public List<Receta> obtenerRecetasPorIds(List<String> recetaIds) throws GatewayException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
System.out.println("Solicitando recetas con IDs: " + recetaIds);
String idsJson = objectMapper.writeValueAsString(recetaIds);
public List<Receta> obtenerRecetasPorIds(List<String> recetaIds) throws Exception {
String idsJson = new ObjectMapper().writeValueAsString(recetaIds);
var evaluateResult = contract.evaluateTransaction("GetMultipleRecetas", idsJson);
if (evaluateResult == null || evaluateResult.length == 0) {
System.err.println("GetMultipleRecetas devolvió una respuesta vacía.");
return new ArrayList<>();
}
List<Receta> recetas = objectMapper.readValue(
evaluateResult,
objectMapper.getTypeFactory().constructCollectionType(List.class, Receta.class));
System.out.println("Recetas obtenidas del contrato:");
for (Receta receta : recetas) {
System.out.println(" - ID: " + receta.getId() + " | Estado: " + receta.getStatus());
}
return recetas;
return new ObjectMapper().readValue(evaluateResult,
new ObjectMapper().getTypeFactory().constructCollectionType(List.class, Receta.class));
}
public void entregarReceta(String recetaId)
throws CommitStatusException, EndorseException, CommitException, SubmitException {
public void entregarReceta(String recetaId) throws Exception {
contract.submitTransaction("EntregarReceta", recetaId);
}
public void firmarReceta(String recetaId, String signature)
throws CommitStatusException, EndorseException, CommitException, SubmitException {
System.out.println("[INFO] Iniciando firma de receta con ID: " + recetaId);
try {
var evaluateResult = contract.submitTransaction("FirmarReceta", recetaId, signature);
System.out.println("[DEBUG] Resultado de transacción recibido: " + new String(evaluateResult));
System.out.println("[INFO] Receta firmada exitosamente para ID: " + recetaId);
} catch (Exception e) {
System.err.println("[ERROR] Error al firmar receta: " + e.getMessage());
e.printStackTrace();
}
public void firmarReceta(String recetaId, String signature) throws Exception {
contract.submitTransaction("FirmarReceta", recetaId, signature);
}
public void borrarReceta(String recetaId)
throws CommitStatusException, EndorseException, CommitException, SubmitException {
System.out.println("[INFO] Iniciando borrado de receta con ID: " + recetaId);
try {
var evaluateResult = contract.submitTransaction("DeleteReceta", recetaId);
System.out.println("[DEBUG] Resultado de transacción recibido: " + new String(evaluateResult));
System.out.println("[INFO] Receta borrada exitosamente para ID: " + recetaId);
} catch (Exception e) {
System.err.println("[ERROR] Error al borrar receta: " + e.getMessage());
e.printStackTrace();
}
public void borrarReceta(String recetaId) throws Exception {
contract.submitTransaction("DeleteReceta", recetaId);
}
public ResultadoPaginado<RecetaDto> obtenerRecetasPorDniYEstadoPaginado(
String dni, String estado, int pageSize, String bookmark) throws GatewayException, IOException {
if (dni == null || dni.isBlank() || estado == null || estado.isBlank()) {
throw new IllegalArgumentException("DNI y estado son obligatorios");
}
var result = contract.evaluateTransaction("GetRecetasPorDniYEstado", dni, estado, String.valueOf(pageSize),
bookmark);
var type = new ObjectMapper()
.getTypeFactory()
.constructParametricType(ResultadoPaginado.class, RecetaDto.class);
return new ObjectMapper().readValue(result, type);
}
/*
* public ResultadoPaginado<RecetaDto> obtenerRecetasPorDniYEstadoPaginado(
* String dni, String estado, int pageSize, String bookmark) throws Exception {
*
* var result = contract.evaluateTransaction("GetRecetasPorDniYEstado", dni,
* estado,
* String.valueOf(pageSize), bookmark);
*
* var type = new ObjectMapper()
* .getTypeFactory()
* .constructParametricType(ResultadoPaginado.class, RecetaDto.class);
*
* return new ObjectMapper().readValue(result, type);
* }
*/
}

View file

@ -1 +1,15 @@
spring.application.name=main
# Fabric configs
fabric.mspId=Org1MSP
fabric.channelName=mychannel
fabric.chaincodeName=basic
fabric.peerEndpoint=localhost:7051
fabric.overrideAuth=peer0.org1.example.com
# Rutas a certificados y claves
fabric.cryptoPath=../../test-network/organizations/peerOrganizations/org1.example.com
fabric.certPath=users/User1@org1.example.com/msp/signcerts
fabric.keyPath=users/User1@org1.example.com/msp/keystore
fabric.tlsCertPath=peers/peer0.org1.example.com/tls/ca.crt