Instalación y Configuración
Guía completa para instalar y configurar el Shori SDK en tu proyecto Java.
Requisitos del sistema
| Componente | Versión mínima |
|---|---|
| Java | 17+ |
| Maven | 3.6+ |
| Spring Boot (opcional) | 2.7+ / 3.x |
Instalación con Maven
Añade el repositorio y la dependencia en tu pom.xml:
<!-- 1. Repositorio del SDK (GitLab Package Registry - público) -->
<repositories>
<repository>
<id>gitlab-maven</id>
<url>https://gitlab.com/api/v4/projects/84253138/packages/maven</url>
</repository>
</repositories>
<!-- 2. Dependencia -->
<dependency>
<groupId>com.nttdata.shori</groupId>
<artifactId>shori-api-client</artifactId>
<version>1.0.0</version>
</dependency>
El Package Registry es público. No necesitas configurar tokens ni credenciales para descargar el artefacto.
Configuración básica
Parámetros requeridos
| Parámetro | Descripción | Ejemplo |
|---|---|---|
environment | Ambiente de Shori | ShoriEnvironment.PROD |
portalId | UUID del portal en Shori | "0306444E-38B1-..." |
tenantId | UUID del tenant/organización | "80ff134a-cae2-..." |
apiKey | Clave de API para autenticación | "sk-live-xxxxx" |
ShoriClient client = ShoriClient.builder()
.environment(ShoriEnvironment.PROD)
.portalId("0306444E-38B1-403D-8753-EC9C2BC43215")
.tenantId("80ff134a-cae2-4a4a-92b9-a109bdee1183")
.apiKey("tu-api-key-secreta")
.build();
Parámetros opcionales
| Parámetro | Descripción | Default |
|---|---|---|
timeoutSeconds | Timeout de conexión y respuesta | 30 |
allowInsecureSsl | Aceptar certificados SSL auto-firmados | true |
downloadPath | Ruta local para archivos descargados | carpeta temporal del SO |
ShoriClient client = ShoriClient.builder()
.environment(ShoriEnvironment.UAT)
.portalId("tu-portal-id")
.tenantId("tu-tenant-id")
.apiKey("tu-api-key")
.timeoutSeconds(60) // 60 segundos de timeout
.allowInsecureSsl(true) // útil en UAT con certificados auto-firmados
.downloadPath("/opt/app/downloads") // ruta para documentos descargados
.build();
Ambientes disponibles
| Ambiente | Constante | Descripción |
|---|---|---|
| Desarrollo | ShoriEnvironment.DEV | Ambiente local de desarrollo |
| Pruebas | ShoriEnvironment.UAT | User Acceptance Testing |
| Producción | ShoriEnvironment.PROD | Ambiente productivo |
// En desarrollo
ShoriClient devClient = ShoriClient.builder()
.environment(ShoriEnvironment.DEV)
.portalId("portal-dev")
.tenantId("tenant-dev")
.apiKey("api-key-dev")
.allowInsecureSsl(true)
.build();
// En producción
ShoriClient prodClient = ShoriClient.builder()
.environment(ShoriEnvironment.PROD)
.portalId("portal-prod")
.tenantId("tenant-prod")
.apiKey("api-key-prod")
.allowInsecureSsl(false) // En producción, verificar el certificado SSL
.build();
Integración con Spring Boot
Configuración recomendada
Define el cliente como un @Bean en una clase de configuración:
@Configuration
public class ShoriConfiguration {
@Value("${shori.portal-id}")
private String portalId;
@Value("${shori.tenant-id}")
private String tenantId;
@Value("${shori.api-key}")
private String apiKey;
@Value("${shori.environment:PROD}")
private String environment;
@Value("${shori.timeout-seconds:30}")
private int timeoutSeconds;
@Bean(destroyMethod = "close")
public ShoriClient shoriClient() {
return ShoriClient.builder()
.environment(ShoriEnvironment.valueOf(environment))
.portalId(portalId)
.tenantId(tenantId)
.apiKey(apiKey)
.timeoutSeconds(timeoutSeconds)
.build();
}
}
Variables en application.properties
# Shori SDK Configuration
shori.portal-id=0306444E-38B1-403D-8753-EC9C2BC43215
shori.tenant-id=80ff134a-cae2-4a4a-92b9-a109bdee1183
shori.api-key=${SHORI_API_KEY}
shori.environment=PROD
shori.timeout-seconds=30
Variables en application.yml
shori:
portal-id: "0306444E-38B1-403D-8753-EC9C2BC43215"
tenant-id: "80ff134a-cae2-4a4a-92b9-a109bdee1183"
api-key: "${SHORI_API_KEY}"
environment: PROD
timeout-seconds: 30
Inyección en servicios
@Service
public class CasoService {
private final ShoriClient shoriClient;
public CasoService(ShoriClient shoriClient) {
this.shoriClient = shoriClient;
}
public String crearSolicitud(Map<String, Object> datos) {
CasoCreateResponse resultado = shoriClient.caso().create(
CasoCreateRequest.builder()
.casoTypeId("tipo-uuid")
.formId("form-uuid")
.submittedData(datos)
.build()
);
return resultado.getCaso();
}
}
Gestión del ciclo de vida
Cerrar el cliente manualmente
// Al finalizar la aplicación
client.close();
En Spring Boot (automático)
Al declarar el bean con destroyMethod = "close", Spring llama automáticamente a close() cuando el contexto de la aplicación se destruye. No es necesario ningún paso adicional.
Configuración de SSL
Por defecto, allowInsecureSsl(true) está habilitado para facilitar el desarrollo en ambientes con certificados auto-firmados. En producción, se recomienda desactivarlo:
ShoriClient client = ShoriClient.builder()
...
.allowInsecureSsl(false) // Verificar certificado SSL en producción
.build();
Nunca uses allowInsecureSsl(true) en un ambiente de producción. Esto desactiva la verificación del certificado del servidor y expone la comunicación a ataques de tipo man-in-the-middle.
Integración con JavaFX y RDA/RPA
Si usas el SDK en una aplicación de escritorio JavaFX o en un sistema de automatización
(RDA/RPA) con múltiples ventanas o procesos, usa el ShoriClientRegistry para
gestionar los clientes de forma centralizada.
¿Qué es ShoriClientRegistry?
Es una clase de utilidad incluida en el SDK que actúa como registro centralizado de
instancias de ShoriClient. Garantiza que cada cliente se inicialice una sola vez
y se reutilice durante toda la vida de la aplicación.
Estructura recomendada para JavaFX
// Application — controla el ciclo de vida completo
public class RdaHubApp extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/MainView.fxml"));
Scene scene = new Scene(loader.load());
primaryStage.setScene(scene);
primaryStage.setTitle("RDA Hub");
primaryStage.show();
}
@Override
public void stop() throws Exception {
// Cierra TODOS los ShoriClients al cerrar la app (X o Platform.exit())
ShoriClientRegistry.closeAll();
}
}
// Controller JavaFX — registra el cliente UNA SOLA VEZ en initialize()
public class PortabilityDownloadController {
// Nombre que identifica esta automatización en el registry
private static final String CLIENT_NAME = "portabilidad";
private PortabilitySearchService searchService;
@FXML
public void initialize() {
// Si el cliente ya fue registrado (ventana abierta antes), no lo recrea.
// Si no existe, lo crea con las credenciales indicadas.
ShoriClientRegistry.register(
CLIENT_NAME,
"portal-portabilidad-uuid",
"tenant-portabilidad-uuid",
"api-key-portabilidad",
ShoriEnvironment.PROD
);
searchService = new PortabilitySearchService();
loadInitialData();
}
private void loadInitialData() {
searchService.setOnSucceeded(e -> {
List<CasoSearchResponse> casos = searchService.getValue();
// actualizar UI con los casos
});
searchService.setOnFailed(e ->
System.err.println("Error: " + searchService.getException().getMessage())
);
searchService.start();
}
}
// Modelo JavaFX — extiende Service<T> y obtiene el cliente por nombre
public class PortabilitySearchService extends Service<List<CasoSearchResponse>> {
private static final String CLIENT_NAME = "portabilidad";
@Override
protected Task<List<CasoSearchResponse>> createTask() {
return new Task<>() {
@Override
protected List<CasoSearchResponse> call() {
// Obtiene el cliente SIN necesidad de pasar credenciales
ShoriClient client = ShoriClientRegistry.get(CLIENT_NAME);
ProductResponse producto = client.caso().casoType()
.findById("producto-portabilidad-uuid");
List<String> estadosAbiertos = ShoriUtils.openStatesIds(producto);
return client.caso().searchAll(
CaseFilter.builder()
.casoTypeId(FilterOperator.EQ, producto.getId())
.workingSubStateId(FilterOperator.IN,
estadosAbiertos.toArray(new String[0]))
.pageSize(100)
.build()
);
}
};
}
}
// Modelo de descarga — mismo patrón
public class PortabilityDownloadService extends Service<RequestStatus> {
private static final String CLIENT_NAME = "portabilidad";
private AttachmentFilterBody filterBody;
public void setFilterBody(AttachmentFilterBody filterBody) {
this.filterBody = filterBody;
}
@Override
protected Task<RequestStatus> createTask() {
AttachmentFilterBody body = this.filterBody;
return new Task<>() {
@Override
protected RequestStatus call() {
ShoriClient client = ShoriClientRegistry.get(CLIENT_NAME);
// lógica de descarga usando el cliente
updateProgress(0, 100);
// ...
return RequestStatus.SUCCESS;
}
};
}
}
Múltiples automatizaciones (RDA/RPA)
Cada automatización tiene su propio nombre en el registry y sus propias credenciales. Si el usuario abre dos ventanas distintas, cada una tiene su cliente independiente:
// Automatización A — portabilidad
ShoriClientRegistry.register("portabilidad",
"portal-port", "tenant-port", "key-port", ShoriEnvironment.PROD);
// Automatización B — activaciones (credenciales diferentes)
ShoriClientRegistry.register("activaciones",
"portal-act", "tenant-act", "key-act", ShoriEnvironment.PROD);
// En cada modelo, solo llamas get() con el nombre de su automatización
ShoriClient client = ShoriClientRegistry.get("portabilidad");
ShoriClient client = ShoriClientRegistry.get("activaciones");
Configuración avanzada para JavaFX (alta concurrencia)
Si tu automatización procesa muchos casos en paralelo, aumenta maxConnections:
ShoriClientRegistry.register(
"portabilidad",
portalId, tenantId, apiKey,
ShoriEnvironment.PROD,
true, // allowInsecureSsl
30, // timeoutSeconds
10 // maxConnections — 10 por módulo = 30 conexiones totales
);
Javadoc y código fuente en el IDE
A partir de la versión 1.0.0, el pipeline publica automáticamente junto al JAR principal los artefactos:
shori-api-client-1.0.0-sources.jar— código fuente del SDKshori-api-client-1.0.0-javadoc.jar— documentación Javadoc compilada
Maven los descarga automáticamente al ejecutar mvn install. Esto permite que tu IDE muestre el Javadoc en los tooltips y navegue al código fuente del SDK.
Si el IDE no los muestra automáticamente:
IntelliJ IDEA: Clic derecho sobre la dependencia en el panel Maven → Download Sources & Documentation
VSCode (Extension Pack for Java):
Ctrl+Shift+P → Java: Import Java Projects para refrescar las dependencias
Solución de problemas comunes
ValidationException: El ambiente (environment) es requerido
// ❌ Incorrecto — falta el ambiente
ShoriClient.builder()
.portalId("id")
.apiKey("key")
.build();
// ✅ Correcto
ShoriClient.builder()
.environment(ShoriEnvironment.PROD) // ← requerido
.portalId("id")
.tenantId("tenant-id") // ← requerido
.apiKey("key")
.build();
AuthenticationException: Error al obtener token
- Verifica que el
apiKeysea correcto para el ambiente seleccionado. - Confirma que el
portalIdytenantIdcorresponden al ambiente seleccionado. - Revisa la conectividad de red con los servidores de Shori.
javax.net.ssl.SSLHandshakeException
Si ves este error en UAT o DEV, habilita el modo SSL permisivo:
.allowInsecureSsl(true)
Acerca del timeout y searchAll
timeoutSeconds aplica por cada request HTTP individual, no al proceso total de searchAll.
searchAll realiza múltiples requests en secuencia (uno por página). Si tienes 5.000 casos con pageSize=100, ejecuta 50 requests de forma encadenada. Cada uno tiene su propio timeout independiente. El proceso total puede tardar varios minutos sin que se dispare ningún timeout, porque cada llamada individual sí responde dentro del límite.
searchAll (5.000 casos, pageSize=100)
├── Request 1 → página 0 → responde en 2s ✅
├── Request 2 → página 1 → responde en 2s ✅
├── ...
└── Request 50 → página 49 → responde en 2s ✅
Tiempo total: ~100s ← sin timeout, cada request fue < 30s
Solo necesitas aumentar timeoutSeconds si una sola llamada al API tarda en responder (API lenta, payload muy grande, problemas de red):
.timeoutSeconds(60) // útil si el API tarda en responder cada página individualmente