Pool de conexões com httpClient

Bom dia!

Sou iniciante no Java e estou com um probleminha… Criei uma classe java para capturar, via http, o HTML de um outro site.
Utilizei a API do httpClient. Essa parte funcionou sem problemas, a questão é que a performance do servidor caiu muitoooooooo…

Para corrigir este problema, estou tentando utilizar um pool de conexões! Só que não está funcionando…

Alguém pode dar um dica do que posso fazer!?

O código da classe é o seguinte:

[code]
import java.io.IOException;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;

import java.sql.;
import javax.servlet.
;
import javax.servlet.http.;
import javax.sql.
;
import javax.naming.*;

public class Delorme extends HttpServlet{

private DataSource pool = null;

public void init(ServletConfig config) throws ServletException		
{	try 
{   
                   Context ambiente = (Context) new InitialContext().lookup("java:comp/env");
                  pool = (DataSource) ambiente.lookup("jdbc/contas");
      		  		
        if (pool == null)
        {	throw new ServletException ("jdbc/contas é um DataSource desconhecido");
        }
    }
catch(NamingException e) 
{	throw new ServletException(e);
    }
}

private static Object gerenciadorTentativas;

public static void main(String[] args) {
    
    // Obtém uma conexão do pool.
    Connection conn = pool.getConnection();
    
    String url = "http://www.vesper.com.br/www/libs/cobertura/verifica_cobertura.asp?CEP1=20511&CEP2=320&num=147";
   
    HttpClient client = new HttpClient();

    HttpMethodBase getMethod = new GetMethod(url);
    
    client.getParams().setParameter("http.connection.timeout", new Integer(5000));
    DefaultHttpMethodRetryHandler gerenciadorTentativas = new DefaultHttpMethodRetryHandler 

(1,true);
client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,gerenciadorTentativas);

    try{
          int status = client.executeMethod(getMethod);
          String cobertura = null;
           if (status == HttpStatus.SC_OK){
           String htmlResposta = getMethod.getResponseBodyAsString();
                          
           if (htmlResposta.indexOf("publicidade") > 0){
            cobertura = "s";
            }
           else if (htmlResposta.indexOf("Obrigado pela consulta") > 0){
            cobertura = "n";
           } 
           else{
               System.out.println("Servidor fora do ar");
           }
           
         if (cobertura.equals("s")){
            System.out.println("Teste OK");
         } else if (cobertura.equals("n")){ 

            System.out.println("Tente mais tarde");
         }
          
        }
        else {
            System.out.println("Erro: " + status + " - " + HttpStatus.getStatusText(status));
        }
        
      }catch(HttpException e){
            //do something
      }catch(IOException e){
         
            System.err.println ("Erro de I/O: " + e.getMessage());
      }finally{
                try
                {	if (conn != null)
		{	conn.close();			                }
                }
                catch(SQLException e)
                {	}
            getMethod.releaseConnection();
      }

}
}[/code]

Fiz as alterações no código dos arquivos web.xml, server.xml, context.xml

Desde já agradeço…

[color=darkred]Editado pelo moderador para incluir as tags Code pois sem elas era difícil entender o código[/color]

Pera ai. Você está usando um pool de conexões com o banco de dados para quê?
O que ele tem a ver com a performance degradada na busca via HttpClient?

É que muitas vezes o site da nextel fica fora do ar e devido a isso tive que implementar um timeOut. Porém depois que coloquei a classe no ar o portal ficava toda hora caindo… fui procurar na documentação do httpClient e estava escrito que ele dava vários problemas de performance. aí pensei em colocar um pool de conexões para tentar melhorar a situação! Você tem alguma outra idéia???

Obrigada :slight_smile:

Bem, você está confundindo as coisas. Vamos lá!

Primeiro: você criou um HttpServlet com um método main(). Como assim? Servlets não deveriam ter um método main. Sua classe executa como um Servlet ou como um programa stand-alone?

Segundo: De quanto em quanto tempo é executado o programa de buscar os dados no seu portal? Isso pode ser um ponto que esteja pegando na performance e na estabilidade do site. Muitas requisições ao mesmo tempo pode matar o server.

Terceiro: Pool de conexões de BD não tem nada a com o seu caso, ao meu ver. Você poderia sim implementar um Pool de Conexões HTTP e não de BD. Depende de como for a implementação da sua máquina de busca. Isso pra evitar ficar criando objetos do HttpClient a toda hora. É para isso que serviria um pool no seu caso (pool de objetos).

Nossa! não pensei que estivesse tão ruim! rsrs
Vamos lá:

Primeiro: Na verdade isso vai er implementado direto em uma página JSP, coloquei o método main só para criar uma classe e fazer testes.

Segundo: os usuários são quem fazem a busca pelos dados, por isso existem várias requisições ao mesmo tempo…

Terceiro: Com relação ao pool de conexões http, você tem toda razão, porém não sei como fazê-lo com o httpClient. Você sabe onde eu consigo achar algum exemplo???

Muito obrigada pela ajuda :slight_smile:

Hoje estou de bom humor!

Eu uma vez tive de implementar um pool de objetos para um serviço de consulta usando Web Services e o que você precisa é algo parecido.

É relativamente simples. Nenhum bixo de outro mundo.

Você pode criar uma classe que gerencia o pool (criação, gerenciamento e destruição dos objetos).

Segue uma idéia. O código mesmo você pode desenvolver ai, se quiser:

[code]public class HttpClientPool {
private static final List objetos = new Vector(); //sincronizado
private static final List objetosUsados = new Vector(); //sincronizado
private static final int MIN = 0;
private static final int MAX = 10;

private HttpClientPool() {}

/**

  • Pega objeto do pool.
    */
    public static HttpClient get() {
    if( objetosUsados.size() >= MAX ) { //pool no limite
    throw new RuntimeException(“Pool chegou ao limite!”);
    }
    HttpClient cli = null;
    if( objetos.size() > 0 ) { //tem objeto livre
    cli = (HttpClient) objetos.remove(0);
    } else { //precisa criar novo objeto
    cli = criarNovoObjetoHttpClient(); //voce implementa
    }
    objetosUsados.add( cli );
    return cli;
    }

public static void release( HttpClient cli ) {
boolean ok = objetosUsados.remove( cli );
if( ok ) {
objetos.add( cli );
}
}
}[/code]

E pra usar:

HttpClient c = HttpClientPool.get(); //pega //usa o HttpCliente HttpClientPool.release( c ); //libera

Pra fazer melhor, você ainda pode encapsular o HttpClient original com uma implementação sua, para gerenciar melhor o recurso, por xemplo, prevenindo acessos indevidos a métodos que não poderiam ser acessados e ter controle total dos objetos gerenciados.

É bem simples. Talvez até tenha uma solução pronta por ai. Desconheço!

Bom, com isso você economiza processamento na criação de objetos. Porém, se tiver muitas chamadas ao seu portal, isso não muda muito.

Você poderia implementar e "comunicação" interna de outra maneira também. Seja via web service ou outro mecanismo.

Vou tentar implementar as suas dicas!!!

Muitooooo obrigado pela ajuda! Valeu mesmo :slight_smile:

Valeu pela ajuda… FUNCIONOU :smiley:

O código é o seguinte:
package conexao;

import java.util.List;
import java.util.Vector;
import org.apache.commons.httpclient.HttpClient;

public class Pool {
    private static final List objetos = new Vector(); //sincronizado
    private static final List objetosUsados = new Vector(); //sincronizado
    private static final int MIN = 0;
    private static final int MAX = 10;
    
    public static HttpClient get() {
        if(objetosUsados.size() >= MAX) {  //pool no limite
            throw new RuntimeException("Pool chegou ao limite!");
        }
        HttpClient client = null;
        if(objetos.size() > 0) {  //tem objeto livre
            client = (HttpClient) objetos.remove(0);
        } else { //precisa criar novo objeto
            client = criarNovoObjetoHttpClient();
        }
        objetosUsados.add(client);
        return client;
    }
    
    public static void release(HttpClient client) {
        boolean ok = objetosUsados.remove(client);
        if(ok) {
            objetos.add(client);
        }
    }

    private static HttpClient criarNovoObjetoHttpClient() {
        HttpClient client = new HttpClient();
        objetos.add(client);
        return client;
    }
}

E a classe principal ficou assim:
package conexao;

import java.io.IOException;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;

import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.sql.*;
import javax.naming.*;

public class Main extends Pool{

    private static Object gerenciadorTentativas;
    
    public static void main(String[] args){
        
        String url = "http://www.vesper.com.br/www/libs/cobertura/verifica_cobertura.asp?CEP1=20511&CEP2=320&num=147";
 
for (int i=0; i<10; i++) {
        long teste = System.currentTimeMillis();
        
        HttpClient client = Pool.get(); //pega
 
        System.out.println(System.currentTimeMillis() - teste + " ms");

        //create a method instance
        HttpMethodBase getMethod = new GetMethod(url);
        
        client.getParams().setParameter("http.connection.timeout", new Integer(5000));
        DefaultHttpMethodRetryHandler gerenciadorTentativas = new DefaultHttpMethodRetryHandler(1,true);
        client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,gerenciadorTentativas);

        try{
              //execute the method
              int status = client.executeMethod(getMethod);
              String cobertura = null;
              if (status == HttpStatus.SC_OK){
              String htmlResposta = getMethod.getResponseBodyAsString();
                              
              if (htmlResposta.indexOf("publicidade") > 0){
                cobertura = "s";
              }
              else if (htmlResposta.indexOf("Obrigado pela consulta") > 0){
                cobertura = "n";
              } 
              else{
                System.out.println("Servidor fora do ar");
              }
               
             if (cobertura.equals("s")){
                System.out.println("Teste OK");
             } else if (cobertura.equals("n")){ 
                System.out.println("Tente mais tarde");
             }
              
            }
            else {
                System.out.println("Erro: " + status + " - " + HttpStatus.getStatusText(status));
            }
          }catch(HttpException e){
                //do something
          }catch(IOException e){
                System.err.println ("Erro de I/O: " + e.getMessage());
          }finally{
              Pool.release(client); //libera
              getMethod.releaseConnection();
          }}
   }
}

[EDITADO: colocação das bbtags CODE].

Este método:

private static HttpClient criarNovoObjetoHttpClient() { HttpClient client = new HttpClient(); objetos.add(client); return client; }

Deveria ser assim:

private static HttpClient criarNovoObjetoHttpClient() { HttpClient client = new HttpClient(); return client; }

Alias… do jeito que você implementou, não há muito ganho, sinceramente.

Perebi que o ganho não é muito grande! Na verdade estou iniciando no Java e ainda não tenho os conceitos muito fortes… :cry:

De qualquer maneira, as bibliotecas do httpClient, não sei porque, deram conflito com a classe FormMail do portal…

Vou tentar inserir um TimeOut no código anterior que não utilizava o httpClient! Tem uma maneira melhor??? (o portal foi desenvolvido em vignette)

Brigadão pela ajuda…

Bom, vamos mudar o foco então.

Me diz qual o seu problema (o que tem de ser feito) e vamos ver se existe uma solução mais adequada.

Bom dia!

O que acontece é o seguinte…

Foi criado em um portal, uma “loja virtual”, onde os clientes fazem solicitações de aparelhos telefônicos (do tipo Vesper). Porém para que eles possam adquirir esses aparelhos eles fazem um teste de CEP, ou seja, é feita uma consulta ao site que retorna se o CEP digitado pelo cliente está dentro da área de cobertura.
Daí, pegamos via HTTP, o resultado gerado pelo site da Vesper e retornamos a resposta ao cliente.

O problema é que o site da Vesper está ficando fora do ar direto, e as conexões estavam ficando abertas sobrecarregando o servidor (que já não é muito bom)!

Para tentar minimizar este problema, tentamos utilizar a classe httpClient para inserir um timeOut…

Foi aí, que descobri que esta classe gera vários problemas de perfomance!

Tem alguma maneira de inserir um TimeOut em uma requisição http feita em uma página JSP (no vignette)? Existe algum método ou classe que eu possa implementar???

Brigadãoooooo

Bom, pelo que entendi você fazia uma chamada HTTP normal direta (via link), né?

Que problemas de performance o HttpClient está causando?

Existem muitas requisições?

E se o site da Vesper não aguenta, melhor tentar outra abordagem, seja através de WebServices ou outra forma de disponibilizar o serviço que você precisa.