Archive for the ‘Banco de Dados’ Category.

Criando, Populando e Consumindo Advanced Queue com BPEL – Parte 3/3

E por fim, vamos fazer uso da AQ que foi criada e populada com dados fixos, veja Parte 1 e Parte 2.
O processo de consumo de uma fila chamado de Dequeue, quando executado remove o registro da tabela controladora (Queue Table).

Na camada Oracle Middleware o consumo desta AQ pode ser feito utilizando o Oracle JCA Adapter for Advanced Queue (AQ Adapter) do BPEL.

Nota: Não serão detalhados os procedimentos para a configuração do AQ Adapter no Weblogic, e também a construção básica de um Composite e BPEL, veja as referências deste post.

Consumindo Advanced Queue com BPEL

Crie um novo projeto SOA, e adicione um processo BPEL assíncrono, dê o nome de BPELProcessQueue.

Criando o BPEL Assincrono

Criando o BPEL Assíncrono

Configure o banco de dados em que foi criada a fila, utilizando o usuário proprietário da AQ.
Arreste o componente AQ Adapter para o processo BPEL, e faça a configuração informando o nome, nome da fila e tipo de uso (enqueue / dequeue) neste caso iremos fazer o Dequeue.

Alguns passos básicos foram ocultados, preencha apenas as configurações a seguir e utilize o next-next-finish.

AQ Adapter

Selecione a configuração Dequeue.

AQ Adapter - Dequeue

Selecione o nome da fila que estamos utilizando como exemplo – “XXAR_INVOICE_QTAB”.

AQ Adapter - Selecionando Queue

Pronto. A fila está preparada para fazer parte do fluxo BPEL, adicione um Receive e associe ao Adaptador, crie uma variável de output que irá conter o tipo de dados da fila.

Fluxo BPEL

Bem, com isso feito você já tem o controle total da fila e poderá fazer uso dos dados como quiser, veja abaixo um Assign simples, apenas demonstrando o resultado do nosso receive.

BPEL Assign

Conclusão
O uso do Oracle AQ pode ser aplicado a diversas situações, uma delas quando está trabalhando com sistemas limitados a tecnologia de Web Services, este recurso é muito útil também em casos que toda a programação está centralizada no banco de dados. Tendo em vista que a implementação e desenvolvimento são razoávelmente rápidos, utilizar a Oracle AQ fornece um ganho enorme para a plataforma de integração.

A seguir você poderá fazer download do projeto utilizado como exemplo e também os scripts para construção da fila.

Downloads

Referência

\o/

Criando, Populando e Consumindo Advanced Queue com BPEL – Parte 2/3

Com a estrutura da AQ criada, o próximo passo ainda utilizando o PLSQL é o envio das informações para a fila. O enqueue deve ser feito utilizado a API Core DBMS_AQ.

Populando (Enqueue)

O enfileiramento é um processo simples, uma vez que as variáveis foram declaradas, basta popular o type da mensagem que será enviada a fila, e fazer uso do dbms_aq.enqueue.

Este exemplo demonstra o enfileiramento de um único registro na fila, mas você pode evoluir o código fazendo o preenchimento com multiplos registros.

Veja como popular o objeto correspondente a mensagem com dados fixos.


    --
    -- Formatacao da Mensagem para o Enqueue com dados fake
    --
    MESSAGE := XXAR_KEY_INVOICE( INVOICE_NUM => 10001,
                                 SOURCE_NAME => 'core system',
                                 TOTAL_AMOUNT => 139.99,
                                 DESCRIPTION => 'White T-Short'
                               );
--

Uma vez que a mensagem foi preenchida, a próximo ação é o enfileiramento da mensagem, um procedimento tão simples quanto o anterior. O commit da transação é obrigatório.

    --
    -- Enqueue (enfileiramento)
    dbms_aq.enqueue(queue_name           => p_queue, -- nome da fila
                    payload              => MESSAGE, -- mensagem
                    enqueue_options      => enqueue_options,
                    message_properties   => message_properties,
                    msgid                => message_handle);

    commit; --
--

Pronto, feito isto já é possível consultar a Queue Table e verificar o novo registro que acabou de ser inserido.

SELECT * FROM XXAR_INVOICE WHERE 1 = 1 ORDER BY enq_time DESC;

A coluna State da Queue Table corresponde ao status do registro.

dbmsaq.READY     = 0
dbmsaq.WAITING   = 1
dbmsaq.PROCESSED = 2
dbmsaq.EXPIRED   = 3

O registro na fila está pronto para ser consumido, e vou demonstrar isto na próxima parte utilizando o BPEL.

Download

Criando, Populando e Consumindo Advanced Queue com BPEL – Parte 1/3

Este post irá mostrar como você pode fazer uso das filas do banco de dados Oracle – Oracle Advanced Queue.
No cenário apresentado, é sugerida a integração entre dois sistemas, sendo que o Sistema A irá enfileirar as informações para que o serviço da camada Middleware faça o consumo e dispare os dados para o Sistema B.

A seguir você poderá criar uma nova fila com um tipo de dado definido, em seguida ela será populada com dados fixos utilizando PLSQL e por fim, em um processo BPEL assíncrono fazer o dequeue (consumo).

Construindo

Os passos a seguir são para construção da fila e definição da mensagem que será entregue ao consumidor.
Conecte no banco de dados Oracle e execute os scripts na sequência, no final deste artigo você poderá fazer download dos scripts.

Tipo que define a estrutura da mensagem que será adicionada a fila.

--
CREATE TYPE XXAR_KEY_INVOICE AS OBJECT (
    INVOICE_NUM         NUMBER(10),
    SOURCE_NAME         VARCHAR2(200),
    TOTAL_AMOUNT        NUMBER(15,2),
    DESCRIPTION         VARCHAR2(500))
/

Criação da Queue Table, associada ao tipo (estrutura da mensagem).

--
Begin
 DBMS_AQADM.create_queue_table( queue_table => 'XXAR_INVOICE', -- nome da QTable
                                queue_payload_type => 'XXAR_KEY_INVOICE' -- tipo mensagem da QTable
                              );
End;
/

Criação da fila vinculada com a tabela controladora dos registros que serão adicionados a fila.

--
Begin
 DBMS_AQADM.create_queue(queue_name => 'XXAR_INVOICE_QTAB', -- nome da Queue
                         queue_table => 'XXAR_INVOICE' -- Tabela controladora da Queue
                         );
End;
/

Iniciando a fila.

--
Begin
  DBMS_AQADM.start_queue( queue_name => 'XXAR_INVOICE_QTAB' );
End;
/
CREATE OR REPLACE TYPE XXAR_KEY_INVOICE_T AS TABLE OF XXAR_KEY_INVOICE;
/

Pronto, agora conseguimos criar a AQ com um tipo de dado complexo definido.
Como você deve ter percebido toda a criação da fila faz uso da API core DBMS_AQADM. Para o nosso próximo passo que é o envio de mensagens para a fila (enqueue), será necessário a DBMS_AQ.

Downloads

[]‘s

PLSQL consuming Web Services

This is a simple sample, how to do to consuming Web Services from Oracle database using PL/SQL. This tutorial was tested in Oracle database versions 9i, 10g and 11g.

The Web Services used is avaliable in webservicex.net, see this link, there are more details.

declare
 soap_request  varchar2(30000);
 soap_respond  varchar2(30000);
 http_req      utl_http.req;
 http_resp     utl_http.resp;

 l_launch_url varchar2(240) := 'http://www.webservicex.net/geoipservice.asmx?WSDL';
 l_soap_action varchar2(240) := 'http://www.webservicex.net/GetGeoIP';
 l_ip varchar2(100) := '189.100.4.198'; // IP just for test

Now, second step you have to build the SOAP request it’s may be boring if you parameter list too long, so you can use the soapUI to test and prepared the string of requisition.

begin

soap_request :=
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webservicex.net/">
 <soapenv:Header/>
 <soapenv:Body>
 <web:GetGeoIP>
 <web:IPAddress>'|| l_ip || '</web:IPAddress>
 </web:GetGeoIP>
 </soapenv:Body>
</soapenv:Envelope>
';
 dbms_output.put_line(soap_request);
 HTTP_REQ:= UTL_HTTP.BEGIN_REQUEST(l_launch_url, -- web services url
 'POST',
 'HTTP/1.1');
 UTL_HTTP.SET_HEADER(HTTP_REQ,'Content-Type', 'text/xml'); -- since we are dealing with plain text in XML documents
 UTL_HTTP.SET_HEADER(HTTP_REQ,'Content-Length', length(soap_request));
 UTL_HTTP.SET_HEADER(HTTP_REQ,'SOAPAction' , l_soap_action); -- required to specify this is a SOAP communication
 UTL_HTTP.WRITE_TEXT(HTTP_REQ, SOAP_REQUEST);
 HTTP_RESP := UTL_HTTP.GET_RESPONSE(HTTP_REQ);
 UTL_HTTP.READ_TEXT(HTTP_RESP, SOAP_RESPOND);
 UTL_HTTP.END_RESPONSE(HTTP_RESP);

 dbms_output.put_line('-------------------------');
 dbms_output.put_line(soap_respond); -- here is the response
end;

Okay, that’s the cake recipe…

Enjoy it.

Enviando e-mail com PL/SQL para múltiplos endereços

A situação mais comum é o envio de e-mail para diversos destinatários, portanto, complementando o código já postado aqui sobre o envio de e-mails utilizando PLSQL.

Uma lista de destinatários formatada normalmente assim:

 Luciano <luciano@lucianosilva.com>, Grupos <grupos@lucianosilva.com>, Futebol <futebol@cfb.com.br

Este é o nosso problema, o Oracle não irá conseguir trabalhar com a String formatada dessa maneira, e irá lançar o erro:

ORA-29279: SMTP permanent error: 501 Bad address syntax

Enfim, para conseguir solucionar o problema do envio de e-mail para multiplos destinatários, utilize a função abaixo, ela irá devolver apenas o endereço de e-mail.


FUNCTION FORMAT_ADDRESS(ADDR_LIST IN OUT VARCHAR2) RETURN VARCHAR2 IS
    ---
    ADDR VARCHAR2(256);
    I    PLS_INTEGER;
    ---
    FUNCTION LOOKUP_UNQUOTED_CHAR(STR IN VARCHAR2, CHRS IN VARCHAR2)
      RETURN PLS_INTEGER AS
      C            VARCHAR2(5);
      I            PLS_INTEGER;
      LEN          PLS_INTEGER;
      INSIDE_QUOTE BOOLEAN;
      ---
    BEGIN
      INSIDE_QUOTE := FALSE;
      I            := 1;
      LEN          := LENGTH(STR);
      WHILE (I <= LEN) LOOP
        C := SUBSTR(STR, I, 1);
        IF (INSIDE_QUOTE) THEN
          IF (C = '"') THEN
            INSIDE_QUOTE := FALSE;
          ELSIF (C = '\') THEN
            I := I + 1; -- Skip the quote character
          END IF;
          GOTO NEXT_CHAR;
        END IF;
        IF (C = '"') THEN
          INSIDE_QUOTE := TRUE;
          GOTO NEXT_CHAR;
        END IF;
        IF (INSTR(CHRS, C) >= 1) THEN
          RETURN I;
        END IF;
        <<NEXT_CHAR>>
        I := I + 1;
      END LOOP;
      RETURN 0;
    END;
  BEGIN
    ADDR_LIST := LTRIM(ADDR_LIST);
    I         := LOOKUP_UNQUOTED_CHAR(ADDR_LIST, ',;');
    IF (I >= 1) THEN
      ADDR      := SUBSTR(ADDR_LIST, 1, I - 1);
      ADDR_LIST := SUBSTR(ADDR_LIST, I + 1);
    ELSE
      ADDR      := ADDR_LIST;
      ADDR_LIST := '';
    END IF;
    I := LOOKUP_UNQUOTED_CHAR(ADDR, '<');
    IF (I >= 1) THEN
      ADDR := SUBSTR(ADDR, I + 1);
      I    := INSTR(ADDR, '>');
      IF (I >= 1) THEN
        ADDR := SUBSTR(ADDR, 1, I - 1);
      END IF;
    END IF;
    RETURN ADDR;
  END FORMAT_ADDRESS;

A mudança do código anterior não é tão drástica, já que o parâmetro é entrada/saída, você pode fazer um looping na lista de endereços para adicionar um-a-um.

UTL_SMTP.MAIL(MAIL_CONN, V_FROM );
    WHILE( V_LIST_ADDRESS IS NOT NULL )LOOP
           UTL_SMTP.RCPT(MAIL_CONN, FORMAT_ADDRESS(V_LIST_ADDRESS) );   
    END LOOP;

Veja que é uma modificação simples, porém, ganha-se muito quando é necessário deixar o programa o mais abrangente possível
Enjoy!