понедельник, 15 марта 2010 г.

Call Web Service from Oracle

There are a lot of samples how to call web service from Oracle.
but after a small research I make this choice because of speed and simplicity.

So, I create a package and here is a code example how to use it:
select ws_tools.callws(
    --endpoint url
    'http://myhost:9763/services/Dictionary.DictionaryHttpSoap11Endpoint/',
    --soap message payload
    XMLElement(
        "ns1:getEducationTypes",
        XMLAttributes('http://mynamespace/' as "xmlns:ns1"),
        XMLElement("ns1:id",null)
    )
    --optional WSSecurity UsernameToken parameters:
    'theusername',
    'thepassword'
) from dual

The package:
CREATE OR REPLACE PACKAGE WS_TOOLS
    IS
    FUNCTION callWS(p_url IN VARCHAR2,p_method IN XMLTYPE,p_user in VARCHAR2 :=null,p_pass in VARCHAR2 :=null) RETURN XMLTYPE;
END;
/
CREATE OR REPLACE PACKAGE BODY WS_TOOLS
IS


--internal function to post http(s) request
FUNCTION httpPost
(
    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(-20400,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;


FUNCTION callWS
(
    p_url IN VARCHAR2,
    p_method IN XMLTYPE,
    p_user in VARCHAR2 :=null,
    p_pass in VARCHAR2 :=null

    --p_timeout IN NUMBER := 60
)
    RETURN XMLTYPE
IS
    -- calls the given SOAP service
    --cn_procedure_name CONSTANT VARCHAR2(30) := 'invoke';
    --
    v_envelope XMLTYPE;
    v_header XMLTYPE;
    v_response CLOB;
    v_fault XMLTYPE;
    v_sqlerrm VARCHAR2(2000);
BEGIN
    if p_user is not null then
        --prepare header
        SELECT
            XMLElement(
                "soap:Header",
                XMLElement(
                    "wsse:Security",
                    XMLAttributes(
                        'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' AS "xmlns:wsse"
                    ),
                    XMLElement(
                        "wsse:UsernameToken",
                        XMLAttributes(
                            'UsernameToken-1' AS "wsu:Id",
                            'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd' AS "xmlns:wsu"
                        ),
                        XMLElement(
                            "wsse:Username",
                            'cfront'
                        ),
                        XMLElement(
                            "wsse:Password",
                            XMLAttributes(
                                'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText' AS "Type"
                            ),
                            'cfrontpass'
                        )
                    )
                )
            )
        INTO
            v_header
        FROM
            dual;
    end if;


    -- wrap method in SOAP envelope
    SELECT
        XMLElement(
            "soap:Envelope",
            XMLAttributes(
                'http://schemas.xmlsoap.org/soap/envelope/' AS "xmlns:soap"
            ),
            v_header,
            
            XMLElement(
                "soap:Body",
                p_method
            )
        )
    INTO
        v_envelope
    FROM
        dual;

    -- POST request
    v_response := httpPost(
        p_url,
        v_envelope.getClobVal(),
        60 -- 60 seconds
    );
    IF v_response IS NULL THEN
        raise_application_error(-20400,'empty response');
    END IF;

    -- parse response
    BEGIN
        v_envelope := XMLType(v_response);
    EXCEPTION
        WHEN OTHERS THEN
            raise_application_error(-20400,'can''t parse xml: '||SQLERRM);
    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_application_error(-20400,'remote error: '||v_sqlerrm);
    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;

END;

Комментариев нет:

Отправить комментарий