Es ist recht einfach, UTL_HTTP in eine Komfortfunktion zu verpacken:
FUNCTION post
(
p_url IN VARCHAR2,
p_data IN CLOB,
p_timeout IN BINARY_INTEGER DEFAULT 60
)
RETURN CLOB
IS
--
v_request utl_http.req;
v_response utl_http.resp;
v_buffer CLOB;
v_chunk VARCHAR2(4000);
v_length NUMBER;
v_index NUMBER;
BEGIN
v_index := 1;
v_length := nvl(length(p_data), 0);
-- configure HTTP
utl_http.set_response_error_check(enable => FALSE);
utl_http.set_detailed_excp_support(enable => FALSE);
utl_http.set_transfer_timeout(p_timeout);
-- send request
v_request := utl_http.begin_request(p_url, 'POST','HTTP/1.0');
utl_http.set_header(v_request, 'Content-Type', 'text/xml');
utl_http.set_header(v_request, 'Content-Length', v_length);
WHILE v_index <= v_length LOOP
utl_http.write_text(v_request, substr(p_data, v_index, 4000));
v_index := v_index + 4000;
END LOOP;
-- check HTTP status code for error
IF v_response.status_code <> utl_http.http_ok THEN
raise_application_error(
cn_http_error,
v_response.status_code || ' - ' || v_response.reason_phrase
);
END IF;
-- get response
dbms_lob.createtemporary(v_buffer, FALSE);
v_response := utl_http.get_response(v_request);
BEGIN
LOOP
utl_http.read_text(v_response, v_chunk, 4000);
dbms_lob.writeappend(v_buffer, length(v_chunk), v_chunk);
END LOOP;
EXCEPTION
WHEN utl_http.end_of_body THEN NULL;
END;
utl_http.end_response(v_response);
RETURN v_buffer;
END;
Dann brauchen Sie nur etwas, um einen SOAP-Umschlag zu POSTEN:
FUNCTION invoke
(
p_url IN VARCHAR2,
p_method IN XMLTYPE,
p_timeout IN NUMBER := 60
)
RETURN XMLTYPE
IS
-- calls the given SOAP service
cn_procedure_name CONSTANT VARCHAR2(30) := 'invoke';
--
v_envelope XMLTYPE;
v_response CLOB;
v_fault XMLTYPE;
v_sqlerrm VARCHAR2(2000);
BEGIN
-- wrap method in SOAP envelope
SELECT
XMLElement(
"soap:Envelope",
XMLAttributes(
'http://schemas.xmlsoap.org/soap/envelope/' AS "xmlns:soap"
),
XMLElement(
"soap:Body",
p_method
)
)
INTO
v_envelope
FROM
dual;
-- POST request
v_response := post(
p_url,
'<?xml version="1.0" encoding="ISO-8859-1"?>' || chr(10) || v_envelope.getClobVal(),
p_timeout
);
IF v_response IS NULL THEN
RAISE null_response;
END IF;
-- parse response
BEGIN
v_envelope := XMLType(v_response);
EXCEPTION
WHEN OTHERS THEN
v_sqlerrm := SQLERRM;
RAISE xml_parse_error;
END;
-- check for a fault
v_fault := v_envelope.extract(
'/soap:Envelope/soap:Body/soap:Fault',
'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"'
);
IF v_fault IS NOT NULL THEN
v_sqlerrm := v_fault.extract('.//faultstring/text()').getStringVal();
RAISE soap_fault;
END IF;
-- the actual response is the child of the <soap:Body /> element
RETURN v_envelope.extract(
'/soap:Envelope/soap:Body/*[position() = 1]',
'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"'
);
END;
Beachten Sie, dass ich unseren Block für die Ausnahmebehandlung entfernt habe, da er für das Beispiel nicht besonders relevant ist.
Damit können Sie jede andere Prozedur das XML generieren lassen, das für den Aufruf eines Dienstes erforderlich ist, es über invoke übergeben und den Rückgabewert analysieren.
Wir haben diese Lösung auf einer 9i-Datenbank entwickelt, daher haben wir uns noch nicht mit UTL_DBWS befasst. Sie funktioniert jedoch hervorragend.