Posts tagged ‘Java’

Fault Policy no MDS com Java Action – Parte 2

Na primeira parte, preparamos os arquivos de fault policy e a classe Java que irá receber as informações de falha para tratativa. Agora queremos adicionar os XMLs de fault ao MDS do SOA para facilitar a localização e manutenção destes arquivos, que poderão ser utilizados por todos os projetos SOA que forem tratar exceções.

Bem, uma vez que os arquivos de Fault Policy estejam concluídos (fault-policies.xml e fault-bindings.xml) você deverá empacotá-los em um arquivo Jar.

Crie um diretório qualquer chamado Fault_Policy_Arquivos, neste diretório iremos montar a estrutura que irá ser armazenada no MDS Database, então crie os sub-diretórios na estrutura abaixo:



No prompt de comando/terminal, vá até o diretório raiz e execute o comando para criação do arquivo Jar.

jar -cf blog-faultpolicy-MDS.jar ./apps/blog/fault/*.xml

Pronto, agora vamos fazer o deploy do arquivo blog-faultpolicy-MDS.jar com as estrutura do Fault Policy no MDS.
Acesse o Enterprise Manager do servidor, clique com o botão direito em soa-infra e depois vá para Administração e por fim clique em Configuração de MDS.


Na tela de Configuração de MDS, em Importar documentos de metadados de um arquivo, selecione o blog-faultpolicy-MDS.jar que acabamos de criar e clique no botão Importar. That’s all! Não é necessário reiniciar o Weblogic!

Para utilizar o fault policy no seu projeto SOA, edite o arquivo composite.xml e adicione os comandos baixo antes da tab component.

  <property name="oracle.composite.faultPolicyFile">oramds:/apps/blog/fault/fault-policies.xml</property>
  <property name="oracle.composite.faultBindingFile">oramds:/apps/blog/fault/fault-bindings.xml</property>

Isto é o suficiente para que seu projeto utilize o fault policy com Java Class Action, configurada no MDS.

Arquivos para Download:
Projeto Jdev (Exemplo de BPEL)
Estrutura de Diretórios para o MDS
Arquivo JAR para o MDS

Fault Policy no MDS com Java Action – Parte 1

Este exemplo esta dividido em duas partes, nessa primeira parte vou demonstrar como configurar os arquivos de Fault Policy chamando uma Java Class Custom como Action para o fault. Já na segunda parte vamos ver como adicionar a configuração ao MDS do SOA, facilitando o acesso e manutenção ao fault policy.

1. Definindo o Fault Policy


Vamos começar com o exemplo de configuração dos arquivos para o Fault Policy, veja a construção dos arquivos fault-policies.xml e fault-bindings.xml

Exemplo para o arquivo fault-policies.xml.

...
<Conditions>
      <faultName xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
                 name="bpelx:remoteFault">
        <condition>
          <action ref="ora-custom-retry"/>
        </condition>
      </faultName>
      <faultName xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
                 name="bpelx:bindingFault">
        <condition>
          <action ref="ora-custom-retry"/>
        </condition>
      </faultName>
    </Conditions>
    <Actions>
      <Action id="ora-custom-retry">
        <javaAction className="com.lucianosilva.lab.soa.CompositeFaultHandler"
                    defaultAction="ora-human-intervention">
            <returnValue value="ERROR" ref="ora-terminate"/>
            <returnValue value="ABORT" ref="ora-terminate"/>
            <returnValue value="RETRY" ref="ora-retry"/>
            <returnValue value="MANUAL" ref="ora-human-intervention"/>
        </javaAction>
      </Action>
            <Action id="ora-retry">
          <retry>
              <retryCount>2</retryCount>
              <retryInterval>3</retryInterval>
              <exponentialBackoff/>
          </retry>
      </Action>
      <Action id="ora-replay-scope">
          <replayScope/>
      </Action>
      <Action id="ora-rethrow-fault">
          <rethrowFault/>
      </Action>
      <Action id="ora-human-intervention">
          <humanIntervention/>
      </Action>
      <Action id="ora-terminate">
          <abort/>
      </Action>
    </Actions>
...

Definição do arquivo fault-bindings.xml.

<?xml version="1.0" encoding="UTF-8" ?>
<faultPolicyBindings version="2.0.1" xmlns="http://schemas.oracle.com/bpel/faultpolicy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <composite faultPolicy="fault-policies"/>
</faultPolicyBindings>

2. Java Action Class

Agora, com os arquivos de policy definidos, vamos construir a classe que irá receber a exception ocorrida no BPEL. No seu projeto adicione as duas classes orabpel.jar e fabric-runtime.jar, se você utiliza o JDeveloper configure-o como a imagem abaixo.

package com.lucianosilva.lab.soa;

import java.util.Collection;
import java.util.Map;

import oracle.integration.platform.faultpolicy.IFaultRecoveryContext;
import oracle.integration.platform.faultpolicy.IFaultRecoveryJavaClass;
import com.collaxa.cube.engine.fp.BPELFaultRecoveryContext;

/**
 * @author luciano silva
 *
 */
public class CompositeFaultHandler implements IFaultRecoveryJavaClass {

    private static final String RETURN_ERROR  = "ERROR";
    private static final String RETURN_MANUAL = "MANUAL";
    private static final String RETURN_RETRY  = "RETRY";

    /**
     *
     */
    public CompositeFaultHandler() {
        super();
    }

    /**
     *
     * @param iFaultRecoveryContext
     * @return
     */
    public String handleFault( IFaultRecoveryContext iFaultRecoveryContext ) {

        // print all fault details
        System.out.println("==========");
        System.out.println("Fault Policy Id : " + iFaultRecoveryContext.getPolicyId());
        System.out.println("Fault Type      : " + iFaultRecoveryContext.getType());
        System.out.println("Partnerlink     : " + iFaultRecoveryContext.getReferenceName());
        System.out.println("Port Type       : " + iFaultRecoveryContext.getPortType());

        if( iFaultRecoveryContext instanceof BPELFaultRecoveryContext ){
            //
            BPELFaultRecoveryContext bctx = (BPELFaultRecoveryContext) iFaultRecoveryContext;

            System.out.println("BPEL ActionId       : " + bctx.getActionId() );
            System.out.println("BPEL ActivityId     : " + bctx.getActivityId() );
            System.out.println("BPEL ActivityName   : " + bctx.getActivityName() );
            System.out.println("BPEL ActivityType   : " + bctx.getActivityType() );
            System.out.println("BPEL CorrelationId  : " + bctx.getCorrelationId() );
            System.out.println("BPEL PartnerLinkName: " + bctx.getPartnerLinkName() );
            System.out.println("BPEL Fault  : " + bctx.getFault().getFaultName() );
            System.out.println( bctx.getFault().getMessage() );
        }

        if( iFaultRecoveryContext.getProperties() != null ){

          System.out.println("Properties found in propertySet:");
          // print all properties defined in the fault-policy file
          Map props = iFaultRecoveryContext.getProperties();
          Collection list = props.values();
          for (String value : list) {
              System.out.println( value );
          }//

        }

        System.out.println("==========");

        return RETURN_MANUAL;
    }

    /**
     *
     * @param iFaultRecoveryContext
     */
    public void handleRetrySuccess( IFaultRecoveryContext iFaultRecoveryContext ) {
        System.out.println("SUCCESS.");
    }
}

Após compilar a classe acima, vamos empacotar em um arquivo .jar, faça isso:

 jar -cf fault-policy-javaaction.jar ./com/lucianosilva/lab/soa/*.class

Lembre-se, de usar \ se estiver no windows.

3. Adicionando Java Class (Jar) ao classpath do Weblogic

Você precisará que seu Jar seja adicionado ao classpath do Weblogic, para que em runtime a classe seja reconhecida pelo contexto e o Faut Policy funcione. O Apache Ant deve estar obrigatóriamente configurado no servidor.

O processo é muito simples, faça shutdown do servidor Weblogic, depois copie o arquivo .Jar para o diretório do servidor Weblogic $ORACLE_MIDDLEWARE_HOME/soa/modules/oracle.soa.ext_11.1.1/classes. Vá para no diretório oracle.soa.ext_11.1.1, aqui temos o build.xml, por fim, execute o Ant.

Pronto, está concluída a configuração de um exemplo para Fault Policy.
Para que as falhas do seu BPEL seja manipulada pela classe Java, as policies devem ser adicionadas ao arquivo composite.xml.

Veja na próxima parte deste post, como adicionar os XMLs de configuração do Fault Policy ao MDS e um BPEL utilizando esta configuração.

Download
Arquivos XML do Fault Policy
Projeto Java

Referências
http://docs.oracle.com/cd/E12839_01/integration.1111/e10224/bp_faults.htm
http://ant.apache.org/

Usando a API LastFm em Java

A LastFm é a queridinha das rádios online, mesmo com diversos concorrentes de alto nível como iLike, Pandora, Imeem, e outros tantos, aqui no Brasil a LastFm é um grande sucesso, seus milhões de usuários brasileiros ignoraram o bloqueio de alguns recursos e continuam fazendo scrobbling de seus áudios diáriamente.

Além de um database music, o LastFm é uma rede social e grande parte de suas informações são públicas e podem ser acessadas facilmente através de sua API.
Vamos dar inicio a um exemplo de como consumir os dados utilizando a library para Java lastfm-java. Antes de tudo, se você não tiver uma conta no LastFm, crie-a agora e depois obtenha a API Key. Neste mesmo link você encontrará a documentação da API, que detalha claramente a funcionalidade de cada método disponível e como é o seu acesso e se necessita ou não de autenticação.

Em nosso primeiro exemplo vamos fazer uma página web que irá listar as últimas faixas ouvidas e a lista de amigos de um usuário específico, com isto, você perceberá que nenhuma autenticação é necessária pois os dados são públicos.

Criei a classe LastFmClient, para facilitar os casts necessários e centralizar as chamadas da API.

public class LastFmClient {
// altere para a sua api key
 private static final String APIKEY = "XyZaBc001";
 private String uName = null;

/**
 *
 * @param uName
 */
 public LastFmClient(String uName){
 this.uName = uName;
 }

/**
 *
 * @return User/Friends List
 */
 public ArrayList<User> getFriends(){
 return (ArrayList<User>) User.getFriends(uName, APIKEY);
 }

 /**
 *
 * @return Tracks List
 */
 public ArrayList<Track> getTracks(){
 return (ArrayList<Track>) User.getRecentTracks(uName, APIKEY);
 }
}

Isto é o suficiente para você montar a lista como descrito acima, veja:

 String userName = request.getParameter("username");
 if( userName!=null && !userName.trim().equals("") ){
 // instancia a classe de backend
 LastFmClient client = new LastFmClient(userName);

 // seu código aqui
 }

Ouvidas recentemente.

<table border="0" cellpadding="2" cellspacing="1">
<% for(Track t : tracks){ %>
<tr>
 <td valign="top" align="left">
 <br/><strong><%=t.getAlbum() %></strong>
 <br/><em><%=t.getArtist() %></em>
 </td>
</tr>
<% }// for end tracks %>
</table>

Lista de amigos.

<table border="0" cellpadding="2" cellspacing="1">
<tr>
<%
 ArrayList<User> friends = client.getFriends();
 int count = 1;
 for(User f : friends){
%>
 <td valign="top" align="center">
 <% if( f.getImageURL()!=null ){ %><img src="<%= f.getImageURL() %>"><% } %>
 <br><strong><%=f.getName() %></strong>
 <br><a href="<%= f.getUrl() %>"><%= f.getUrl() %></a>
 <br/>
 </td>
<%
 if( count%5==0 ) out.print("</tr><tr>");
 count++;

 }// for end friends

}//
%>

Faça download do código completo.

Pronto, você conseguiu acessar dados do LastFm, usando o caminho correto e fácil, sem autenticação. Mas alguns dados são restritos e necessitam da autorização do usuário, informações básicas como a quantidade de músicas ouvidas, data de cadastro, nome, etc. são de acesso restrito.

Manipulando BLOB – MySQL vs. Oracle

A missão de um programador em manipular arquivos e armazená-los no banco de dados já não é uma tarefa desafiadora a tempos, visto que é extremamente fácil encontrar exemplos internet a fora, aqui vou fazer mais um, em que o foco é demonstrar a diferença de se realizar o mesmo procedimento utilizando o MySQL e Oracle.

1. Oracle

Primeiramente vamos fazer o processo para gravar um arquivo qualquer no banco de dados.
Criação da tabela que será utilizada para armazenar os arquivos.


CREATE TABLE ARQUIVOS(
ID     NUMBER(4)      NOT NULL,
TIPO   VARCHAR2(20)   NULL,
ARQ    BLOB           DEFAULT EMPTY_BLOB() NOT NULL,
CONSTRAINT PKARQ PRIMARY KEY(ID)
)

Perceba que o campo ARQ que irá guardar o binário, tem como valor default a propriedade EMPTY_BLOB() – Retorna um LOB vazio, para ser usado como um indicador para INSERT ou UPDATE.

No geral, o processo para inserir um campo LOB (BLOB ou CLOB) no Oracle é um pouco burocrático, feito em duas etapas. Primeiro deve-se inserir o registro setando o campo BLOB como EMPTY_BLOB, no em seguida finalizamos com um SELECT FOR UPDATE no campo “LOB” especifico para que o byte[] seja gravado.


// Inserindo o empty_blob
//
String sql  = "INSERT INTO arquivos(id, tipo, arq) VALUES(1, ?, EMPTY_BLOB())";
conn   = ConnOracle.getInstance().getConn();
pstmt1   = conn.prepareStatement(sql);
pstmt1.setString(1, "TEXT");
pstmt1.execute();

Este passo irá fazer com que um arquivo seja armazenado no banco.


// Faz o select como for update
// Inserir o binário
//
String ins  = "SELECT arq FROM arquivos WHERE id = 1 FOR UPDATE";
pstmt2  = conn.prepareStatement(ins);
rset  = pstmt2.executeQuery(ins);
while( rset.next() ){
Blob blob   = rset.getBlob(1);
// filePath eh a String com o caminho do arquivo a ser gravado

File file    = new File( filePath );
byte[] bbuf   = new byte[1024];
InputStream bin  = new FileInputStream( file );
// Realiza o cast especifico para o driver Oracle
OutputStream bout  = ((BLOB) blob).getBinaryOutputStream();

int bytesRead   = 0;
while( (bytesRead = bin.read(bbuf))!=-1 ){
bout.write(bbuf, 0, bytesRead);
}//

if( bout!=null ) bout.close();

}// end while
conn.commit();

2. MySQL

A estrutura da tabela muda pouco, o mais importante é que o campo para armazenar o arquivo é do tipo LONGBLOB, veja:

CREATE TABLE ARQUIVOS(
ID     INT(4)        NOT NULL,
TIPO   VARCHAR(20)   NULL,
ARQ    LONGBLOB      NOT NULL,
PRIMARY KEY(ID)
);

Gravar um campo LONGBLOB no MySQL, é tão fácil quando gravar um int ou uma String, e eu não estou falando no sentido figurado.

   File file    = new File( filePath );
byte[] bytes  = getBytesFromFile( file );</pre>
// Inserindo o longblob
//
String sql  = "INSERT INTO arquivos(id, tipo, arq) VALUES(1, ?, ?)";
conn   = ConnMysql.getInstance().getConn();
pstmt   = conn.prepareStatement(sql);
pstmt.setString(1, "TEXT");
pstmt.setBytes(2, bytes);
pstmt.execute();

O método getBytesFromFile() é uma função genérica para converter o File em byte[], e somente este último é necessário para gravar, fácil assim.

Não posso deixar de indicar este artigo completo e bem detalhado, escrito por Giovane Kuhn do JavaFree.

Espero que estes simples códigos sejam proveitosos, abaixo estão as duas classes utilizadas para este post.

Faça download das classes.

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!