@WebServiceBeispiel: BillingServiceEndpoint in novaris-billing-soap.
@WebService(endpointInterface = "com.novaris.legacy.common.billing.contract.BillingServicePort",
targetNamespace = "http://billing.novaris.com/soap",
serviceName = "BillingService",
portName = "BillingServicePort")
public class BillingServiceEndpoint implements BillingServicePort {
@Override
public String registerPolicy(String policyNumber, long annualPremiumCents)
throws BillingRegistrationFault { ... }
}
endpointInterface verweist auf das SEI - alle Web-Service-relevanten Metadaten
(Operationsnamen, Parameter-Namen, Namespace, Fault-Zuordnung) kommen von dort; die
Implementierungsklasse selbst traegt inhaltlich nur die Fachlogik. Diese Trennung
(Interface = Vertrag, Implementierung = Verhalten) ist derselbe Gedanke wie bei
PolicyManagementLocal/PolicyManagementBean in novaris-policy-core - nur hier fuer
einen SOAP- statt einen EJB-Vertrag.
Wie wird das in einer echten WebSphere-Umgebung deployt? Ueber den JAX-WS-
Servlet-Transport - der Anwendungsserver registriert automatisch einen HTTP-Endpunkt fuer
die annotierte Klasse (aehnlich wie fuer ein Servlet), sobald sie Teil eines deployten
Moduls ist. In dieser Ausbaustufe (vor Phase 4, EAR-Packaging) wird der Endpoint stattdessen
in Tests ueber die eingebaute JAX-WS-RI-Mini-HTTP-Laufzeit
(javax.xml.ws.Endpoint.publish(...)) veroeffentlicht - funktional dasselbe Prinzip
("ein Java-Objekt wird unter einer URL als SOAP-Endpunkt erreichbar"), nur ohne vollen
Container.
@WebServiceRefBeispiel: BillingIntegrationBean in novaris-policy-core.
@WebServiceRef(wsdlLocation = "wsdl/BillingService.wsdl")
BillingServicePort billingPort;
@WebServiceRef ist das Gegenstueck zu @EJB/@Resource/@PersistenceContext: eine
deklarative Injection-Annotation, mit der der Container zur Deployzeit einen fertigen
SOAP-Client-Proxy bereitstellt. Der Container liest die referenzierte WSDL, findet das
(hier: einzige) <service>/<port>-Paar und generiert daraus eine Instanz von
BillingServicePort, die intern alle SOAP-Details (XML-Marshalling, HTTP-Transport,
Fault-Deserialisierung) kapselt - der Anwendungscode ruft einfach eine Java-Methode auf.
Ohne Container - der manuelle, dynamische Weg: Ausserhalb eines Containers (z.B. in
Tests) uebernimmt niemand die @WebServiceRef-Injection. Der aequivalente manuelle Weg,
den BillingServiceEndpointTest und BillingIntegrationBeanRealEndpointTest verwenden:
URL wsdlUrl = new URL(endpointAddress + "?wsdl");
Service service = Service.create(wsdlUrl, BillingServiceLocations.SERVICE_QNAME);
BillingServicePort port = service.getPort(BillingServicePort.class);
Beide Wege fuehren zum selben Ergebnis - ein Objekt, das BillingServicePort implementiert
und Aufrufe transparent in SOAP-Requests uebersetzt. @WebServiceRef ist nur die
deklarative, containergesteuerte Abkuerzung dafuer.
BindingProviderMap<String, Object> requestContext = ((BindingProvider) billingPort).getRequestContext();
requestContext.put("javax.xml.ws.client.connectTimeout", 3000);
requestContext.put("javax.xml.ws.client.receiveTimeout", 5000);
Jeder JAX-WS-Client-Proxy implementiert zusaetzlich javax.xml.ws.BindingProvider - darueber
lassen sich Laufzeiteinstellungen wie Verbindungs-/Antwort-Timeouts, HTTP-Header oder eine
abweichende Endpunkt-Adresse setzen, ohne den generierten/injizierten Proxy selbst zu
veraendern. Ohne explizite Timeouts wartet ein SOAP-Aufruf im schlimmsten Fall
unbegrenzt auf ein nicht antwortendes Partnersystem - ein haeufig uebersehener Grund fuer
haengende Threads in Produktionsproblemen.
BillingIntegrationBean.registerPolicyForBilling(...) zeigt ein einfaches, aber
vollstaendiges Resilienzmuster: ein technischer Fehlschlag
(javax.xml.ws.WebServiceException - Netzwerkproblem, Timeout, ungueltige SOAP-Antwort)
wird einmal automatisch wiederholt, bevor endgueltig aufgegeben und in die projekt-
einheitliche LegacySystemUnavailableException (System Exception, siehe
docs/10-ejb-konzepte/06-exceptions.md) uebersetzt wird. Ein fachlicher Fehler
(BillingRegistrationFault) wird dagegen NICHT wiederholt - ein erneuter Versuch mit
denselben Daten wuerde exakt denselben fachlichen Fehler erneut ausloesen, siehe
docs/20-soap/03-soap-faults.md.