Bei SOAP findet die Kommunikation mit Nachrichten im XML-Format statt. Die Übertragung von Dateien, die konvertiert werden sollen oder als Ergebnis an den Client zurückgesendet werden, ist als MTOM-Attachment realisiert.
Tipp
Zur Entwicklung und zum Debugging von SOAP-Anfragen empfehlen wir soapUI.
Nachdem wie in Abschnitt „Konfiguration SOAP-Schnittstelle“ beschrieben die Webservice-Schnittelle aktiviert wurde, kann
unter http://<url>?wsdl
(z. B. bei Konfiguration wie im o. g. Kapitel:
http://localhost:9000/jadiceServer?wsdl
) die formale Beschreibung der Schnittstelle im
WSDL-Format heruntergeladen werden. Damit kann in vielen Webservice-Frameworks Code generiert
werden, um den Webservice des jadice servers anzusprechen. Bei einer SOAP-Anfrage kann jadice server
auf zwei unterschiedliche Arten angesprochen werden:
-
Der Workflow wird anhand eines Templates, das zuvor serverseitig abgelegt wurde, vorkonfiguriert
-
Der Workflow wird zur Laufzeit innerhalb der SOAP-Anfrage definiert.
Die beiden Möglichkeiten werden in den beiden folgenden Kapiteln dargestellt.
Es ist möglich, serverseitig eine in XML kodierte Jobbeschreibung abzulegen, sodass ein Client bei einer SOAP-Anfrage auf diese verweisen kann und der Job nicht zur Laufzeit konfiguriert werden muss.
Der Aufbau dieser Nachricht soll anhand des folgenden Beispiels erläutert werden:
Beispiel 7.1. Beispiel einer SOAP-Anfrage mit Job-Template
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.server.jadice.levigo.com/"> <soapenv:Header/> <soapenv:Body> <ws:run> <ws:job templateLocation="resource:/jobtemplates/x2pdf.xml"> <ws:property name="dp.rulesetName">default</ws:property> <ws:property name="dp.targetMimeType">application/pdf</ws:property> <ws:property name="dp.timeout">8000</ws:property> <ws:stream mimeType="unknown/*" uuid="123456789" nodeId="node0"> <ws:documentData>BASE64_encoded_data</ws:documentData> </ws:stream> </ws:job> </ws:run> </soapenv:Body> </soapenv:Envelope>
Neben den vom SOAP-Standard vorgegebenen Elementen für Header und Body gibt es das
spezifische Element run
, das die vom Webservice
angebotene Methode run
adressiert.
Darin wird ein Job (siehe Kapitel 4, Systemarchitektur) definiert, der über ein Template vordefiniert ist
(siehe Abschnitt „Definition von Job-Templates“).
Im Attribut templateLocation
steht dabei der Ort, an dem das jeweilige
Template serverseitig zu finden ist. Sind im Template Variablen definiert, so können diese
mittels property
-Elementen konfiguriert bzw. deren Standardwert überschrieben werden.
Optional ist das Attribut messageID
. Dies kann der Client frei vergeben und wird ggf. in
einer Antwort des Servers übernommen.
Zu verarbeitende Datenströme werden über stream
-Elemente in der SOAP-Nachricht
referenziert. Die Angabe einer eindeutigen ID (uuid
) und des MIME-Typen sind optional.
Sollte der MIME-Type nicht bekannt sein, aber dennoch angegeben werden, so ist dort
unknown/*
anzugeben.
Sind in der Templatedatei mehrere StreamInputNode
s definiert, so muss eine eindeutige
Zuordnung getroffen werden, welcher Datenstrom an welchen StreamInputNode
gesendet wird.
Dies erfolgt durch das Attribut nodeId
. Dies verweist auf die ID, die dem StreamInputNode
innerhalb des Templates (Attribut id
) gegeben wurde.
Die eigentlichen Daten können entweder direkt im Tag documentData
als Base64-codierter
Datenstrom angegeben werden oder in einem multipart/related-Container referenziert werden,
der die hier angegebene CID (contentID
) besitzt, wenn das MTOM-Feature aktiviert
ist.
Soll der Client keine serverseitig vordefinierte Jobkonfiguration verwenden, ist es
möglich, diese in der SOAP-Anfrage einzubetten. Das Format ist hierbei das selbe, wie
innerhalb eines separaten Job-Templates (vgl. Abschnitt „Definition von Job-Templates“).
Anstelle des Root-Elements job
wird hierbei die Definition als configuration
-Element in die SOAP-Anfrage
eingebettet.
Das folgende Beispiel soll dies veranschaulichen:
Beispiel 7.2. Beispiel einer SOAP-Anfrage mit eingebetteter Job-Definition
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.server.jadice.levigo.com/"> <soapenv:Header/> <soapenv:Body> <ws:run> <ws:job messageID="4711"> <ws:configuration type="demultipexer example"> <ws:nodes> <ws:node class="com.levigo.jadice.server.nodes.StreamInputNode" id="input1" /> <ws:node class="com.levigo.jadice.server.nodes.StreamInputNode" id="input2" /> <ws:node class="com.levigo.jadice.server.nodes.DemultiplexerNode" id="demux" /> <ws:node class="com.levigo.jadice.server.nodes.StreamOutputNode" id="out" /> </ws:nodes> <ws:connections> <ws:connect from="input1" to="demux" /> <ws:connect from="input2" to="demux" /> <ws:connect from="demux" to="out" /> </ws:connections> </ws:configuration> <ws:stream nodeId="input1"> <ws:documentData>BASE64_encoded_data</ws:documentData> </ws:stream> <ws:stream nodeId="input2"> <ws:documentData>BASE64_encoded_data</ws:documentData> </ws:stream> </ws:job> </ws:run> </soapenv:Body> </soapenv:Envelope>
In diesem Beispiel werden zwei StreamInputNode
s miteinander über einen
DemultiplexerNode
gekoppelt und die Eingabedaten unverändert an den Client
zurückgesendet.
Die Definition der Node
s und welchen Workflow-Graphen sie bilden, ist innerhalb des
Blocks configuration
beschrieben.
Hier ist außerdem zu sehen, wie es möglich ist, bestimmte Eingabeströme an einen
StreamInputNode
zu binden: Das erste Dokument wird an den ersten (nodeId
input1
),
das zweite Dokument an den zweiten StreamInputNode
(nodeId
input2
) gebunden.
Der Aufbau einer Antwort, die dem Client als Antwort auf eine Anfrage geschickt wird, ist auch in der oben genannten WSDL spezifiziert.
Eine mögliche Antwort könnte so aussehen:
Beispiel 7.3. Beispiel einer SOAP-Antwort
<<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <js:runResponse xmlns:js="http://ws.server.jadice.levigo.com/"> <js:return> <js:stream> <js:documentData>BASE64_encoded_data</js:documentData> </js:stream> <js:status>COMPLETED</js:status> </js:return> </js:runResponse> </soap:Body> </soap:Envelope>
Neben einer (eventuell leeren) Menge von Ergebnisströmen, die jeweils über eine eindeutige ID in einem multipart/related-Container referenziert werden, ist dort eine Status-Meldung vorhanden. Folgende Werte sind möglich:
Wert | Bedeutung |
---|---|
|
Job wurde durchgeführt. |
|
Job konnte nicht durchgeführt werden. |
In beiden Fällen kann das return
-Element eine Menge an log-entry
-Elementen enthalten, die
Hinweise über den Fehlschlag der Verarbeitung oder Meldungen, die während der Verarbeitung
aufgetreten sind, enthalten (vgl. Abschnitt „Erstellung eines JobListeners“). Die
Fehlermeldung, die gezeigt wird, wenn eine nicht vorhandene Jobtemplate-Datei referenziert
wird, zeigt das folgende Beispiel:
Beispiel 7.4. Beispiel einer SOAP-Antwort mit Fehlermeldung
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <js:runResponse xmlns:js="http://ws.server.jadice.levigo.com/"> <js:return messageID="12345"> <js:log-entry timeStamp="31.12.2009 22:33:44"> <js:level>ERROR</js:level> <js:id>JS.WEBSERVICE-EXCEPTION</js:id> <js:message>java.io.FileNotFoundException: Could not locate resource: does_not_exist.xml</js:message> </js:log-entry> <js:status>FAILED</js:status> </js:return> </js:runResponse> </soap:Body> </soap:Envelope>
Durch die Definition von Job-Templates wurde die Möglichkeit geschaffen, dass Clients nun
nicht mehr die internen Schritte des jadice server, die für eine Konvertierung notwendig
sind, kennen müssen. Diese werden für die Webservice-Schnittstelle an zentraler Stelle
vorgehalten werden. Dadurch muss der Client nunmehr nur noch die Webservice-Methode run
sowie den Ort des auszuführenden Templates kennen (diese liegen i.d.R. im Unterordner
/server-config/
).
Im Ordner /server-config/jobtemplates
liegt die XSD-Definition für diese Templates.
Ein Beispiel, wie solch ein Template aussehen kann, ist das im Lieferumfang enthaltene
Template x2pdf.xml
, das ähnlich dem Beispiel aus Abschnitt „Konvertierung unbekannter Eingabedaten in ein einheitliches Format (PDF)“
unbekannte Eingabedaten identifiziert und in das PDF-Format umwandelt:
Beispiel 7.5. Beispiel eines Job-Templates
<job xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="jobtemplate.xsd" type="x2pdf"> <ws:properties> <ws:property name="PROPERTY_KEY_COMMUNICATION_TIMEOUT">${communication_timeout:22000}</ws:property> </ws:properties> <ws:nodes> <ws:node class="com.levigo.jadice.server.nodes.StreamInputNode" id="node0"> <ws:property name="timeout">${timeout:6000}</ws:property> </ws:node> <ws:node class="com.levigo.jadice.server.nodes.DynamicPipelineNode" id="node1"> <ws:property name="ruleset">${ruleset:resource:/dynamic-pipeline-rules/default.xml}</ws:property> <ws:property name="targetMimeType">${targetMimeType:application/pdf}</ws:property> <ws:property name="timeout">${timeout:6000}</ws:property> </ws:node> <ws:node class="com.levigo.jadice.server.nodes.StreamOutputNode" id="node2"> <ws:property name="timeout">${timeout:6000}</ws:property> </ws:node> </ws:nodes> <ws:connections> <ws:connect from="node0" to="node1" /> <ws:connect from="node1" to="node2" /> </ws:connections> </ws:job>
Wie man erkennen kann, ist ein Template in drei Blöcke gegliedert:
Sofern die einzelnen Node
s und deren Eigenschaften den Konventionen für java beans entsprechen, können die
jeweiligen Eigenschaften hier einfach über deren Namen gesetzt werden. Außerdem ist es
möglich, diese variabel zu machen, wie im obigen Beispiel zu sehen ist. Dies geschieht nach
folgendem Muster: ${<Bezeichner>}
oder ${<Bezeichner>:<Standardwert>}
, wobei der
Bezeichner zwingend mit einem Buchstaben beginnen muss und als weitere Zeichen Buchstaben,
Ziffern, „_“ (Unterstrich), „-“ (Bindestrich) und „.“ (Punkt) haben darf.
Durch diesen Bezeichner können diese Werte beim SOAP-Aufruf als Eigenschaft (Element
<property name="bezeichner">wert</property>
) gesetzt bzw. überschrieben werden. Werden
Variablen, die keinen Standardwert haben, nicht gesetzt, so führt dies beim Aufruf zu
folgendem Fehler:
com.thoughtworks.xstream.converters.ConversionException: Pattern refers to undefined
variable <Bezeichner> for which there is no default
Die einzelnen Node
-Elemente müssen eine für das jeweilige Template eindeutige ID
einhalten. Durch diese werden sie im connections
-Block zu einem Workflow
verkettet.
Sollen über den SOAP-Aufruf, der zu diesem Template gehört, Daten vom Client zum Server
übertragen werden, ist es notwendig, mindestens einen StreamInputNode
zu definieren. Werden
mehrere StreamInputNode
s definiert, so müssen die einzelnen stream
-Elemente in der
SOAP-Anfrage den jeweils zutreffenden Node
über das Attribut
nodeId
referenzieren. Dies entfällt, wenn es genau einen StreamInputNode
gibt.
Die Datenströme, die aus StreamOutputNode
s resultieren, werden als MTOM-Attachments in der
SOAP-Antwort an den Client zurückgesendet. Dabei ist es auch möglich, mehrere
StreamOutputNode
s zu definieren. Dabei ist die Reihenfolge, in der die StreamOutputNode
s
abgefragt werden, um ihre Datenströme an die SOAP-Antwort anzuhängen, zufällig.
Um Job-Templates in eine SOAP-Anfrage einzubetten (siehe Abschnitt „Jobdefinition innerhalb der SOAP-Nachricht“), muss das Root-Element
job
entfernt werden; der Inhalt wird stattdessen an das Element
configuration
in der SOAP-Anfrage eingehängt. Das XML-Attribut type
wird verwendet, um den Job-Typen so im Java-Code in
Beispiel 6.2, „Job konfigurieren und ausführen“ zu deklarieren.
Da die Webservice-Schnittstelle durch die WSDL klar definiert ist, können frei verfügbare Webservice-Bibliotheken diese Definition verarbeiten und daraus Proxy-Klassen generieren, die die notwendigen SOAP-Anfragen kapseln und dadurch eine effiziente Entwicklung von Clientanwendungen ermöglichen. In diesem Kapitel wird dies anhand Suns Referenzimplemenentierung von JAX-WS, der Bibliothek Apache Axis2 und der Bibliothek Apache CXFgezeigt.
Im Lieferumfang des Java Development Kit (JDK) Version 1.7 befindet sich das Kommandozeilentool wsimport, mit dem Proxy-Klassen generiert werden können. Ist der Webservice von jadice server wie in Abschnitt „Konfiguration SOAP-Schnittstelle“ beschrieben aktiviert worden, werden mit folgendem Aufruf die notwenden Clientklassen erzeugt:
<jdk1.7>\bin\wsimporthttp://localhost:9000/jadiceServer?wsdl
-keep
-extension
Der Parameter -keep
bewirkt, dass nicht nur die Klassen, sondern auch deren Quelltexte
gespeichert werden. Zur weiteren Entwicklung empfehlt es sich, mit diesen weiter zu
arbeiten. Abbildung 7.2, „Von JAX-WS generierte Klassen“ zeigt die generierten Klassen, die in die Entwicklungsumgebung
eingebunden werden können.
Einstiegspunkte für eine Clientanwendung sind die Klassen JadiceServerJobInvoker
und
JobInvocationService
, über die ein Zugriff auf die SOAP-Schnittstelle erfolgt, und die
Klasse JobConfiguration
über die der Aufruf konfiguriert wird. Eine minimale
Implementierung kann so aussehen:
Beispiel 7.6. Implementierung eines SOAP-Clients mit der JAX-WS Referenzimplemenentierung
// Abstraction of the SOAP interface: JadiceServerJobInvoker invoker = new JadiceServerJobInvoker(); JobInvocationService service = invoker.getJobInvocationServiceImplPort(); // Configuration of the job JobConfiguration job = new JobConfiguration(); job.setTemplateLocation("resource:/jobtemplates/x2pdf.xml"); // Optional: Apply a property (e.g. a timeout) Property timeout = new Property(); timeout.setName("timeout"); timeout.setValue("20000"); job.getProperty().add(timeout); // Attach input data (if the template defines a StreamInputNode) Stream inputStream = new Stream(); inputStream.setDocumentData(…); job.getStream().add(inputStream); // Submit the SOAP request (method is blocking!) JobResult result = service.run(job); // Retrieve result status ResultStatus status = result.getStatus(); for (Log log : result.getLogEntry()) { // Evaluate log entries... } // Retrieve and handle result data for (Stream stream : result.getStream()) { InputStream is = stream.getDocumentData().getInputStream(); … }
Wenn die Security-Schnittstelle von jadice server wie in Abschnitt „Konfiguration Security-Schnittstelle“ beschrieben aktiviert ist,
muss der clientseitige SOAP-Request um einen Security-Header erweitert werden.
Folgendes Beispiel zeigt dies anhand der Java-WS Referenzimplementierung.
Ein SOAPHandler
erzeugt den benötigeten Security-Header:
Beispiel 7.7. Implementierung eines SecuritySoapHeaderHandler
public class SecurityHeaderSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final String SOAP_HEADER_SECURITY_NAMESPACE // = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; private static final String SOAP_HEADER_USER_TOKEN_NAMESPACE // = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"; private static final String SOAP_HEADER_PASSWORD_TYPE_NAMESPACE // = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"; @Override public boolean handleMessage(SOAPMessageContext context) { final Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (outboundProperty.booleanValue()) { final SOAPMessage message = context.getMessage(); try { SOAPEnvelope envelope = message.getSOAPPart().getEnvelope(); SOAPHeader header = envelope.getHeader(); SOAPElement security = header.addChildElement("Security", "wsse", SOAP_HEADER_SECURITY_NAMESPACE); SOAPElement usernameToken = security.addChildElement("UsernameToken", "wsse"); usernameToken.addAttribute(new QName("xmlns:wsu"), SOAP_HEADER_USER_TOKEN_NAMESPACE); SOAPElement username = usernameToken.addChildElement("Username", "wsse"); username.addTextNode("myUsername"); SOAPElement password = usernameToken.addChildElement("Password", "wsse"); password.setAttribute("Type", SOAP_HEADER_PASSWORD_TYPE_NAMESPACE); password.addTextNode("myPassword"); } catch (Exception e) { // Causes the JAX-WS runtime to cease handler processing and generate a fault throw new RuntimeException("Cannot apply username token", e); } } return outboundProperty; }
Dieser Handler wird mittels eines HandlerResolver
s dem Invoker
gesetzt.
Folgender Abschnitt des Client-Codes muss hierzu angepasst werden:
Beispiel 7.8. Implementierung eines Security Headers mit JAX-WS Referenzimplementierung
// Abstraction of the SOAP interface: JadiceServerJobInvoker invoker = new JadiceServerJobInvoker(); invoker.setHandlerResolver(new HandlerResolver() { @Override public List<Handler> getHandlerChain(PortInfo portInfo) { List<Handler> handlerChain = new ArrayList<Handler>(); SecurityHeaderSoapHandler securtiyHandler = new SecurityHeaderSoapHandler(); handlerChain.add(securtiyHandler); return handlerChain; } }); JobInvocationService service = invoker.getJobInvocationServiceImplPort();
Apache Axis2 ist unter http://axis.apache.org/axis2/java/core/ verfügbar und steht unter der Apache License. Ist der Webservice von jadice server wie in Abschnitt „Konfiguration SOAP-Schnittstelle“ beschrieben aktiviert worden, werden mit folgendem Aufruf die notwendigen Clientklassen erzeugt:
<AXIS2_HOME>\bin\wsdl2java-o generatedCode
-p com.levigo.jadice.server.ws.client.axis2.stub
-d jaxbri
-uri http://localhost:9000/jadiceServer?wsdl
Die Verwendung der Parameter -o
für das Ausgabeverzeichnis und -p
für den zu
verwendenden Paketnamen sind optional. Der Parameter -d
bestimmt, welches Databinding für
die Wandlung nach / von XML verwendet werden soll. Standard ist das Apache Axis Data Binding
(ADB). Dieses hat in der aktuellen Fassung jedoch Probleme mit der Deserialisierung von
SOAP/MTOM-Attachments, sodass stattdessen auf die JAX-B Referenzimplemenentierung (jaxbri
)
zurückgegriffen werden sollte.
Einstiegspunkte für eine Clientanwendung sind die Klassen JadiceServerJobInvokerStub
und
Run
, über die ein Zugriff auf die SOAP-Schnittstelle erfolgt, und die Klasse
JobConfiguration
, über die der Aufruf konfiguriert wird. Eine minimale Implementierung kann
so aussehen:
Beispiel 7.9. Implementierung eines SOAP-Clients mit Apache Axis2
// Abstraction of the SOAP interface: JadiceServerJobInvokerStub invoker = new JadiceServerJobInvokerStub(); // Configuration of the job JobConfiguration job = new JobConfiguration(); job.setTemplateLocation("resource:/jobtemplates/x2pdf.xml"); // Optional: Apply a property (e.g. a timeout) Property timeout = new Property(); timeout.setName("timeout"); timeout.setValue("20000"); job.getProperty().add(timeout); // Attach input data (if the template defines a StreamInputNode) Stream inputStream = new Stream(); inputStream.setDocumentData(…); job.getStream().add(inputStream); // Configure the SOAP request Run run = new Run(); run.setJob(job); // Submit the SOAP request (method is blocking!) RunResponse response = invoker.run(run); // Retrieve the result object JobResult result = response.getReturn(); // Retrieve result status ResultStatus status = result.getStatus(); for (Log log : result.getLogEntry()) { // Evaluate log entries... } // Retrieve and handle result data for (Stream stream : result.getStream()) { InputStream is = stream.getDocumentData().getInputStream(); … }
Wenn die Security-Schnittstelle von jadice server wie in Abschnitt „Konfiguration Security-Schnittstelle“ beschrieben aktiviert ist, muss der clientseitige SOAP-Request um einen Security-Header erweitert werden. Folgendes Beispiel zeigt dies für Apache Axis2.
Beispiel 7.10. Erzeugung eines Security Headers
private static final String SOAP_HEADER_SECURITY_NAMESPACE = // "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; private static final String SOAP_HEADER_USER_TOKEN_NAMESPACE = // "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"; private static final String SOAP_HEADER_PASSWORD_TYPE_NAMESPACE = // "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"; private static OMElement createSecurityHeader() { OMFactory omFactory = OMAbstractFactory.getOMFactory(); OMElement omSecurityElement = omFactory.createOMElement(new QName(SOAP_HEADER_SECURITY_NAMESPACE, "Security", "wsse")); omSecurityElement.addAttribute("mustUnderstand", "1", null); OMElement omUsertoken = omFactory.createOMElement(new QName(SOAP_HEADER_SECURITY_NAMESPACE, "UsernameToken", "wsse")); omUsertoken.declareNamespace(SOAP_HEADER_USER_TOKEN_NAMESPACE, "wsu"); OMElement omUserName = omFactory.createOMElement(new QName(SOAP_HEADER_SECURITY_NAMESPACE, "Username", "wsse")); omUserName.setText("myUsername"); OMElement omPassword = omFactory.createOMElement(new QName(SOAP_HEADER_SECURITY_NAMESPACE, "Password", "wsse")); omPassword.addAttribute("Type", SOAP_HEADER_PASSWORD_TYPE_NAMESPACE, null); omPassword.setText("myPassword"); omUsertoken.addChild(omUserName); omUsertoken.addChild(omPassword); omSecurityElement.addChild(omUsertoken); return omSecurityElement; }
Der erzeugte Header wird mit den folgenden Anpassungen des Webservice Client-Codes gesetzt und für jeden Webservice-Request
verwendet:
Beispiel 7.11. Implementierung eines Security Headers mit Apache Axis2
// Abstraction of the SOAP interface:
JadiceServerJobInvokerStub invoker = new JadiceServerJobInvokerStub();
ServiceClient _stub = invoker._getServiceClient();
_stub.addHeader(createSecurityHeader());
Apache CXF ist unter http://cxf.apache.org/ verfügbar und steht unter der Apache License. Ist der Webservice von jadice server wie in Abschnitt „Konfiguration SOAP-Schnittstelle“ beschrieben aktiviert worden, werden mit folgendem Aufruf die notwendigen Clientklassen erzeugt:
<CXF_HOME>\bin\wsdl2java-d generatedCode
-p com.levigo.jadice.server.ws.client.cxf
http://localhost:9000/jadiceServer?wsdl
Die Verwendung der Parameter -d
für das Ausgabeverzeichnis und -p
für den zu
verwendenden Paketnamen sind optional.
Einstiegspunkte für eine Clientanwendung sind die Klassen JadiceServerJobInvoker
und
Run
, über die ein Zugriff auf die SOAP-Schnittstelle erfolgt, und die Klasse
JobConfiguration
, über die der Aufruf konfiguriert wird. Eine minimale Implementierung kann
so aussehen:
Beispiel 7.12. Implementierung eines SOAP-Clients mit Apache CXF
// Abstraction of the SOAP interface: JadiceServerJobInvoker invoker = new JadiceServerJobInvoker(); JobInvocationService service = invoker.getJobInvocationServiceImplPort(); // Configuration of the job JobConfiguration job = new JobConfiguration(); job.setTemplateLocation("resource:/jobtemplates/x2pdf.xml"); // Optional: Apply a property (e.g. a timeout) Property timeout = new Property(); timeout.setName("timeout"); timeout.setValue("20000"); job.getProperty().add(timeout); // Attach input data (if the template defines a StreamInputNode) Stream inputStream = new Stream(); inputStream.setDocumentData(…); job.getStream().add(inputStream); Run run = new Run(); run.setJob(job); // Submit the SOAP request (method is blocking!) RunResponse response = service.run(run); // Retrieve the result object JobResult result = response.getReturn(); // Retrieve result status ResultStatus status = result.getStatus(); for (Log log : result.getLogEntry()) { // Evaluate log entries... } // Retrieve and handle result data for (Stream stream : result.getStream()) { InputStream is = stream.getDocumentData().getInputStream(); … }
Wenn die Security-Schnittstelle von jadice server wie in Abschnitt „Konfiguration Security-Schnittstelle“ beschrieben aktiviert ist, muss der clientseitige SOAP-Request um einen Security-Header erweitert werden. Hierbei kann die gleiche Syntax wie bei der JAX-WS Referenzimplementierung verwendet werden, siehe „JAX-WS Referenzimplemenentierung“