Nachrichten, Schnittstellen, Transformation, Routing, Entkopplung und Partnerkommunikation.

dp049: Message Channel im Enterprise-Kontext sauber einsetzen
Warum wichtig: Das Muster hilft, fachliche Customer-Logik von technischer Kopplung zu trennen und Aenderungen kontrolliert einzubauen.
Wann einsetzen: Einsetzen, wenn Customer-Varianten, Integrationsgrenzen oder wiederkehrende Entscheidungen nicht mehr sicher durch einfache Methoden ausdrueckbar sind.
Typischer Fehler: Message Channel wird als Selbstzweck eingebaut, waehrend die eigentliche Customer-Regel weiterhin in Controllern, Jobs oder Clients verstreut bleibt.
Enterprise-Einordnung: Relevant fuer Legacy-Modernisierung, modulare Maven-Projekte, Spring/Jakarta Services, OpenShift-Betrieb und testbare Fachgrenzen.
Ausgangspunkt-Code
public class CustomerProcessor {
public void process(CustomerRequest request) {
if (request.type().equals("STANDARD")) {
validateStandard(request);
sendToCoreSystem(request);
} else if (request.type().equals("PARTNER")) {
validatePartner(request);
sendToPartnerGateway(request);
} else {
throw new IllegalArgumentException("Unknown customer type: " + request.type());
}
}
private void validateStandard(CustomerRequest request) { /* konkrete Pflichtfeldpruefung */ }
private void validatePartner(CustomerRequest request) { /* konkrete Partner-Regel */ }
private void sendToCoreSystem(CustomerRequest request) { /* REST-Aufruf an Core */ }
private void sendToPartnerGateway(CustomerRequest request) { /* JMS/REST an Partner */ }
}
record CustomerRequest(String id, String type, java.math.BigDecimal amount) { }
Ziel-Code
// Pattern: Message Channel - trennt interne Domain von externer Schnittstelle.
public final class MessageChannelCustomerAdapter {
private final ExternalCustomerClient client;
public MessageChannelCustomerAdapter(ExternalCustomerClient client) { this.client = client; }
public CustomerResult submit(CustomerRequest request) {
ExternalCustomerPayload payload = new ExternalCustomerPayload(request.id(), request.amount().toPlainString());
ExternalCustomerResponse response = client.send(payload);
return new CustomerResult(response.reference(), response.accepted());
}
}
interface ExternalCustomerClient { ExternalCustomerResponse send(ExternalCustomerPayload payload); }
record ExternalCustomerPayload(String id, String amount) { }
record ExternalCustomerResponse(String reference, boolean accepted) { }
record CustomerResult(String reference, boolean accepted) { }
record CustomerRequest(String id, String type, java.math.BigDecimal amount) { }
dp050: Message Router im Enterprise-Kontext sauber einsetzen
Warum wichtig: Das Muster hilft, fachliche Payment-Logik von technischer Kopplung zu trennen und Aenderungen kontrolliert einzubauen.
Wann einsetzen: Einsetzen, wenn Payment-Varianten, Integrationsgrenzen oder wiederkehrende Entscheidungen nicht mehr sicher durch einfache Methoden ausdrueckbar sind.
Typischer Fehler: Message Router wird als Selbstzweck eingebaut, waehrend die eigentliche Payment-Regel weiterhin in Controllern, Jobs oder Clients verstreut bleibt.
Enterprise-Einordnung: Relevant fuer Legacy-Modernisierung, modulare Maven-Projekte, Spring/Jakarta Services, OpenShift-Betrieb und testbare Fachgrenzen.
Ausgangspunkt-Code
public class PaymentProcessor {
public void process(PaymentRequest request) {
if (request.type().equals("STANDARD")) {
validateStandard(request);
sendToCoreSystem(request);
} else if (request.type().equals("PARTNER")) {
validatePartner(request);
sendToPartnerGateway(request);
} else {
throw new IllegalArgumentException("Unknown payment type: " + request.type());
}
}
private void validateStandard(PaymentRequest request) { /* konkrete Pflichtfeldpruefung */ }
private void validatePartner(PaymentRequest request) { /* konkrete Partner-Regel */ }
private void sendToCoreSystem(PaymentRequest request) { /* REST-Aufruf an Core */ }
private void sendToPartnerGateway(PaymentRequest request) { /* JMS/REST an Partner */ }
}
record PaymentRequest(String id, String type, java.math.BigDecimal amount) { }
Ziel-Code
// Pattern: Message Router - trennt interne Domain von externer Schnittstelle.
public final class MessageRouterPaymentAdapter {
private final ExternalPaymentClient client;
public MessageRouterPaymentAdapter(ExternalPaymentClient client) { this.client = client; }
public PaymentResult submit(PaymentRequest request) {
ExternalPaymentPayload payload = new ExternalPaymentPayload(request.id(), request.amount().toPlainString());
ExternalPaymentResponse response = client.send(payload);
return new PaymentResult(response.reference(), response.accepted());
}
}
interface ExternalPaymentClient { ExternalPaymentResponse send(ExternalPaymentPayload payload); }
record ExternalPaymentPayload(String id, String amount) { }
record ExternalPaymentResponse(String reference, boolean accepted) { }
record PaymentResult(String reference, boolean accepted) { }
record PaymentRequest(String id, String type, java.math.BigDecimal amount) { }
dp051: Content-Based Router im Enterprise-Kontext sauber einsetzen
Warum wichtig: Das Muster hilft, fachliche Partner-Logik von technischer Kopplung zu trennen und Aenderungen kontrolliert einzubauen.
Wann einsetzen: Einsetzen, wenn Partner-Varianten, Integrationsgrenzen oder wiederkehrende Entscheidungen nicht mehr sicher durch einfache Methoden ausdrueckbar sind.
Typischer Fehler: Content-Based Router wird als Selbstzweck eingebaut, waehrend die eigentliche Partner-Regel weiterhin in Controllern, Jobs oder Clients verstreut bleibt.
Enterprise-Einordnung: Relevant fuer Legacy-Modernisierung, modulare Maven-Projekte, Spring/Jakarta Services, OpenShift-Betrieb und testbare Fachgrenzen.
Ausgangspunkt-Code
public class PartnerProcessor {
public void process(PartnerRequest request) {
if (request.type().equals("STANDARD")) {
validateStandard(request);
sendToCoreSystem(request);
} else if (request.type().equals("PARTNER")) {
validatePartner(request);
sendToPartnerGateway(request);
} else {
throw new IllegalArgumentException("Unknown partner type: " + request.type());
}
}
private void validateStandard(PartnerRequest request) { /* konkrete Pflichtfeldpruefung */ }
private void validatePartner(PartnerRequest request) { /* konkrete Partner-Regel */ }
private void sendToCoreSystem(PartnerRequest request) { /* REST-Aufruf an Core */ }
private void sendToPartnerGateway(PartnerRequest request) { /* JMS/REST an Partner */ }
}
record PartnerRequest(String id, String type, java.math.BigDecimal amount) { }
Ziel-Code
// Pattern: Content-Based Router - trennt interne Domain von externer Schnittstelle.
public final class ContentBasedRouterPartnerAdapter {
private final ExternalPartnerClient client;
public ContentBasedRouterPartnerAdapter(ExternalPartnerClient client) { this.client = client; }
public PartnerResult submit(PartnerRequest request) {
ExternalPartnerPayload payload = new ExternalPartnerPayload(request.id(), request.amount().toPlainString());
ExternalPartnerResponse response = client.send(payload);
return new PartnerResult(response.reference(), response.accepted());
}
}
interface ExternalPartnerClient { ExternalPartnerResponse send(ExternalPartnerPayload payload); }
record ExternalPartnerPayload(String id, String amount) { }
record ExternalPartnerResponse(String reference, boolean accepted) { }
record PartnerResult(String reference, boolean accepted) { }
record PartnerRequest(String id, String type, java.math.BigDecimal amount) { }
dp052: Message Translator im Enterprise-Kontext sauber einsetzen
Warum wichtig: Das Muster hilft, fachliche Account-Logik von technischer Kopplung zu trennen und Aenderungen kontrolliert einzubauen.
Wann einsetzen: Einsetzen, wenn Account-Varianten, Integrationsgrenzen oder wiederkehrende Entscheidungen nicht mehr sicher durch einfache Methoden ausdrueckbar sind.
Typischer Fehler: Message Translator wird als Selbstzweck eingebaut, waehrend die eigentliche Account-Regel weiterhin in Controllern, Jobs oder Clients verstreut bleibt.
Enterprise-Einordnung: Relevant fuer Legacy-Modernisierung, modulare Maven-Projekte, Spring/Jakarta Services, OpenShift-Betrieb und testbare Fachgrenzen.
Ausgangspunkt-Code
public class AccountProcessor {
public void process(AccountRequest request) {
if (request.type().equals("STANDARD")) {
validateStandard(request);
sendToCoreSystem(request);
} else if (request.type().equals("PARTNER")) {
validatePartner(request);
sendToPartnerGateway(request);
} else {
throw new IllegalArgumentException("Unknown account type: " + request.type());
}
}
private void validateStandard(AccountRequest request) { /* konkrete Pflichtfeldpruefung */ }
private void validatePartner(AccountRequest request) { /* konkrete Partner-Regel */ }
private void sendToCoreSystem(AccountRequest request) { /* REST-Aufruf an Core */ }
private void sendToPartnerGateway(AccountRequest request) { /* JMS/REST an Partner */ }
}
record AccountRequest(String id, String type, java.math.BigDecimal amount) { }
Ziel-Code
// Pattern: Message Translator - trennt interne Domain von externer Schnittstelle.
public final class MessageTranslatorAccountAdapter {
private final ExternalAccountClient client;
public MessageTranslatorAccountAdapter(ExternalAccountClient client) { this.client = client; }
public AccountResult submit(AccountRequest request) {
ExternalAccountPayload payload = new ExternalAccountPayload(request.id(), request.amount().toPlainString());
ExternalAccountResponse response = client.send(payload);
return new AccountResult(response.reference(), response.accepted());
}
}
interface ExternalAccountClient { ExternalAccountResponse send(ExternalAccountPayload payload); }
record ExternalAccountPayload(String id, String amount) { }
record ExternalAccountResponse(String reference, boolean accepted) { }
record AccountResult(String reference, boolean accepted) { }
record AccountRequest(String id, String type, java.math.BigDecimal amount) { }
dp053: Envelope Wrapper im Enterprise-Kontext sauber einsetzen
Warum wichtig: Das Muster hilft, fachliche Product-Logik von technischer Kopplung zu trennen und Aenderungen kontrolliert einzubauen.
Wann einsetzen: Einsetzen, wenn Product-Varianten, Integrationsgrenzen oder wiederkehrende Entscheidungen nicht mehr sicher durch einfache Methoden ausdrueckbar sind.
Typischer Fehler: Envelope Wrapper wird als Selbstzweck eingebaut, waehrend die eigentliche Product-Regel weiterhin in Controllern, Jobs oder Clients verstreut bleibt.
Enterprise-Einordnung: Relevant fuer Legacy-Modernisierung, modulare Maven-Projekte, Spring/Jakarta Services, OpenShift-Betrieb und testbare Fachgrenzen.
Ausgangspunkt-Code
public class ProductProcessor {
public void process(ProductRequest request) {
if (request.type().equals("STANDARD")) {
validateStandard(request);
sendToCoreSystem(request);
} else if (request.type().equals("PARTNER")) {
validatePartner(request);
sendToPartnerGateway(request);
} else {
throw new IllegalArgumentException("Unknown product type: " + request.type());
}
}
private void validateStandard(ProductRequest request) { /* konkrete Pflichtfeldpruefung */ }
private void validatePartner(ProductRequest request) { /* konkrete Partner-Regel */ }
private void sendToCoreSystem(ProductRequest request) { /* REST-Aufruf an Core */ }
private void sendToPartnerGateway(ProductRequest request) { /* JMS/REST an Partner */ }
}
record ProductRequest(String id, String type, java.math.BigDecimal amount) { }
Ziel-Code
// Pattern: Envelope Wrapper - trennt interne Domain von externer Schnittstelle.
public final class EnvelopeWrapperProductAdapter {
private final ExternalProductClient client;
public EnvelopeWrapperProductAdapter(ExternalProductClient client) { this.client = client; }
public ProductResult submit(ProductRequest request) {
ExternalProductPayload payload = new ExternalProductPayload(request.id(), request.amount().toPlainString());
ExternalProductResponse response = client.send(payload);
return new ProductResult(response.reference(), response.accepted());
}
}
interface ExternalProductClient { ExternalProductResponse send(ExternalProductPayload payload); }
record ExternalProductPayload(String id, String amount) { }
record ExternalProductResponse(String reference, boolean accepted) { }
record ProductResult(String reference, boolean accepted) { }
record ProductRequest(String id, String type, java.math.BigDecimal amount) { }
dp054: Claim Check im Enterprise-Kontext sauber einsetzen
Warum wichtig: Das Muster hilft, fachliche Order-Logik von technischer Kopplung zu trennen und Aenderungen kontrolliert einzubauen.
Wann einsetzen: Einsetzen, wenn Order-Varianten, Integrationsgrenzen oder wiederkehrende Entscheidungen nicht mehr sicher durch einfache Methoden ausdrueckbar sind.
Typischer Fehler: Claim Check wird als Selbstzweck eingebaut, waehrend die eigentliche Order-Regel weiterhin in Controllern, Jobs oder Clients verstreut bleibt.
Enterprise-Einordnung: Relevant fuer Legacy-Modernisierung, modulare Maven-Projekte, Spring/Jakarta Services, OpenShift-Betrieb und testbare Fachgrenzen.
Ausgangspunkt-Code
public class OrderProcessor {
public void process(OrderRequest request) {
if (request.type().equals("STANDARD")) {
validateStandard(request);
sendToCoreSystem(request);
} else if (request.type().equals("PARTNER")) {
validatePartner(request);
sendToPartnerGateway(request);
} else {
throw new IllegalArgumentException("Unknown order type: " + request.type());
}
}
private void validateStandard(OrderRequest request) { /* konkrete Pflichtfeldpruefung */ }
private void validatePartner(OrderRequest request) { /* konkrete Partner-Regel */ }
private void sendToCoreSystem(OrderRequest request) { /* REST-Aufruf an Core */ }
private void sendToPartnerGateway(OrderRequest request) { /* JMS/REST an Partner */ }
}
record OrderRequest(String id, String type, java.math.BigDecimal amount) { }
Ziel-Code
// Pattern: Claim Check - trennt interne Domain von externer Schnittstelle.
public final class ClaimCheckOrderAdapter {
private final ExternalOrderClient client;
public ClaimCheckOrderAdapter(ExternalOrderClient client) { this.client = client; }
public OrderResult submit(OrderRequest request) {
ExternalOrderPayload payload = new ExternalOrderPayload(request.id(), request.amount().toPlainString());
ExternalOrderResponse response = client.send(payload);
return new OrderResult(response.reference(), response.accepted());
}
}
interface ExternalOrderClient { ExternalOrderResponse send(ExternalOrderPayload payload); }
record ExternalOrderPayload(String id, String amount) { }
record ExternalOrderResponse(String reference, boolean accepted) { }
record OrderResult(String reference, boolean accepted) { }
record OrderRequest(String id, String type, java.math.BigDecimal amount) { }
dp055: Idempotent Receiver im Enterprise-Kontext sauber einsetzen
Warum wichtig: Das Muster hilft, fachliche Customer-Logik von technischer Kopplung zu trennen und Aenderungen kontrolliert einzubauen.
Wann einsetzen: Einsetzen, wenn Customer-Varianten, Integrationsgrenzen oder wiederkehrende Entscheidungen nicht mehr sicher durch einfache Methoden ausdrueckbar sind.
Typischer Fehler: Idempotent Receiver wird als Selbstzweck eingebaut, waehrend die eigentliche Customer-Regel weiterhin in Controllern, Jobs oder Clients verstreut bleibt.
Enterprise-Einordnung: Relevant fuer Legacy-Modernisierung, modulare Maven-Projekte, Spring/Jakarta Services, OpenShift-Betrieb und testbare Fachgrenzen.
Ausgangspunkt-Code
public class CustomerProcessor {
public void process(CustomerRequest request) {
if (request.type().equals("STANDARD")) {
validateStandard(request);
sendToCoreSystem(request);
} else if (request.type().equals("PARTNER")) {
validatePartner(request);
sendToPartnerGateway(request);
} else {
throw new IllegalArgumentException("Unknown customer type: " + request.type());
}
}
private void validateStandard(CustomerRequest request) { /* konkrete Pflichtfeldpruefung */ }
private void validatePartner(CustomerRequest request) { /* konkrete Partner-Regel */ }
private void sendToCoreSystem(CustomerRequest request) { /* REST-Aufruf an Core */ }
private void sendToPartnerGateway(CustomerRequest request) { /* JMS/REST an Partner */ }
}
record CustomerRequest(String id, String type, java.math.BigDecimal amount) { }
Ziel-Code
// Pattern: Idempotent Receiver - trennt interne Domain von externer Schnittstelle.
public final class IdempotentReceiverCustomerAdapter {
private final ExternalCustomerClient client;
public IdempotentReceiverCustomerAdapter(ExternalCustomerClient client) { this.client = client; }
public CustomerResult submit(CustomerRequest request) {
ExternalCustomerPayload payload = new ExternalCustomerPayload(request.id(), request.amount().toPlainString());
ExternalCustomerResponse response = client.send(payload);
return new CustomerResult(response.reference(), response.accepted());
}
}
interface ExternalCustomerClient { ExternalCustomerResponse send(ExternalCustomerPayload payload); }
record ExternalCustomerPayload(String id, String amount) { }
record ExternalCustomerResponse(String reference, boolean accepted) { }
record CustomerResult(String reference, boolean accepted) { }
record CustomerRequest(String id, String type, java.math.BigDecimal amount) { }
dp056: Polling Consumer im Enterprise-Kontext sauber einsetzen
Warum wichtig: Das Muster hilft, fachliche Payment-Logik von technischer Kopplung zu trennen und Aenderungen kontrolliert einzubauen.
Wann einsetzen: Einsetzen, wenn Payment-Varianten, Integrationsgrenzen oder wiederkehrende Entscheidungen nicht mehr sicher durch einfache Methoden ausdrueckbar sind.
Typischer Fehler: Polling Consumer wird als Selbstzweck eingebaut, waehrend die eigentliche Payment-Regel weiterhin in Controllern, Jobs oder Clients verstreut bleibt.
Enterprise-Einordnung: Relevant fuer Legacy-Modernisierung, modulare Maven-Projekte, Spring/Jakarta Services, OpenShift-Betrieb und testbare Fachgrenzen.
Ausgangspunkt-Code
public class PaymentProcessor {
public void process(PaymentRequest request) {
if (request.type().equals("STANDARD")) {
validateStandard(request);
sendToCoreSystem(request);
} else if (request.type().equals("PARTNER")) {
validatePartner(request);
sendToPartnerGateway(request);
} else {
throw new IllegalArgumentException("Unknown payment type: " + request.type());
}
}
private void validateStandard(PaymentRequest request) { /* konkrete Pflichtfeldpruefung */ }
private void validatePartner(PaymentRequest request) { /* konkrete Partner-Regel */ }
private void sendToCoreSystem(PaymentRequest request) { /* REST-Aufruf an Core */ }
private void sendToPartnerGateway(PaymentRequest request) { /* JMS/REST an Partner */ }
}
record PaymentRequest(String id, String type, java.math.BigDecimal amount) { }
Ziel-Code
// Pattern: Polling Consumer - trennt interne Domain von externer Schnittstelle.
public final class PollingConsumerPaymentAdapter {
private final ExternalPaymentClient client;
public PollingConsumerPaymentAdapter(ExternalPaymentClient client) { this.client = client; }
public PaymentResult submit(PaymentRequest request) {
ExternalPaymentPayload payload = new ExternalPaymentPayload(request.id(), request.amount().toPlainString());
ExternalPaymentResponse response = client.send(payload);
return new PaymentResult(response.reference(), response.accepted());
}
}
interface ExternalPaymentClient { ExternalPaymentResponse send(ExternalPaymentPayload payload); }
record ExternalPaymentPayload(String id, String amount) { }
record ExternalPaymentResponse(String reference, boolean accepted) { }
record PaymentResult(String reference, boolean accepted) { }
record PaymentRequest(String id, String type, java.math.BigDecimal amount) { }
dp057: Event-Driven Consumer im Enterprise-Kontext sauber einsetzen
Warum wichtig: Das Muster hilft, fachliche Partner-Logik von technischer Kopplung zu trennen und Aenderungen kontrolliert einzubauen.
Wann einsetzen: Einsetzen, wenn Partner-Varianten, Integrationsgrenzen oder wiederkehrende Entscheidungen nicht mehr sicher durch einfache Methoden ausdrueckbar sind.
Typischer Fehler: Event-Driven Consumer wird als Selbstzweck eingebaut, waehrend die eigentliche Partner-Regel weiterhin in Controllern, Jobs oder Clients verstreut bleibt.
Enterprise-Einordnung: Relevant fuer Legacy-Modernisierung, modulare Maven-Projekte, Spring/Jakarta Services, OpenShift-Betrieb und testbare Fachgrenzen.
Ausgangspunkt-Code
public class PartnerProcessor {
public void process(PartnerRequest request) {
if (request.type().equals("STANDARD")) {
validateStandard(request);
sendToCoreSystem(request);
} else if (request.type().equals("PARTNER")) {
validatePartner(request);
sendToPartnerGateway(request);
} else {
throw new IllegalArgumentException("Unknown partner type: " + request.type());
}
}
private void validateStandard(PartnerRequest request) { /* konkrete Pflichtfeldpruefung */ }
private void validatePartner(PartnerRequest request) { /* konkrete Partner-Regel */ }
private void sendToCoreSystem(PartnerRequest request) { /* REST-Aufruf an Core */ }
private void sendToPartnerGateway(PartnerRequest request) { /* JMS/REST an Partner */ }
}
record PartnerRequest(String id, String type, java.math.BigDecimal amount) { }
Ziel-Code
// Pattern: Event-Driven Consumer - trennt interne Domain von externer Schnittstelle.
public final class EventDrivenConsumerPartnerAdapter {
private final ExternalPartnerClient client;
public EventDrivenConsumerPartnerAdapter(ExternalPartnerClient client) { this.client = client; }
public PartnerResult submit(PartnerRequest request) {
ExternalPartnerPayload payload = new ExternalPartnerPayload(request.id(), request.amount().toPlainString());
ExternalPartnerResponse response = client.send(payload);
return new PartnerResult(response.reference(), response.accepted());
}
}
interface ExternalPartnerClient { ExternalPartnerResponse send(ExternalPartnerPayload payload); }
record ExternalPartnerPayload(String id, String amount) { }
record ExternalPartnerResponse(String reference, boolean accepted) { }
record PartnerResult(String reference, boolean accepted) { }
record PartnerRequest(String id, String type, java.math.BigDecimal amount) { }
dp058: Dead Letter Channel im Enterprise-Kontext sauber einsetzen
Warum wichtig: Das Muster hilft, fachliche Account-Logik von technischer Kopplung zu trennen und Aenderungen kontrolliert einzubauen.
Wann einsetzen: Einsetzen, wenn Account-Varianten, Integrationsgrenzen oder wiederkehrende Entscheidungen nicht mehr sicher durch einfache Methoden ausdrueckbar sind.
Typischer Fehler: Dead Letter Channel wird als Selbstzweck eingebaut, waehrend die eigentliche Account-Regel weiterhin in Controllern, Jobs oder Clients verstreut bleibt.
Enterprise-Einordnung: Relevant fuer Legacy-Modernisierung, modulare Maven-Projekte, Spring/Jakarta Services, OpenShift-Betrieb und testbare Fachgrenzen.
Ausgangspunkt-Code
public class AccountProcessor {
public void process(AccountRequest request) {
if (request.type().equals("STANDARD")) {
validateStandard(request);
sendToCoreSystem(request);
} else if (request.type().equals("PARTNER")) {
validatePartner(request);
sendToPartnerGateway(request);
} else {
throw new IllegalArgumentException("Unknown account type: " + request.type());
}
}
private void validateStandard(AccountRequest request) { /* konkrete Pflichtfeldpruefung */ }
private void validatePartner(AccountRequest request) { /* konkrete Partner-Regel */ }
private void sendToCoreSystem(AccountRequest request) { /* REST-Aufruf an Core */ }
private void sendToPartnerGateway(AccountRequest request) { /* JMS/REST an Partner */ }
}
record AccountRequest(String id, String type, java.math.BigDecimal amount) { }
Ziel-Code
// Pattern: Dead Letter Channel - trennt interne Domain von externer Schnittstelle.
public final class DeadLetterChannelAccountAdapter {
private final ExternalAccountClient client;
public DeadLetterChannelAccountAdapter(ExternalAccountClient client) { this.client = client; }
public AccountResult submit(AccountRequest request) {
ExternalAccountPayload payload = new ExternalAccountPayload(request.id(), request.amount().toPlainString());
ExternalAccountResponse response = client.send(payload);
return new AccountResult(response.reference(), response.accepted());
}
}
interface ExternalAccountClient { ExternalAccountResponse send(ExternalAccountPayload payload); }
record ExternalAccountPayload(String id, String amount) { }
record ExternalAccountResponse(String reference, boolean accepted) { }
record AccountResult(String reference, boolean accepted) { }
record AccountRequest(String id, String type, java.math.BigDecimal amount) { }
dp059: Outbox im Enterprise-Kontext sauber einsetzen
Warum wichtig: Das Muster hilft, fachliche Product-Logik von technischer Kopplung zu trennen und Aenderungen kontrolliert einzubauen.
Wann einsetzen: Einsetzen, wenn Product-Varianten, Integrationsgrenzen oder wiederkehrende Entscheidungen nicht mehr sicher durch einfache Methoden ausdrueckbar sind.
Typischer Fehler: Outbox wird als Selbstzweck eingebaut, waehrend die eigentliche Product-Regel weiterhin in Controllern, Jobs oder Clients verstreut bleibt.
Enterprise-Einordnung: Relevant fuer Legacy-Modernisierung, modulare Maven-Projekte, Spring/Jakarta Services, OpenShift-Betrieb und testbare Fachgrenzen.
Ausgangspunkt-Code
public class ProductProcessor {
public void process(ProductRequest request) {
if (request.type().equals("STANDARD")) {
validateStandard(request);
sendToCoreSystem(request);
} else if (request.type().equals("PARTNER")) {
validatePartner(request);
sendToPartnerGateway(request);
} else {
throw new IllegalArgumentException("Unknown product type: " + request.type());
}
}
private void validateStandard(ProductRequest request) { /* konkrete Pflichtfeldpruefung */ }
private void validatePartner(ProductRequest request) { /* konkrete Partner-Regel */ }
private void sendToCoreSystem(ProductRequest request) { /* REST-Aufruf an Core */ }
private void sendToPartnerGateway(ProductRequest request) { /* JMS/REST an Partner */ }
}
record ProductRequest(String id, String type, java.math.BigDecimal amount) { }
Ziel-Code
// Pattern: Outbox - trennt interne Domain von externer Schnittstelle.
public final class OutboxProductAdapter {
private final ExternalProductClient client;
public OutboxProductAdapter(ExternalProductClient client) { this.client = client; }
public ProductResult submit(ProductRequest request) {
ExternalProductPayload payload = new ExternalProductPayload(request.id(), request.amount().toPlainString());
ExternalProductResponse response = client.send(payload);
return new ProductResult(response.reference(), response.accepted());
}
}
interface ExternalProductClient { ExternalProductResponse send(ExternalProductPayload payload); }
record ExternalProductPayload(String id, String amount) { }
record ExternalProductResponse(String reference, boolean accepted) { }
record ProductResult(String reference, boolean accepted) { }
record ProductRequest(String id, String type, java.math.BigDecimal amount) { }
dp060: Saga im Enterprise-Kontext sauber einsetzen
Warum wichtig: Das Muster hilft, fachliche Order-Logik von technischer Kopplung zu trennen und Aenderungen kontrolliert einzubauen.
Wann einsetzen: Einsetzen, wenn Order-Varianten, Integrationsgrenzen oder wiederkehrende Entscheidungen nicht mehr sicher durch einfache Methoden ausdrueckbar sind.
Typischer Fehler: Saga wird als Selbstzweck eingebaut, waehrend die eigentliche Order-Regel weiterhin in Controllern, Jobs oder Clients verstreut bleibt.
Enterprise-Einordnung: Relevant fuer Legacy-Modernisierung, modulare Maven-Projekte, Spring/Jakarta Services, OpenShift-Betrieb und testbare Fachgrenzen.
Ausgangspunkt-Code
public class OrderProcessor {
public void process(OrderRequest request) {
if (request.type().equals("STANDARD")) {
validateStandard(request);
sendToCoreSystem(request);
} else if (request.type().equals("PARTNER")) {
validatePartner(request);
sendToPartnerGateway(request);
} else {
throw new IllegalArgumentException("Unknown order type: " + request.type());
}
}
private void validateStandard(OrderRequest request) { /* konkrete Pflichtfeldpruefung */ }
private void validatePartner(OrderRequest request) { /* konkrete Partner-Regel */ }
private void sendToCoreSystem(OrderRequest request) { /* REST-Aufruf an Core */ }
private void sendToPartnerGateway(OrderRequest request) { /* JMS/REST an Partner */ }
}
record OrderRequest(String id, String type, java.math.BigDecimal amount) { }
Ziel-Code
// Pattern: Saga - trennt interne Domain von externer Schnittstelle.
public final class SagaOrderAdapter {
private final ExternalOrderClient client;
public SagaOrderAdapter(ExternalOrderClient client) { this.client = client; }
public OrderResult submit(OrderRequest request) {
ExternalOrderPayload payload = new ExternalOrderPayload(request.id(), request.amount().toPlainString());
ExternalOrderResponse response = client.send(payload);
return new OrderResult(response.reference(), response.accepted());
}
}
interface ExternalOrderClient { ExternalOrderResponse send(ExternalOrderPayload payload); }
record ExternalOrderPayload(String id, String amount) { }
record ExternalOrderResponse(String reference, boolean accepted) { }
record OrderResult(String reference, boolean accepted) { }
record OrderRequest(String id, String type, java.math.BigDecimal amount) { }