quarta-feira, 11 de dezembro de 2013

DBCP – Database connection pool



DBCP – Database connection pool

Imagine a seguinte a situação: em uma aplicação sem um pool, caso você abra uma conexão com um banco de dados,  será criado um objeto do tipo Connection na memória,  esse objeto se comunicará com o  seu servidor de banco de dados, e este por sua vez, alocará recursos de instância de forma dedicada para aquela conexão, repetindo-se, cada vez que sua aplicação for iniciada por qualquer usuário(ver figura 01). Esse processo apesar de ser perfeitamente funcional e simples, pode implicar em um alto custo  de performance, caso sua aplicação tenha uma alta demanda de usuários e um grande tráfego de dados.   




Figura 01 – Arquitetura de conexão sem pool

Um Pool de conexões almeja exatamente solucionar esse gargalo, pois através dessa técnica, cada sessão de nossa aplicação, consumirá  apenas uma conexão já existe com o banco de dados.
             
Na verdade, essa conexão vai ser criada somente uma vez pela primeira sessão que a consumi-la,  ou quando o servidor como o TomCat for iniciado, assumindo a responsabilidade de gerenciar o ciclo de vida da conexão em vigor e fornece-la da maneira mais dinâmica possível para as aplicações(ver figura 02).        
           

Figura 02 – Arquitetura de  conexão com pool gerenciado pelo TomCat
Pool de conexões por aplicação(Cada aplicação possui um DBCP).



DBCP   Técnica para criaçao e gerenciamento de um pool de conecções que estão prontas para  serem executadas por qualquer thread que necessite.
JNDI    O JNDI (Java Naming and Directory Interface) é a API J2EE que fornece uma interface padrão para localizar usuários, máquinas, objetos, redes e serviços. Por exemplo, você pode utilizar o JNDI para localizar um computador na rede. Pode ser usado também para buscar objetos Java.

1-    Criar arquivo context.xml na pasta META-INF da aplicação (JNDI)

<?xml version="1.0" encoding="UTF-8"?>

<Context path="/jndi">
  <Resource
      auth="Container"
      driverClassName="org.postgresql.Driver"
      maxActive="20"
      maxIdle="10"
      maxWait="-1"
      name="jdbc/db_pool"
      type="javax.sql.DataSource"
      url="jdbc:postgresql://127.0.0.1:5432/enoc?autoReconnect=true"
      autoReconnect="true"
      username="manuka"
      password="manuka"   />
</Context>

Lembrando que essa é uma das formas de configurar um pool de conexões, pois, podemos usar esse mesmo conjunto de tags XML, no arquivo server.xml, disponível na pasta “conf” do servidor TomCat.

auth
Se definido como “Container”,  será passado ao servidor TomCat, o processo de abertura e fechamento da conexão.
driverClassName
Namespace do pacote do driver JDBC específico do banco de dados.
maxActive
                                                 
Número máximo de conexões do DB no pool, onde pode ser especificado “0” para nenhum limite.
maxIdle
Número máximo das conexões inativas.
maxWait

                        
Tempo máximo (em milesegundos) de espera por uma conexão,  se este intervalo de parada for excedido, uma exceção é lançada. Podemos ajustar com   “-1”  para  esperar indefinidamente.
name
Definição do nome em formato de JNDI(Java Naming and Directory Interface), que servirá como forma de acesso ao nosso pool pela nossa aplicação.
type
Tipo da classe dataSource, que implementará um objeto com a conexão que será compartilhada por várias sessões da aplicação.
url
Caminho de acesso ao serviço do banco de dados, lembrando que  cada banco de dados, tem sua forma própria de chamada.
Username e  password
Respectivamente usuário e senha para acessar o servidor de banco de dados.


2-    Criar arquivo web-xml que vai referenciar a JNDI.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>

    <resource-ref>        
        <res-ref-name>jdbc/db_pool</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>

</web-app>

3-    Copiar drive de banco de dados para \[diretório apache]\common\lib
4-    Gerar modulo da camada MODEL de conecção com o DBCP.(JSP ou bean)

<html>
<%@ page import="java.sql.*" %> 
<%@ page import="javax.naming.Context" %> 
<%@ page import="javax.naming.InitialContext" %> 
<%@ page import="javax.naming.NamingException" %> 
<%@ page import="javax.sql.DataSource" %> 
<%@ page import="java.sql.Connection" %> 
<%@ page import="java.sql.DriverManager" %> 
<%@ page import="java.sql.ResultSet" %> 
<%@ page import="java.sql.Statement" %> 
<%@ page import="java.sql.ResultSetMetaData" %> 
<body>
<%
     try   {
            Context initContext = new InitialContext();
            Context envContext = (Context)initContext.lookup("java:/comp/env");                   
            DataSource ds   = (javax.sql.DataSource)envContext.lookup("jdbc/db_pool");
            Connection conn = ds.getConnection();              
            Statement st      = conn.createStatement();
            String    sql        = "select * from cliente";
            ResultSet rs       = st.executeQuery(sql);             
            while (rs.next())
                        out.println(rs.getString("nome")+"<br />");
            }
            catch(Exception e){
            out.println("Erro: "+e.getMessage());}    
 %> </body>
</html>

sexta-feira, 6 de setembro de 2013

Declaracoes em Java



Declarando Campos 

Um campo é uma variável declarada no corpo de uma classe e sua declaração tem a sintaxe abaixo:
 
[ ( 'public' | 'private' | 'protected' ) ] 
  [ ( 'final' | 'volatile' ) ] 
    [ 'static' ] [ 'transient' ]
      tipo_do_dado nome_do_campo [ '=' expressao ] ';'
 
A declaração de um campo especifica o nome do campo, o tipo do dado, uma expressão opcional que inicializa o campo, especificadores de acesso e modificadores:

class Pessoa
{ 
   String nome;         // Nome da pessoa
   String endereco;    // Endereço da pessoa
   int    idade;           // Idade da pessoa
}
 
Declarando
Métodos

Para declarar um método no código fonte, use a seguinte sintaxe:
 
[ ( 'public' | 'private' | 'protected' ) ] 
  ( [ 'abstract' ] | [ 'final' ] [ 'static' ] [ 'native' ] [ 'synchronized' ] )
    tido_de_retorno nome_do_metodo '(' [ lista_de_parametros ] ')'
    sequencia_de_instrucoes
 
Uma declaração de método consistem de uma assinatura de método seguida por uma sequência de instruções. A assinatura do método especifica o nome do método, o tipo de dado de retorno, a lista de parâmetros, especificadores de acesso, modificadores e os tipos de exceções que o método pode lançar. A sequência de instruções é um bloco (grupo) de instruções que executam quando o método é chamado pelo código executado em um outro método. O código que chama um método é conhecido como chamador do método.

Antecedendo cada método está um tipo de dado de retorno, que ou identifica o tipo de dado dos valores que o método retorna ou indica que o método não retorna nada. Além de void tipo_de_retorno pode ser:

- uma das palavras-chave de tipos de dados primitivos: boolean, byte, char, double, float, int, long ou short;

- o identificador de um tipo de dado referência (referência para um objeto).

Um par de parênteses segue cada método. Você pode opcionalmente declarar uma lista de variáveis separada por vírgulas entre os parênteses. Cada variável na declaração é conhecida como um parâmetro.

Modificadores de Membros

Existem palavras reservadas que servem para modificar o comportamento ou a forma de tratamento dos membros de uma classe (campos e métodos). Alguns servem para diferenciar o nível de acesso ao um membro e outros servem para adicionar características diferenciadas aos membros da classe. Vamos vê-los um a um:

 Modificadores de Acesso

 Em Java, você pode usar especificadores de acesso para proteger tanto as variáveis quanto os métodos de uma classe quando você os declara. A linguagem Java suporta quatro níveis de acesso distintos para variáveis e métodos membros: private, protected, public e, se deixar sem especificação, package-access .

A tabela abaixo mostra o nível de acesso permitido por cada especificador:
Especificador
classe
sub-classe
package
exterior
private
X



protected
X
X*
X

public
X
X
X
X
package
X

X



A primeira coluna indica se a própria classe tem acesso ao membro definido pelo especificador de acesso. Como você pode ver, uma classe sempre tem acesso aos seus próprios membros. A segunda coluna indica se subclasses da classe (independente em qual package elas estejam) têm acesso ao membro. A terceira coluna indica se classes no mesmo package que a classe (independente de seus parentescos) têm acesso ao membro. A quarta coluna indica se todas as classes têm acesso ao membro.

A interseção protected/subclasse tem um '*' (este caso em particular será discutido mais adiante).

Vejamos agora detalhadamente cada um dos níveis de acesso:

private:

O nível de acesso mais restritivo é o private. Um membro privado é acessível apenas para a classe na qual ele é definido. Use este modificador para declarar membros que devem ser usados apenas pela classe. Isto inclui variáveis que contém informações que se acessadas por algum objeto estranho poderia colocar o objeto em um estado inconsistente, ou métodos que se invocados por outros objetos poderiam colocar em risco o estado do objeto ou do programa que o está executando. Membros privados são como segredos que você nunca falaria a ninguém.

Para declarar um membro privado, use a palavra-chave private na sua declaração. A classe a seguir contém uma variável membro privada e um método privado.
class Alpha {
    private int iamprivate;
    private void privateMethod() {
        System.out.println("Método privado");
    }
}
Objetos do tipo Alpha podem examinar ou modificar a variável iamprivate e podem invocar privateMethod(), mas objetos de outros tipos não podem. Por exemplo, a classe Beta definida aqui:
class Beta {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iamprivate = 10;      // ilegal
        a.privateMethod();      // ilegal
    }
}
não pode acessar a variável iamprivate ou invocar privateMethod() sobre um objeto do tipo Alpha porque Beta não é do tipo Alpha.

Quando uma de suas classes está tentando acessar uma variável membro para a qual ela não tem acesso, o compilador imprimirá uma mensagem de erro similar à seguinte e não compilará o programa:
 
Beta.java:12: No method matching privateMethod() found in class Alpha.
        a.privateMethod();         // illegal
1 error
Novos programadores Java poderiam se perguntar se um objeto Alpha pode acessar os membros privados de um outro objeto Alpha. Isto é ilustrado no exemplo a seguir. Suponha que a classe Alpha contivesse um método de instância que comparasse o objeto Alpha atual (this) a outro objeto colocado na sua variável iamprivate:
 
class Alpha {
    private int iamprivate;
    boolean isEqualTo(Alpha anotherAlpha) {
        if (this.iamprivate == anotherAlpha.iamprivate)
            return true;
        else
            return false;
    }
}
Isto é perfeitamente legal. Objetos do mesmo tipo têm acesso aos membros privados uns dos outros. Isto porque as restrições de acesso aplicam-se no nível da classe ou do tipo (todas as instâncias de uma classe) em vez de ser aplicada apenas sobre o objeto (a instância particular de uma classe).


protected:

O próximo especificador de nível de acesso é protected que permite que a própria classe, subclasses, e todas as classes no mesmo package acessem os membros. Use o nível de acesso protected quando as subclasses de uma classe tem que acessar os seus membros, mas não classes não relacionadas. Membros protegidos são como segredos de família (você não se importa se toda a família sabe e mesmo se alguns poucos amigos sabem, mas você não gostaria que algum estranho soubesse).

Para declarar um membro protegido use a palavra-chave protected. Primeiro vamos ver como o especificador protected afeta o acesso para as classes no mesmo package.

Considere esta versão da classe Alpha que é agora declarada para estar dentro de um package chamado Greek e que tem uma variável membro e um método protegido declarados nela:
package Greek;
 
class Alpha {
    protected int iamprotected;
    protected void protectedMethod() {
        System.out.println("protectedMethod");
    }
}
Agora, suponha que a classe, Gamma, também foi declarada para ser um membro do package Greek (e ela não é uma subclasse de Alpha). A classe Gamma pode acessar legalmente a variável membro iamprotected de um objeto Alpha e pode legalmente invocar seu protectedMethod():
package Greek;
 
class Gamma {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iamprotected = 10;    // legal
        a.protectedMethod();    // legal
    }
}
É bem simples. Agora, vamos investigar como o especificador protected afeta o acesso para subclasses de Alpha.

Vamos introduzir uma nova classe, Delta, que deriva de Alpha mas que fica em um package diferente (Latin). A classe Delta pode acessar tanto iamprotected quanto protectedMethod(), mas apenas sobre objetos do tipo Delta ou suas subclasses. A classe Delta não pode acessar iamprotected ou protectedMethod() em objetos do tipo Alpha. accessMethod() no código exemplo a seguir tenta acessar a variável membro iamprotected em um objeto do tipo Alpha, o que é ilegal, e em um objeto do tipo Delta, o que é legal. Da mesma forma, accessMethod() tenta invocar um protectedMethod() de objetos Alpha o que também é ilegal:
import Greek.*;
 
package Latin;
 
class Delta extends Alpha {
    void accessMethod(Alpha a, Delta d) {
        a.iamprotected = 10;    // ilegal
        d.iamprotected = 10;    // legal
        a.protectedMethod();    // ilegal
        d.protectedMethod();    // legal
    }
}
Se uma classe é tanto uma subclasse da classe com o membro protegido e está no mesmo pacote dela, então a classe tem acesso ao membro protegido.

public:

A especificador de acesso mais fácil é o public. Qualquer classe, em qualquer package, tem acesso aos membros públicos da classe. Declare membros públicos apenas se tal acesso não puder produzir resultados indesejados se algum objeto externo os utilizar. Não existem segredos pessoais ou de família aqui; isto é para as coisas que você não se importa se outros ficarem sabendo.

Para declarer um membro público, use a palavra-chave public.
Por exemplo,
package Greek;
 
class Alpha {
    public int iampublic;
    public void publicMethod() {
        System.out.println("publicMethod");
    }
}
Vamos re-escrever nossa classe Beta uma vez mais e colocá-la em um package diferente de Alpha e garantir que ela esteja completamente desrelacionada (não é uma subclasse) à Alpha:
package Roman;
 
import Greek.*;
 
class Beta {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iampublic = 10;       // legal
        a.publicMethod();       // legal
    }
}
Como você pode ver do código acima, Beta pode inspecionar e modificar a variável iampublic na classe Alpha e pode legalmente invocar publicMethod().

package:

E finalmente, o último nível de acesso é aquele que você tem se não ajustar explicitamente o nível de acesso do membro para um dos outros níveis. Este nível de acesso permite que classes no mesmo package que a sua classe acessem os membros. Este nível de acesso assume que classes no mesmo package são amigos confiáveis. Este nível de confiança é como aquele que você extende para os seus amigos mais próximos mas que não concederia até mesmo para sua família. Por exemplo, esta versão da classe Alpha declara uma variável membro com nível de acesso de package e um método simples com nível de package.
Alpha fica no package Greek:
package Greek;
 
class Alpha {
    int iampackage;
    void packageMethod() {
        System.out.println("packageMethod");
    }
}
A classe Alpha acessa tanto iampackage quanto packageMethod(). Além disso, todas as classes declaradas dentro do mesmo package que Alpha também têm acesso à iampackage e packageMethod(). Suponha que tanto Alpha e Beta foram declaradas como parte do package Greek:
package Greek;
 
class Beta {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iampackage = 10;     // legal
        a.packageMethod();     // legal
    }
}
Assim, Beta pode acessar legalmente iampackage e packageMethod() como mostrado.

Outros Modificadores

abstract:

Classes e métodos podem ser abstratos. Métodos abstratos não possuem corpo. Dessa forma eles devem ser implementados por uma subclasse. Uma classe que contém métodos abstratos é uma classe abstrata.
abstract class Item {
               ...
abstract void print();
...
               abstract object nextElement();
               ...
               abstract boolean hasMoreElements();
               ..
}
static:

Quando usado antes da declaração de um método, a palavra-chave static indica que este método é um método de classe. Isto significa que existe apenas uma cópia do método que está associada com a classe e não com alguma instância criada da classe. Então um método de classe é invocado através da classe em vez de ser através de uma instância da classe. O mesmo vale para declaração de variáveis. De dentro de um método estático, não se pode acessar variáveis de instância ou métodos de instância. Uma variável de classe é criada quando uma classe é carregada e é destruída se e quando a sua classe é descarregada (pela JVM). Uma vez que uma classe é carregada, a JVM aloca memória para cada variável de classe e estabelece um valor default para ele.
 
class Estatico
{
   // variável estática
   public static int valor = 5;
 
   // método estático
   // só pode manipular valores estáticos da classe
   public static int getValor()
   { return valor; }
}
 
public class Teste
{
   public static void main( String[] args )
   {
      // Acessando o valor da variável estática
      // da classe Estatico
      System.out.println(Estatico.valor);
      
      // Alterando o valor da variável estática
      Estatico.valor++;
      
      // Chamando um método estático
      System.out.println(Estatico.getValor());
   }
}
Veja o código a seguir:
 
class Employee
{
   private static int numEmployees;
 
   static void setEmployeeCount (int numEmployees)
   {
      this.numEmployees = numEmployees; // erro de compilação.
   }
}
O erro ocorre porque a palavra-chave this representa à intância da classe corrente, e o método de classe setEmployeeCount não está associado com uma instância da classe.

volatile:

A palavra-chave volatile pode ser aplicada a variáveis em uma classe. Ela especifica que a variável é usada por threads sincronizadas e que o compilador não deve tentar efetuar otimizações com ela. Veja abaixo a utilização de volatile:
private volatile int doNotOptimizeAccessToMe;
final:

A palavra-chave final pode ser usada com declarações de classes, métodos ou variáveis. O significado nestes três usos é similar, mas não idêntico.
public final
class Leaf {                // esta nunca poderá ter subclasses
 
  // esta variável nunca poderá ter seu valor ajustado -> valor constante
  public final int SIZE = 15;
  // este método nunca poderá ser sobrescrito
  public final void tryToOverride() {}
 
}
synchronized:

A palavra-chave synchronized é usada se tivermos múltiplas threads e quisermos evitar que elas modifiquem objetos ou arrays simultaneamente de forma que possa haver alguma inconsistência de valores. A instrução synchronized pode ser usada de duas formas: antes de um bloco de código ou como um modificador de método.

Uso de synchronized antes de um bloco de código. Depois da palavra -chave synchronized vem uma referência par aum objeto ou array. A código crítico não é executado até que um bloqueio exclusivo para o objeto ou array possa ser obtido.
 
public static void SortIntArray(int[] a) {
  synchronized (a) {
    ..// aqui vem o código crítico
  }
}
A palavra-chave synchronized é mais usada em Java como um modificador de método ou classe. Desta forma ela indica que todo o método é uma seção crítica de código que tem que ser executado sozinha.
 
public synchronized void SortIntArray(int[] a) {  
  ..// critical code comes here  
}
native:

A palavra-chave native pode ser usada com declarações de métodos. Ela indica que o método é implementado em código nativo, dependente da plataforma (por exemplo em C). Devido a perda de uma das vantagens, a independência de plataforma, apenas utilize código nativo para aplicações críticas se nenhuma outra otimização de código for suficiente.
 
public class NativeTest {
  public native void printNative( String text );
}
transient:

Quando queremos transportar algum dado que está armazenado em um objeto Java através da rede ou mesmo torná-lo persistente em algum dispositivo de armazenagem devemos serializar o objeto, isto é, transformá-lo em uma sequência de bytes que posteriormetne poderá ser completamente restaurada para gerar novamente o objeto original (futuramente trateremos de serialização em um artigo).

Quando você está controlando serialização, pode haver algum subobjeto particular que você não queira que o mecanismo de serialização do Java salve e restaure automaticamente. Este geralmente é o caso se tal subobjeto representa alguma informação importante que você não queira serializar, tal como uma senha. Mesmo que esta informação seja privada dentro do objeto, quando ela for serializada, é possível que alguém acesse-a lendo o arquivo ou interceptando uma transmissão na rede.

Ao trabalhar com serialização geralmente implementamos nossas classes a partir da interface Serializable. Com isso a serialização de todos os dados da classe será automática. Para controlar isto, você pode desligar a serialização sobre um campo utilizando a palavra-chave transient, que diz "Não se incomode de salvar ou restaurar ele, eu cuidarei disto."

Por exemplo, considere um objeto Login que guarda informações sobre uma sessão logada. Suponha que, uma vez verificado o login, você queira armazenar os dados, mas sem o password. A forma mais fácil de se fazer isto é implementando Serializable e tornando o campo password um transient. Veja como ficaria:
import java.io.*;
import java.util.*;
 
public class Logon implements Serializable {
  private Date date = new Date();
  private String username;
  private transient String password;
 
  public Logon(String name, String pwd) {
    username = name;
    password = pwd;
  }
 
  public String toString() {
    return "Informações: \n   username: " + username +
      "\n   data: " + date + "\n   password: " + password;
  }
  public static void main(String[] args) throws Exception {
 
    Logon a = new Logon("HourGlass", "pentaBrasil");
    System.out.println( "logon a = " + a);
 
    ObjectOutputStream o = new ObjectOutputStream(
      new FileOutputStream("Logon.out"));
 
    o.writeObject(a);
    o.close();
 
    Thread.sleep(1000); // Espera por um segundo
 
    // Restaurando os dados
    ObjectInputStream in = new ObjectInputStream(
      new FileInputStream("Logon.out"));
 
    System.out.println("Recuperando objeto em "+new Date());
 
    a = (Logon)in.readObject();
    System.out.println("logon a = " + a);
  }
}
Como você pode ver, a data e o nome de usuário são normais (não transientes) e, assim, são automaticamente serializados. Já o password é transiente, e por isso não é armazenado no disco; e o mecanismo de serialização nem tenta recuperá-lo. You can see that the date and username fields are ordinary (not transient), and thus are automatically serialized. However, the password is transient, so it is not stored to disk; also, the serialization mechanism makes no attempt to recover it. A saída fica assim:
 
logon a = logon info:
   username: Hulk
   date: Mon Oct 21 12:10:13 MDT 2002
   password: myLittlePony
Recovering object at Mon Oct 21 12:10:14 MDT 2002
logon a = logon info:
   username: Hulk
   date: Mon Oct 21 12:10:13 MDT 2002
   password: null
Quando o objeto é recuperado, o campo de password é nulo.