CON3 - Escribiendo su propio Conector (HTTP)

Para comenzar

El paso del tutorial utiliza la solución "add_kafka" del proyecto como su punto de partida.

Si en algún momento desea ver la solución a este paso, puede encontrarla en la solución "add_http".

En CON2 - Escribiendo su propio conector (Kafka), conectamos nuestra aplicación con un sistema de sanciones externo para realizar solicitudes. Para ello, creamos nuestro propio Kafka conector y lo utilizó para enviar solicitudes y recibir las respuestas a través de Kafka. En este tutorial, vamos a cambiar nuestros protocolos y a considerar el uso de HTTP.

Una diferencia importante con el ejemplo anterior es que, mientras que al utilizar Kafka estábamos utilizando el conector de manera asíncrona, esta vez necesitamos utilizar uno sincrónico HTTP llamada. Esto significa que necesitamos utilizar un estilo diferente de conector.- el "Request Reply Connector"

Usted lo hará integrándose con un sistema de fraude de prueba. Este sistema:

  • Espera recibir un custom OlafRequest objeto.

  • Devolverá un custom OlafResponse objeto.

Clases de Soporte

Lo primero que haremos es importar la definición del dominio para el sistema de fraude. Para ello, necesitamos añadir una dependencia en nuestras aplicaciones.pom.xml:

<dependency>
    <artifactId>fraud-domain</artifactId>
    <groupId>com.iconsolutions.ipf.sample.samplesystems</groupId>
</dependency>

Veamos las clases clave que recibimos de este módulo. La primera es el objeto de solicitud que enviamos al sistema de fraude.

@Data
public class OlafRequest extends SampleEvent<OlafRequestPayload> {
}

Si profundizamos un poco más, encontraremos que el elemento clave de la carga útil es el FraudRequest:

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FraudRequest {
    ObjectNode fiToFICstmrCdtTrf;
}

Aquí podemos ver que se espera que se le proporcione un pacs. 008 en un formato ObjectNode. Esto es solo un jackson representación del pacs008.

Mapping

En nuestro Kafka ejemplo utilizamos un paquete predefinido mapper para convertir de nuestro pacs. 008 a la solicitud de Olaf. Aquí, como un ejemplo de los diferentes enfoques disponibles, escribiremos nuestro propio mapper.

Así que comencemos creando un mapping clase que puede tomar nuestro pacs. 008 y cree nuestra solicitud de fraude para nosotros. Usted hará esto creando un nuevo " mappers " empaquetar y luego agregar una clase para el "FraudMapper"."

Para crear el objeto FraudRequest, necesitaremos utilizar el jackson mapper’s valueToTree método. Podemos entonces utilizar esto para construir nuestro FraudRequest. Una vez que tengamos esto, lo envolvemos en el objeto OlafRequest.

El objeto olafRequest en sí espera un encabezado que debe contener un técnico event id y un componente funcional (puede ver esto profundizando en la clase SampleEvent y la clase Header de samplesystems.shared.model). Vea si puede crear esto.mapping método ahora, y cuando esté listo, la solución se encuentra a continuación:

@AllArgsConstructor
public class FraudMapper {

    private final Config config;
    private final String prefix;
    private final ObjectMapper objectMapper;

    public OlafRequest mapToRequest(FIToFICustomerCreditTransferV08 fiToFICustomerCreditTransfer) {
        FraudRequest fraudRequest = new FraudRequest();
        fraudRequest.setFiToFICstmrCdtTrf(objectMapper.valueToTree(fiToFICustomerCreditTransfer));

        OlafRequest olafRequest = new OlafRequest();
        olafRequest.setHeader(Header.builder()
                .technical(Technical.builder().eventId("EventId").build())
                .functional(Functional.builder().build())
                .build());
        olafRequest.setPayload(new OlafRequestPayload(fraudRequest));
        return olafRequest;
    }
}

Tenga en cuenta que no estamos utilizando ningún marco especial para realizar nuestro mapping como en este caso es simplemente un java mapping eso es lo más fácil.

Ahora pensemos en el lado de la respuesta. En primer lugar, necesitaremos un método para mapear desde el cuerpo de la HTTP respuesta a un FraudResponse objeto. Para esto, nuevamente utilizaremos el ObjectMapper:

public OlafResponse convertResponse(String messageText) {
    try {
        return objectMapper.readValue(messageText, OlafResponse.class);
    } catch (JsonProcessingException e) {
        throw new IconRuntimeException(e);
    }
}

Añadamos este método a nuestro FraudMapper.

Finalmente, también necesitaremos un método para mapear el objeto OlafRequest a un TransportMessage. En este caso, nuestro transport message necesita incluir dos cosas:

  • El OlafRequest en sí mismo como una carga útil de cadena.

  • Un conjunto de encabezados que contiene:

    • An " httpUrl " encabezado que contiene la url del endpoint a objetivo"

    • Un " httpMethod " encabezado, en este caso solo una constante "POST"

    • Un encabezado "Content-Type", en este caso solo un constante "application/json "

Para la URL del endpoint, recuperaremos el valor de la configuración.

Vea si puede añadir el método a nuestro FraudMapper, y luego, cuando esté listo, la solución se encuentra a continuación:

public TransportMessage mapToTransport(OlafRequest olafRequest) {
    try {
        Config httpConfig = config.getConfig(prefix + ".http.client");
        String endpointUrl = httpConfig.hasPath("endpoint-url")? httpConfig.getString("endpoint-url"): null;
        MessageHeaders messageHeaders = new MessageHeaders(CryptoHelper.messageHeaders())
                .putHeader("httpUrl",  endpointUrl)
                .putHeader("httpMethod", "POST")
                .putHeader("Content-Type", "application/json");
        return new TransportMessage(messageHeaders, objectMapper.writeValueAsString(olafRequest));
    } catch (JsonProcessingException e) {
        throw new IconRuntimeException(e);
    }
}

Necesitamos utilizar Spring para proporcionarnos una instancia de FraudMapper que podamos usar. Para hacer esto, crearemos un nuevo bean dentro de la IpfTutorialConfig clase como:

@Bean
public FraudMapper fraudMapper(ActorSystem actorSystem, ObjectMapper objectMapper) {
    return new FraudMapper(actorSystem.classicSystem().settings().config(), "fraud", objectMapper);
}

Eso es todo de nuestro mappings Preparado, proceda a comenzar a crear nuestro conector.

El Conector

Ahora que tenemos nuestro mapper Listo, estamos listos para comenzar a construir nuestro conector.

Primero, añadamos la dependencia para el marco del conector. HTTP implementación.

<dependency>
    <groupId>com.iconsolutions.ipf.core.connector</groupId>
    <artifactId>connector-http</artifactId>
</dependency>

Ahora escribamos nuestro conector, nuevamente necesitará hacer algunos decisions primero:

  • Tipos- La definición de un conector de solicitud-respuesta es RequestReplySendConnector<REQ_D, REQ_T, REP_D, REP_T>. En este caso:

  • el REQ_D el tipo de solicitud de dominio proporcionado por el flujo

  • el REQ_T el http tipo de solicitud enviada al HTTP servicio

  • el REP_D el tipo de respuesta de dominio enviado de vuelta al flujo

  • el REP_T el http tipo de respuesta recibido de la HTTP servicio

En nuestro conector se tomará un FIToFICustomerCreditTransferV08, transfórmelo en un OlafRequest enviar al sistema de Fraude y luego devolver un OlafResponse. Cuando recibamos eso OlafResponse lo dejaremos en ese formato (pero podríamos asignarlo a algo más si quisiéramos).

  • Registro- Al igual que en nuestro ejemplo anterior, lo haremos lo más simple posible y utilizaremos la implementación de registro que se nos ha proporcionado.

  • Mapeo- Aquí utilizaremos nuestro mapper¡discutimos arriba!

Comencemos pensando a nivel de clase. Usted creará una nueva clase dentro de nuestro paquete de conectores para el FraudConnectorConfiguration.

Su clase necesitará acceder al sistema de actores, el fraude mapper y el message logger implementación para apoyar la creación del conector de solicitud y respuesta.

@Slf4j
@Configuration
@AllArgsConstructor
public class FraudConnectorConfiguration {

    private final ClassicActorSystemProvider actorSystem;
    private final MessageLogger messageLogger;
    private final FraudMapper fraudMapper;

    @Bean
    public RequestReplySendConnector<FIToFICustomerCreditTransferV08, OlafRequest, OlafResponse, OlafResponse> fraudSendConnector() {

        return new RequestReplySendConnector. Builder<FIToFICustomerCreditTransferV08, OlafRequest, OlafResponse, OlafResponse>(
                "Fraud", "fraud.connector", actorSystem)
                .withMessageLogger(messageLogger)
                .withDomainToTargetTypeConverter(fraudMapper::mapToRequest)
                .withSendTransportMessageConverter(fraudMapper::mapToTransport)
                .withConnectorTransport(fraudHttpConnectorTransport)
                .withReceiveTransportMessageConverter(message -> fraudMapper.convertResponse(message.getPayload().toString()))
                .build();
    }

    @Bean
    @SneakyThrows
    public HttpConnectorTransport fraudHttpConnectorTransport() {
        return new HttpConnectorTransport. Builder("OlafRequestReplyHttpConnectorTransport", actorSystem, "fraud")
                .build();
    }

}

Esto es lo suficientemente importante como para revisar cada parte por turno.

  • La construcción del constructor- esto toma una cadena simple para nombrar el conector, el prefijo de configuración para el conector

  • el sistema de actores- Un Sistema de Actores en Akka proporciona un entorno de ejecución para gestionar y ejecutar actores, coordinar el paso de mensajes y manejar la concurrencia. Aunque es útil saberlo, no es necesario que entienda el sistema de actores para desarrollar con IPF de manera efectiva.

  • el transporte- construimos esto aquí, proporcionando un nombre simple, el sistema de actores, y el prefijo de configuración

  • el message logger- Como se discutió, simplemente utilizaremos enfoques de registro estándar aquí por ahora.

  • el convertidor de tipo de dominio a objetivo- aquí utilizaremos nuestro método mapToRequest que construimos en el FraudMapper, para mapear FIToFICustomerCreditTransfer a un OlafRequest.

  • el transport message converter- aquí utilizaremos nuestro mapToTransport método que construimos sobre el FraudMapper, para mapear el OlafRequest a un TransportMessage.

  • el convertidor de tipo de transporte de recepción- aquí simplemente proporcionaremos una función que convierte la carga del mensaje en una cadena y luego utiliza nuestro fraude mapper servicio para cambiar a nuestro OlafResponse.

Eso es, esa es nuestra primera solicitud/respuesta.send connector construido desde cero.

Puede preguntarse dónde se encuentran los controles de correlación. En el mundo de solicitud-respuesta, debido a que todo es sincrónico, las características de correlación son una complejidad de la que no debemos preocuparnos, ya que todo se maneja dentro del mismo hilo.

Ese es nuestro conector definido.

Utilizando el conector

Ahora volvamos a nuestra FraudSystemActionAdapter. Para simplificar las cosas en nuestro caso de uso actual, usted simplemente adaptará el caso de uso de éxito existente ("else" en el código a continuación) para enviar al FraudSystem utilizando el recién construido HTTP conector, enviando su pacs. 008 al servicio de fraude. Asumirá por brevedad que cualquier respuesta es exitosa.

Vea si puede actualizar el adaptador ahora, y cuando esté listo, la solución se encuentra a continuación (las otras condiciones else-if permanecen como antes).

@Slf4j
public class FraudSystemActionAdapter implements FraudSystemActionPort {

    private RequestReplySendConnector<FIToFICustomerCreditTransferV08, OlafRequest, OlafResponse, OlafResponse> fraudConnector;

    @Autowired
    public FraudSystemActionAdapter(RequestReplySendConnector<FIToFICustomerCreditTransferV08, OlafRequest, OlafResponse, OlafResponse> fraudConnector) {
        this.fraudConnector = fraudConnector;
    }

    ..

        } else {
            return fraudConnector.send(action.getProcessingContext(), action.getCustomerCreditTransfer())
                    .thenCompose(response -> IpftutorialmodelDomain.fraudSystem().handle(new FraudCheckResponseInput. Builder(action.getId(), AcceptOrRejectCodes. Accepted).build())
                    .thenAccept(done -> log.debug("Sent input of type {} for id {} with result {}", done.getCommandName(), action.getId(), done.getResult().name())));
        }
    }
}

También necesita realizar una modificación para utilizar el RequestReplySendConnector fraudConnector y el cambiado FraudSystemActionAdapter ahora que hemos añadido el FraudConnector a su constructor.

@Bean
  public IpftutorialmodelDomain init(ActorSystem actorSystem,
                   IsoMappingService mappingService,
                   SendConnector<FIToFICustomerCreditTransferV08, SanctionsRequest> sanctionsConnector,
                   RequestReplySendConnector<FIToFICustomerCreditTransferV08, OlafRequest, OlafResponse, OlafResponse> fraudConnector) {
    ..

                .withFraudSystemActionAdapter(new FraudSystemActionAdapter(fraudConnector))

    ..

Eso es todo nuestro código terminado, a continuación, revisemos la configuración.

Configuración

Usted añadirá nuestra configuración en el archivo de configuración de nuestra aplicación (ipf-tutorial-app/application.conf).

fraud {
  transport = http
  http {
    client {
      host = "localhost"
      port = "8089"
      endpoint-url = "/v1"
    }
  }
}

Esta configuración asume que el simulador de fraude se ejecutará en el localhost y el puerto 8089. Esto es lo que será al ejecutarse desde la línea de comandos (consulte no-docker setup). Si estamos ejecutando desde dentro de docker, necesitaremos actualizar solo el host y el puerto.

Eso es todo lo que hemos completado desde nuestra parte de la aplicación.

Ejecutando la aplicación

Para ejecutar la aplicación, lo primero que debe hacer es configurar el servicio de fraude real con el que estará interactuando. Para esto, necesita una nueva entrada en el application.yml(docker/application.yml)

Docker Configuración

  fraud-sim:
    image:registry.ipf.iconsolutions.com/sample-systems-fraud-simulator-http:2. 1. 46
    container_name: fraud-sim
    environment:
      - FRAUD_SIM_ENCRYPTION_ENABLED=FALSE
    ports:
      - 8089:8080
      - 8090:55555
    volumes:
      -./config/fraud:/fraud-simulator-http/conf
      -./logs:/ipf/logs
    user: "${UID:-1000}:${GID:-1000}"

Tenga en cuenta que la versión "2. 1. 46" proporcionada aquí es la última versión en el momento de la redacción de este documento.

Para facilitar las cosas, también añadirá un logback.xml archivo:

<? xml version="1. 0" encoding="UTF-8"?>
<configuration>
    <appender name="FILE"
              class="ch.qos.logback.core.rolling. RollingFileAppender">
        <file>/ipf/logs/fraud-sim.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling. FixedWindowRollingPolicy">
            <fileNamePattern>/ipf/logs/fraud-sim.log.%i</fileNamePattern>
            <minIndex>1</minIndex>
            <maxIndex>20</maxIndex>
        </rollingPolicy>
        <triggeringPolicy
                class="ch.qos.logback.core.rolling. SizeBasedTriggeringPolicy">
            <maxFileSize>50MB</maxFileSize>
        </triggeringPolicy>
        <encoder>
            <pattern>%date{yyyy-MM-dd} %d{HH:mm:ss. SSS} %-5level %X{traceId} %logger{36} %X{sourceThread} %X{akkaSource} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="FILE" />
    </root>
</configuration>

También deberá actualizar el application.conf en el docker configuración para indicarle el nombre del host del nuevo simulador de fraude. Para hacer esto, simplemente añadimos:

fraud {
  http {
    client {
      host = "fraud-sim"
      port = 8080
    }
  }
}

Non Docker Configuración

Los detalles sobre cómo ejecutar el simulador de fraude se pueden encontrar aquí:Uso del simulador de fraude

Probando que todo funcione

Ahora es el momento de verificar que todo funcione, así que reconstruya la aplicación:

mvn clean install -rf:ipf-tutorial-app

Y luego puede enviar un pago:

curl -X POST localhost:8080/submit -H 'Content-Type: application/json' -d '{"value": "25"}' | jq
[NOTA]
====
Tenga en cuenta que está enviando un valor de 25. Eso es para asegurar que alcance nuestro camino feliz y se comunique con el Simulador de Fraude.
====

Y si usted menciona el pago en el Developer GUI y consulte los mensajes del flujo del tutorial (search by " Unit of Work ID", haga clic en "Ver", haga clic en la pestaña "Mensajes") entonces verá:

write http1

Aquí puede ver que ahora también estamos enviando OlafRequest mensajes de fraude. Si usted observa los datos del mensaje (Click "Body"), debería ver que el mensaje de Solicitud contiene el completo fiToFICstmrCdtTrf(pacs. 008) y la respuesta tiene el fraudFeedback carga útil.

Conclusiones

En esta sección, hemos establecido un nuevo HTTP conexión a un servidor de fraude existente.