Fachlicher Vertrag: unverändert zu erhalten
- Servicevertrag, Transaktions- und Security-Semantik bleiben explizit.
- Remote-Ausnahmen werden stabil auf HTTP/Fachfehler abgebildet.
- Geschäftslogik bleibt im Service, nicht im Controller.
EJB-2-artige Home/Remote-Schnittstellen wird nachvollziehbar in Spring Service und REST Facade überführt. Die Akte zeigt nicht nur das Ziel, sondern die tatsächlichen Dateien, APIs, Dependencies, Codebelege, Tests, Risiken und Cutover-Schritte.
| Dimension | Legacy | Modern | Migrationskonsequenz |
|---|---|---|---|
| Programmiermodell | imperativ / ohne Framework-Annotationen | PostMapping, RequestMapping, RequestParam, RestController, Service, SpringBootApplication | Annotationen und Containerfunktionen werden nur dort eingesetzt, wo sie eine konkrete technische Verantwortung übernehmen. |
| Abhängigkeiten | 2 direkte Dependencies | 2 direkte Dependencies | 2 neu, 2 entfernt; Versionen und transitive Auswirkungen im erfolgreichen Online-Build prüfen. |
| Öffentliche API | 6 erkannte Methoden | 3 erkannte Methoden | Methoden werden nach fachlicher Rolle gemappt; reine Bootstrap- und Framework-Methoden sind kein fachlicher Vertrag. |
| Datenmodell | class OrderSessionBean, interface OrderHome, interface OrderRemote | class OrderApplication, class OrderController, class OrderService | Feldnamen, IDs, Null-Semantik, Gleichheit und Serialisierungsform werden separat regressionstestet. |
| Fehlerverhalten | Legacy-Exceptions und Rückgabewerte | explizitere Fach-/Framework-Fehlerabbildung | Fehler dürfen nicht nur technisch übersetzt werden; Status, Ursache, Retrybarkeit und Client-Vertrag müssen erhalten oder versioniert werden. |
| Tests | Bestands- und Golden-Master-Tests | Unit-, Slice-, Contract- und Integrationstests | Der Modern-Pfad wird zuerst gegen denselben fachlichen Vektor geprüft und danach um neue technische Risiken ergänzt. |
| Betrieb | Legacy-Start/Lifecycle | modernes Packaging, Health und externe Konfiguration | Startup, Lifecycle, Security Context und Remote-/Containerfehler separat testen. |
| Rollback | Legacy-Artefakt bleibt unverändert | Modern-Artefakt getrennt deploybar | Kein Rollback über Datenverlust: Schema, Nachrichten und verschlüsselte Daten müssen rückwärtslesbar oder durch Dual-Read abgesichert sein. |
transaction/security semantics and remote contract drift
service contract, web adapter and transaction tests
Die Zuordnung ist semantisch: Eine Legacy-Klasse kann in mehrere moderne Rollen zerlegt werden.
| Legacy-Rolle / Datei | Modern-Rolle / Datei | Bedeutung |
|---|---|---|
| OrderHome.java + OrderRemote.java | OrderController.java | Remote EJB Contract wird HTTP Remote Facade. |
| OrderSessionBean.java | OrderService.java | Session Bean wird containerarmer Service. |
| EJB Container Bootstrap | OrderApplication.java | Deploymentmodell wechselt zu Spring Boot. |
| Datei | Typ | Annotationen | öffentliche API | Pattern | Zeilen |
|---|---|---|---|---|---|
| OrderHome.java | interface OrderHome | — | — | — | 8 |
| OrderRemote.java | interface OrderRemote | — | — | Remote Facade | 10 |
| OrderSessionBean.java | class OrderSessionBean | — | String placeOrder(String sku, int quantity) void ejbCreate() void ejbActivate() void ejbPassivate() void ejbRemove() void setSessionContext(SessionContext context) | Session Facade | 26 |
| Datei | Typ | Annotationen | öffentliche API | Pattern | Zeilen |
|---|---|---|---|---|---|
| OrderApplication.java | class OrderApplication | SpringBootApplication | void main(String[] args) | — | 11 |
| OrderController.java | class OrderController | PostMapping, RequestMapping, RequestParam, RestController | String order(@RequestParam String sku, @RequestParam int quantity) | — | 17 |
| OrderService.java | class OrderService | Service | String placeOrder(String sku, int quantity) | Service Layer | 13 |
| Status | Dependency | Version | Scope | Prüfung |
|---|---|---|---|---|
| ENTFERNT | javax.ejb:javax.ejb-api | 3.2.2 | compile | Legacy-Laufzeit entfällt oder wird durch Plattform/BOM ersetzt. |
| ENTFERNT | org.junit.jupiter:junit-jupiter | BOM/Parent | test | Legacy-Laufzeit entfällt oder wird durch Plattform/BOM ersetzt. |
| NEU | org.springframework.boot:spring-boot-starter-test | BOM/Parent | test | Neue Laufzeit-/Testabhängigkeit; transitiv, lizenz- und security-seitig prüfen. |
| NEU | org.springframework.boot:spring-boot-starter-web | BOM/Parent | compile | Neue Laufzeit-/Testabhängigkeit; transitiv, lizenz- und security-seitig prüfen. |
Die folgenden Ausschnitte stammen direkt aus den enthaltenen Projekten. Dadurch ist sichtbar, welche Verantwortung tatsächlich verschoben wurde.
Migrationsbedeutung: Remote EJB Contract wird HTTP Remote Facade.
projects/27-ejb-services/legacy/src/main/java/at/aydin/lab/ejb/legacy/OrderHome.java
package at.aydin.lab.ejb.legacy;
import javax.ejb.*;
import java.rmi.RemoteException;
public interface OrderHome extends EJBHome {
OrderRemote create() throws CreateException, RemoteException;
}
projects/27-ejb-services/legacy/src/main/java/at/aydin/lab/ejb/legacy/OrderRemote.java
package at.aydin.lab.ejb.legacy;
import javax.ejb.EJBObject;
import java.rmi.RemoteException;
// Design Pattern: Remote Facade
// Zweck: Grobgranulare Remote-Schnittstelle reduziert verteilte Einzelaufrufe.
public interface OrderRemote extends EJBObject {
String placeOrder(String sku, int quantity) throws RemoteException;
}
projects/27-ejb-services/modern/src/main/java/at/aydin/lab/ejb/modern/OrderController.java
package at.aydin.lab.ejb.modern;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/orders")
public class OrderController {
private final OrderService service;
public OrderController(OrderService service) {
this.service = service;
}
@PostMapping
public String order(@RequestParam String sku, @RequestParam int quantity) {
return service.placeOrder(sku, quantity);
}
}
Migrationsbedeutung: Session Bean wird containerarmer Service.
projects/27-ejb-services/legacy/src/main/java/at/aydin/lab/ejb/legacy/OrderSessionBean.java
package at.aydin.lab.ejb.legacy;
import javax.ejb.*;
// Design Pattern: Session Facade
// Zweck: Bündelt fachlichen Bestellablauf in einer serverseitigen Session-Komponente.
public class OrderSessionBean implements SessionBean {
public String placeOrder(String sku, int quantity) {
return "ORDERED " + quantity + " x " + sku;
}
public void ejbCreate() {
}
public void ejbActivate() {
}
public void ejbPassivate() {
}
public void ejbRemove() {
}
public void setSessionContext(SessionContext context) {
}
}
projects/27-ejb-services/modern/src/main/java/at/aydin/lab/ejb/modern/OrderService.java
package at.aydin.lab.ejb.modern;
import org.springframework.stereotype.Service;
// Design Pattern: Service Layer
// Zweck: Fachlogik ist containerleicht, lokal testbar und nicht an RemoteObject gebunden.
@Service
public class OrderService {
public String placeOrder(String sku, int quantity) {
if (quantity <= 0) throw new IllegalArgumentException("quantity");
return "ORDERED " + quantity + " x " + sku;
}
}
--- OrderSessionBean.java
+++ OrderService.java
@@ -1,26 +1,13 @@
-package at.aydin.lab.ejb.legacy;
+package at.aydin.lab.ejb.modern;
-import javax.ejb.*;
+import org.springframework.stereotype.Service;
-// Design Pattern: Session Facade
-// Zweck: Bündelt fachlichen Bestellablauf in einer serverseitigen Session-Komponente.
-public class OrderSessionBean implements SessionBean {
+// Design Pattern: Service Layer
+// Zweck: Fachlogik ist containerleicht, lokal testbar und nicht an RemoteObject gebunden.
+@Service
+public class OrderService {
public String placeOrder(String sku, int quantity) {
+ if (quantity <= 0) throw new IllegalArgumentException("quantity");
return "ORDERED " + quantity + " x " + sku;
}
-
- public void ejbCreate() {
- }
-
- public void ejbActivate() {
- }
-
- public void ejbPassivate() {
- }
-
- public void ejbRemove() {
- }
-
- public void setSessionContext(SessionContext context) {
- }
}
Migrationsbedeutung: Deploymentmodell wechselt zu Spring Boot.
projects/27-ejb-services/legacy/src/main/java/at/aydin/lab/ejb/legacy/OrderSessionBean.java
package at.aydin.lab.ejb.legacy;
import javax.ejb.*;
// Design Pattern: Session Facade
// Zweck: Bündelt fachlichen Bestellablauf in einer serverseitigen Session-Komponente.
public class OrderSessionBean implements SessionBean {
public String placeOrder(String sku, int quantity) {
return "ORDERED " + quantity + " x " + sku;
}
public void ejbCreate() {
}
public void ejbActivate() {
}
public void ejbPassivate() {
}
public void ejbRemove() {
}
public void setSessionContext(SessionContext context) {
}
}
projects/27-ejb-services/modern/src/main/java/at/aydin/lab/ejb/modern/OrderApplication.java
package at.aydin.lab.ejb.modern;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
--- OrderSessionBean.java
+++ OrderApplication.java
@@ -1,26 +1,11 @@
-package at.aydin.lab.ejb.legacy;
+package at.aydin.lab.ejb.modern;
-import javax.ejb.*;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
-// Design Pattern: Session Facade
-// Zweck: Bündelt fachlichen Bestellablauf in einer serverseitigen Session-Komponente.
-public class OrderSessionBean implements SessionBean {
- public String placeOrder(String sku, int quantity) {
- return "ORDERED " + quantity + " x " + sku;
- }
-
- public void ejbCreate() {
- }
-
- public void ejbActivate() {
- }
-
- public void ejbPassivate() {
- }
-
- public void ejbRemove() {
- }
-
- public void setSessionContext(SessionContext context) {
+@SpringBootApplication
+public class OrderApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(OrderApplication.class, args);
}
}
| ID | Ebene | Prüfung | erforderlicher Nachweis |
|---|---|---|---|
| 27-EJB-SERVICES-A01 | Integration/Contract | Fachresultate stimmen zwischen EJB und Service überein. | Automatisierter Test und CI-Protokoll |
| 27-EJB-SERVICES-A02 | Integration/Contract | Transaktionsrollback entspricht bisheriger Semantik. | Automatisierter Test und CI-Protokoll |
| 27-EJB-SERVICES-A03 | Integration/Contract | Security-Entscheidungen sind mindestens gleich streng. | Automatisierter Test und CI-Protokoll |
| 27-EJB-SERVICES-A04 | Integration/Contract | HTTP-Fehlerabbildung ist dokumentiert. | Automatisierter Test und CI-Protokoll |
| 27-EJB-SERVICES-A05 | Integration/Contract | Keine EJB-API in der Fachlogik. | Automatisierter Test und CI-Protokoll |
| 27-EJB-SERVICES-T01 | Unit | Fachlogik ohne Container oder externen Dienst testen. | Unit-Test |
| 27-EJB-SERVICES-T02 | Regression | Legacy- und Modern-Ergebnis für denselben Golden-Master-Vektor vergleichen. | Vergleichsreport |
| 27-EJB-SERVICES-T03 | Negative | Fehlerhafte, leere und grenzwertige Eingaben prüfen. | Negativtest |
| 27-EJB-SERVICES-T04 | Operations | Start, Health, Shutdown und Konfigurationsfehler prüfen. | Deployment-/Startprotokoll |
| 27-EJB-SERVICES-T05 | Lifecycle | Container-/Service-Lifecycle, Startup-Fehler und Recovery prüfen. | Runtime-Test |
| 27-EJB-SERVICES-F01 | Fokus | service contract, web adapter and transaction tests | Modulspezifischer Testreport |
| Risiko | Auswirkung | Gegenmaßnahme | Gate |
|---|---|---|---|
| transaction/security semantics and remote contract drift | NIEDRIG | service contract, web adapter and transaction tests | vor Cutover |
| Neue Framework-/Library-Laufzeitabhängigkeiten | MITTEL | SBOM, Lizenz-, CVE- und transitive Dependency-Prüfung im Online-Build | vor Release |
| Legacy-Verhalten war implizit an entfernte Library gekoppelt | MITTEL | Contract-/Golden-Master-Tests und gezielte Fehlerpfade | vor Abschaltung |
Keine zusätzlichen Ressourcen.
REST Facade kann intern auf den EJB-Adapter delegieren; externe Umschaltung erfolgt unabhängig von der schrittweisen Fachlogikmigration.