2008-11-18 48 views
10

¿Alguien ha accedido con éxito a un servicio web desde un procedimiento almacenado de Oracle? Si es así, ¿era un procedimiento almacenado de Java? ¿Un procedimiento almacenado PL/SQL?Acceder al servicio web desde el procedimiento almacenado de Oracle

¿Hay alguna razón por la que no deba intentar acceder a un WS desde un proceso almacenado?

Aquí hay un par de referencias que he encontrado hasta ahora

.just para aclarar, esto es para llamadas SOAP

Respuesta

13

primer lugar ¿A qué tipo de servicio web llamas? Estoy asumiendo SOAP o REST.

Para los servicios web REST, UTL_HTTP a menudo es más que suficiente, combinado con un poco de XPath en un procedimiento simple almacenado PL/SQL.

Para los servicios web SOAP, depende de lo sofisticado que necesite (o desee). Sin duda, puede usar XQuery para crear un documento XML que cumpla con las especificaciones para el servicio web, use UTL_HTTP para publicar el documento y obtener la respuesta, y luego use algo de XPath para analizar la respuesta en PL/SQL. Se trata de una solución relativamente manual y relativamente de fuerza bruta, pero si se trata de un puñado de servicios web, implica un mínimo de infraestructura y las llamadas se pueden recuperar rápidamente.

Si espera que las llamadas evolucionen con el tiempo o si espera que haya una serie de procedimientos llamando a una serie de servicios web, probablemente tenga sentido invertir tiempo en algo como UTL_DBWS (esto no es algo, sin embargo, que generalmente trabajas en un par de horas).

+3

Voy a votar esto aunque no entiendo nada de eso. –

+1

Una razón ENORME de no llamar a los servicios de los procedimientos almacenados es la probabilidad de que una transacción corta se ejecute por mucho tiempo. ¡Usar con precaución! –

10

Es bastante sencillo para envolver UTL_HTTP en una función de confort:

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; 

continuación, sólo tiene algo para poner un sobre SOAP:

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; 

Tenga en cuenta que me quita nuestro bloque de control de excepciones, ya que es no particularmente relevante para el ejemplo.

Con eso, puede tener cualquier otro procedimiento que genere el XML necesario para llamar a un servicio, pasarlo a través de invocación y analizar el valor devuelto.

Desarrollamos esta solución en una base de datos 9i, por lo que aún no hemos examinado UTL_DBWS. Sin embargo, funciona muy bien.

Cuestiones relacionadas